@spinnaker/titus 0.0.0-main-2

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,200 @@
1
+ import type { FormikProps } from 'formik';
2
+ import React from 'react';
3
+ import type { Option } from 'react-select';
4
+ import Select from 'react-select';
5
+
6
+ import type { IWizardPageComponent } from '@spinnaker/core';
7
+ import { HelpField, SpelNumberInput } from '@spinnaker/core';
8
+
9
+ import type { ITitusServerGroupCommand } from '../../../configure/serverGroupConfiguration.service';
10
+
11
+ const mountPermOptions = [
12
+ { label: 'Read and Write', value: 'RW' },
13
+ { label: 'Read Only', value: 'RO' },
14
+ { label: 'Write Only', value: 'WO' },
15
+ ];
16
+
17
+ export interface IServerGroupResourcesProps {
18
+ formik: FormikProps<ITitusServerGroupCommand>;
19
+ }
20
+
21
+ export class ServerGroupResources
22
+ extends React.Component<IServerGroupResourcesProps>
23
+ implements IWizardPageComponent<ITitusServerGroupCommand> {
24
+ public validate(values: ITitusServerGroupCommand) {
25
+ const errors = {} as any;
26
+
27
+ if (!values.resources) {
28
+ errors.resources = 'CPU is required.';
29
+ }
30
+ if (!values.resources) {
31
+ errors.resources = 'Memory is required.';
32
+ }
33
+ if (!values.resources) {
34
+ errors.resources = 'Disk is required.';
35
+ }
36
+ if (!values.resources) {
37
+ errors.resources = 'Network is required.';
38
+ }
39
+
40
+ return errors;
41
+ }
42
+
43
+ public render() {
44
+ const { setFieldValue, values } = this.props.formik;
45
+ return (
46
+ <div className="clearfix">
47
+ <div className="form-group">
48
+ <div className="col-md-3 sm-label-right">
49
+ <b>CPU(s)</b>
50
+ </div>
51
+ <div className="col-md-8">
52
+ <SpelNumberInput
53
+ value={values.resources.cpu}
54
+ onChange={(value) =>
55
+ setFieldValue('resources', {
56
+ ...values.resources,
57
+ ...{ cpu: value },
58
+ })
59
+ }
60
+ required={true}
61
+ />
62
+ </div>
63
+ </div>
64
+ <div className="form-group">
65
+ <div className="col-md-3 sm-label-right">
66
+ <b>Memory (MB)</b>
67
+ </div>
68
+ <div className="col-md-8">
69
+ <SpelNumberInput
70
+ value={values.resources.memory}
71
+ onChange={(value) =>
72
+ setFieldValue('resources', {
73
+ ...values.resources,
74
+ ...{ memory: value },
75
+ })
76
+ }
77
+ required={true}
78
+ />
79
+ </div>
80
+ </div>
81
+ <div className="form-group">
82
+ <div className="col-md-3 sm-label-right">
83
+ <b>Disk (MB)</b>
84
+ </div>
85
+ <div className="col-md-8">
86
+ <SpelNumberInput
87
+ value={values.resources.disk}
88
+ onChange={(value) =>
89
+ setFieldValue('resources', {
90
+ ...values.resources,
91
+ ...{ disk: value },
92
+ })
93
+ }
94
+ required={true}
95
+ />
96
+ </div>
97
+ </div>
98
+ <div className="form-group">
99
+ <div className="col-md-3 sm-label-right">
100
+ <b>Network (Mbps)</b>
101
+ <HelpField id="titus.deploy.network" />
102
+ </div>
103
+ <div className="col-md-8">
104
+ <SpelNumberInput
105
+ value={values.resources.networkMbps}
106
+ onChange={(value) =>
107
+ setFieldValue('resources', {
108
+ ...values.resources,
109
+ ...{ networkMbps: value },
110
+ })
111
+ }
112
+ required={true}
113
+ />
114
+ </div>
115
+ </div>
116
+ <div className="form-group">
117
+ <div className="col-md-3 sm-label-right">
118
+ <b>Gpu</b>
119
+ <HelpField id="titus.deploy.gpu" />
120
+ </div>
121
+ <div className="col-md-8">
122
+ <SpelNumberInput
123
+ value={values.resources.gpu}
124
+ onChange={(value) =>
125
+ setFieldValue('resources', {
126
+ ...values.resources,
127
+ ...{ gpu: value },
128
+ })
129
+ }
130
+ />
131
+ </div>
132
+ </div>
133
+ <hr />
134
+
135
+ <h4>
136
+ <b>
137
+ Elastic File System Options <HelpField id="titus.deploy.efs" />
138
+ </b>
139
+ </h4>
140
+ <div className="form-group">
141
+ <div className="col-md-3 sm-label-right">
142
+ <b>Mount Permission </b>
143
+ <HelpField id="titus.deploy.mountPermissions" />
144
+ </div>
145
+ <div className="col-md-8">
146
+ <Select
147
+ value={values.efs.mountPerm}
148
+ clearable={false}
149
+ options={mountPermOptions}
150
+ onChange={(option: Option) => setFieldValue('efs', { ...values.efs, ...{ mountPerm: option.value } })}
151
+ />
152
+ </div>
153
+ </div>
154
+ <div className="form-group">
155
+ <div className="col-md-3 sm-label-right">
156
+ <b>Mount Point </b>
157
+ <HelpField id="titus.deploy.mountPoint" />
158
+ </div>
159
+ <div className="col-md-8">
160
+ <input
161
+ type="text"
162
+ className="form-control input-sm no-spel"
163
+ value={values.efs.mountPoint}
164
+ onChange={(e) => setFieldValue('efs', { ...values.efs, ...{ mountPoint: e.target.value } })}
165
+ />
166
+ </div>
167
+ </div>
168
+ <div className="form-group">
169
+ <div className="col-md-3 sm-label-right">
170
+ <b>EFS ID </b>
171
+ <HelpField id="titus.deploy.efsId" />
172
+ </div>
173
+ <div className="col-md-8">
174
+ <input
175
+ type="text"
176
+ className="form-control input-sm no-spel"
177
+ value={values.efs.efsId}
178
+ onChange={(e) => setFieldValue('efs', { ...values.efs, ...{ efsId: e.target.value } })}
179
+ />
180
+ </div>
181
+ <div className="col-md-offset-3 col-md-8" />
182
+ </div>
183
+ <div className="form-group">
184
+ <div className="col-md-3 sm-label-right">
185
+ <b>EFS Relative Mount Point </b>
186
+ <HelpField id="titus.deploy.efsRelativeMountPoint" />
187
+ </div>
188
+ <div className="col-md-8">
189
+ <input
190
+ type="text"
191
+ className="form-control input-sm no-spel"
192
+ value={values.efs.efsRelativeMountPoint}
193
+ onChange={(e) => setFieldValue('efs', { ...values.efs, ...{ efsRelativeMountPoint: e.target.value } })}
194
+ />
195
+ </div>
196
+ </div>
197
+ </div>
198
+ );
199
+ }
200
+ }
@@ -0,0 +1,3 @@
1
+ .TitusMapLayout_Contents * {
2
+ flex: auto;
3
+ }
@@ -0,0 +1,29 @@
1
+ import { isUndefined } from 'lodash';
2
+ import React from 'react';
3
+
4
+ import type { IFormInputValidation } from '@spinnaker/core';
5
+ import { ValidationMessage } from '@spinnaker/core';
6
+ import type { ILayoutProps } from '@spinnaker/core';
7
+ import './TitusMapLayout.less';
8
+
9
+ export function TitusMapLayout(props: ILayoutProps) {
10
+ const { label, help, input, actions, validation = {} as IFormInputValidation } = props;
11
+ const { hidden, messageNode, category } = validation;
12
+ const showLabel = !isUndefined(label) || !isUndefined(help);
13
+
14
+ return (
15
+ <div className="TitusMapLayout flex-container-v">
16
+ {showLabel && (
17
+ <h4>
18
+ {label} {help}
19
+ </h4>
20
+ )}
21
+
22
+ <div className="flex-container-h baseline margin-between-lg TitusMapLayout_Contents">
23
+ {input} {actions}
24
+ </div>
25
+
26
+ {!hidden && <ValidationMessage message={messageNode} type={category} />}
27
+ </div>
28
+ );
29
+ }
@@ -0,0 +1,285 @@
1
+ import type { FormikProps } from 'formik';
2
+ import { get, isEqual } from 'lodash';
3
+ import React from 'react';
4
+ import type { Option } from 'react-select';
5
+
6
+ import type { Application } from '@spinnaker/core';
7
+ import {
8
+ CheckboxInput,
9
+ FormikFormField,
10
+ HelpField,
11
+ LayoutProvider,
12
+ ResponsiveFieldLayout,
13
+ TetheredSelect,
14
+ } from '@spinnaker/core';
15
+
16
+ import { policyOptions } from './PolicyOptions';
17
+ import { rateOptions } from './RateOptions';
18
+ import { WindowPicker } from './WindowPicker';
19
+ import type { IJobDisruptionBudget } from '../../../../../domain';
20
+ import type { ITitusServerGroupCommand } from '../../../serverGroupConfiguration.service';
21
+ import {
22
+ defaultJobDisruptionBudget,
23
+ getDefaultJobDisruptionBudgetForApp,
24
+ } from '../../../serverGroupConfiguration.service';
25
+
26
+ export interface IJobDisruptionBudgetProps {
27
+ formik: FormikProps<ITitusServerGroupCommand>;
28
+ app: Application;
29
+ runJobView?: boolean;
30
+ onStageChange?: (values: IJobDisruptionBudget) => void;
31
+ }
32
+
33
+ export interface IJobDisruptionBudgetState {
34
+ usingDefault: boolean;
35
+ }
36
+
37
+ export interface IFieldOption extends Option {
38
+ field: keyof IJobDisruptionBudget;
39
+ description?: string;
40
+ defaultValues: any;
41
+ fieldComponent?: (props: IFieldOptionComponentProps) => JSX.Element;
42
+ }
43
+
44
+ export interface IFieldOptionComponentProps {
45
+ isDisabled: boolean;
46
+ }
47
+
48
+ export const DisruptionBudgetDescription = () => (
49
+ <p>
50
+ The Job Disruption Budget is part of the job descriptor, and defines the behavior of how containers of the job can
51
+ be relocated.{' '}
52
+ <a href="http://manuals.test.netflix.net/view/titus-docs/mkdocs/master/disruption_budget/" target="_blank">
53
+ Read the full documentation
54
+ </a>
55
+ </p>
56
+ );
57
+
58
+ export class JobDisruptionBudget extends React.Component<IJobDisruptionBudgetProps, IJobDisruptionBudgetState> {
59
+ private timeWindowOptions: IFieldOption[] = [
60
+ {
61
+ field: 'timeWindows',
62
+ label: 'Anytime',
63
+ value: 0,
64
+ defaultValues: undefined,
65
+ },
66
+ {
67
+ field: 'timeWindows',
68
+ label: 'Specific Time Windows',
69
+ value: 1,
70
+ defaultValues: defaultJobDisruptionBudget.timeWindows,
71
+ },
72
+ ];
73
+
74
+ constructor(props: IJobDisruptionBudgetProps) {
75
+ super(props);
76
+ const { disruptionBudget } = props.formik.values;
77
+ this.state = {
78
+ usingDefault: !disruptionBudget || isEqual(disruptionBudget, getDefaultJobDisruptionBudgetForApp(props.app)),
79
+ };
80
+ if (this.state.usingDefault) {
81
+ this.setToDefaultBudget();
82
+ }
83
+ }
84
+
85
+ private setToDefaultBudget(): void {
86
+ this.props.formik.setFieldValue('disruptionBudget', getDefaultJobDisruptionBudgetForApp(this.props.app));
87
+ }
88
+
89
+ private toggleUseDefault = (): void => {
90
+ if (!this.state.usingDefault) {
91
+ this.setToDefaultBudget();
92
+ }
93
+ this.setState({ usingDefault: !this.state.usingDefault });
94
+ };
95
+
96
+ private getSelectionFromFields(options: IFieldOption[]): IFieldOption {
97
+ const { disruptionBudget } = this.props.formik.values;
98
+ if (!disruptionBudget) {
99
+ return options[0];
100
+ }
101
+ return options.find((o) => !!disruptionBudget[o.field]);
102
+ }
103
+
104
+ componentDidUpdate = (oldProps: IJobDisruptionBudgetProps) => {
105
+ if (
106
+ this.props.onStageChange &&
107
+ !isEqual(oldProps.formik.values.disruptionBudget, this.props.formik.values.disruptionBudget)
108
+ ) {
109
+ this.props.onStageChange(this.props.formik.values.disruptionBudget);
110
+ }
111
+ };
112
+
113
+ private optionTypeChanged = (e: IFieldOption, options: IFieldOption[]) => {
114
+ const deselected = options.filter((o) => o !== e);
115
+ deselected.forEach((o) => this.props.formik.setFieldValue('disruptionBudget.' + o.field, undefined));
116
+ this.props.formik.setFieldValue('disruptionBudget.' + e.field, e.defaultValues);
117
+ };
118
+
119
+ private policyTypeChanged = (e: IFieldOption) => this.optionTypeChanged(e, policyOptions);
120
+
121
+ private rateTypeChanged = (e: IFieldOption) => this.optionTypeChanged(e, rateOptions);
122
+
123
+ private timeWindowsChanged = (e: IFieldOption) => {
124
+ this.props.formik.setFieldValue('disruptionBudget.' + e.field, e.defaultValues);
125
+ };
126
+
127
+ private getTimeWindowSelection(): IFieldOption {
128
+ const windows = get(this.props.formik.values, 'disruptionBudget.timeWindows');
129
+ if (windows) {
130
+ return this.timeWindowOptions.find((o) => o.defaultValues);
131
+ }
132
+ return this.timeWindowOptions.find((o) => !o.defaultValues);
133
+ }
134
+
135
+ private toggleHealthProvider(provider: string) {
136
+ const { values, setFieldValue } = this.props.formik;
137
+ const providers = values.disruptionBudget.containerHealthProviders;
138
+ const existing = providers.find((p) => p.name === provider);
139
+ if (existing) {
140
+ setFieldValue(
141
+ 'disruptionBudget.containerHealthProviders',
142
+ providers.filter((p) => p !== existing),
143
+ );
144
+ } else {
145
+ setFieldValue('disruptionBudget.containerHealthProviders', providers.concat({ name: provider }));
146
+ }
147
+ }
148
+
149
+ public render() {
150
+ const { runJobView } = this.props;
151
+ const { usingDefault } = this.state;
152
+ const budget = this.props.formik.values.disruptionBudget || getDefaultJobDisruptionBudgetForApp(this.props.app);
153
+
154
+ const policyType = this.getSelectionFromFields(policyOptions);
155
+ const PolicyFields = policyType.fieldComponent;
156
+
157
+ const rateType = this.getSelectionFromFields(rateOptions);
158
+ const RateFields = rateType?.fieldComponent;
159
+
160
+ const windowType = this.getTimeWindowSelection();
161
+
162
+ const selectedProviders = (budget.containerHealthProviders ?? []).map((p) => p.name);
163
+
164
+ const isSelfManaged = !!budget.selfManaged;
165
+ const showConfig = !runJobView || (runJobView && !usingDefault);
166
+
167
+ return (
168
+ <LayoutProvider value={ResponsiveFieldLayout}>
169
+ <div className="form-horizontal sp-margin-l-xaxis">
170
+ {!runJobView && <DisruptionBudgetDescription />}
171
+
172
+ <FormikFormField
173
+ name="usingDefault"
174
+ input={() => (
175
+ <CheckboxInput
176
+ checked={usingDefault}
177
+ onChange={this.toggleUseDefault}
178
+ text={<b>Use Netflix Defaults</b>}
179
+ />
180
+ )}
181
+ layout={runJobView ? ({ input }) => <>{input}</> : undefined}
182
+ />
183
+
184
+ {showConfig && (
185
+ <div style={{ opacity: usingDefault ? 0.5 : 1 }}>
186
+ <div className="sp-formGroup">
187
+ <div className="groupHeader">
188
+ <FormikFormField
189
+ name="policyType"
190
+ label="Policy"
191
+ input={(props) => (
192
+ <div>
193
+ <TetheredSelect
194
+ {...props}
195
+ menuContainerStyle={{ height: '300px' }}
196
+ className="Select-menu-long"
197
+ style={{ width: '300px' }}
198
+ disabled={usingDefault}
199
+ clearable={false}
200
+ onChange={this.policyTypeChanged}
201
+ value={policyType}
202
+ options={policyOptions}
203
+ />
204
+ <HelpField
205
+ expand={true}
206
+ content="A job policy defines container relocation rules and constraints"
207
+ />
208
+ </div>
209
+ )}
210
+ />
211
+ </div>
212
+ <div className="sp-formItem">
213
+ <p>{policyType.description}</p>
214
+ </div>
215
+ {PolicyFields && <PolicyFields isDisabled={usingDefault} />}
216
+ </div>
217
+ {!isSelfManaged && (
218
+ <div>
219
+ <div className={`${budget.rateUnlimited ? '' : 'sp-formGroup'}`}>
220
+ <div className={`${budget.rateUnlimited ? '' : 'groupHeader'}`}>
221
+ <FormikFormField
222
+ name="rates"
223
+ label="Rates"
224
+ input={(props) => (
225
+ <TetheredSelect
226
+ {...props}
227
+ style={{ width: '300px' }}
228
+ disabled={usingDefault}
229
+ clearable={false}
230
+ onChange={this.rateTypeChanged}
231
+ value={rateType}
232
+ options={rateOptions}
233
+ />
234
+ )}
235
+ />
236
+ </div>
237
+ <div className="sp-formItem">
238
+ <p>{rateType.description}</p>
239
+ </div>
240
+ {RateFields && <RateFields isDisabled={usingDefault} />}
241
+ </div>
242
+
243
+ <div className={`${budget.timeWindows ? 'sp-formGroup' : ''}`}>
244
+ <div className={`${budget.timeWindows ? 'groupHeader' : ''}`}>
245
+ <FormikFormField
246
+ name="timeWindows"
247
+ label="When Can Disruption Occur?"
248
+ input={(props) => (
249
+ <TetheredSelect
250
+ {...props}
251
+ style={{ width: '300px' }}
252
+ disabled={usingDefault}
253
+ clearable={false}
254
+ onChange={this.timeWindowsChanged}
255
+ value={windowType}
256
+ options={this.timeWindowOptions}
257
+ />
258
+ )}
259
+ />
260
+ </div>
261
+ {budget.timeWindows && <WindowPicker isDisabled={usingDefault} formik={this.props.formik} />}
262
+ </div>
263
+ <FormikFormField
264
+ name="healthProviders"
265
+ label="Container Health Provider"
266
+ input={() => (
267
+ <div>
268
+ <CheckboxInput
269
+ checked={selectedProviders.includes('eureka')}
270
+ onChange={() => this.toggleHealthProvider('eureka')}
271
+ text="Discovery"
272
+ disabled={usingDefault}
273
+ />
274
+ </div>
275
+ )}
276
+ />
277
+ </div>
278
+ )}
279
+ </div>
280
+ )}
281
+ </div>
282
+ </LayoutProvider>
283
+ );
284
+ }
285
+ }
@@ -0,0 +1,112 @@
1
+ import React from 'react';
2
+
3
+ import { FormikFormField, HelpField, NumberInput } from '@spinnaker/core';
4
+
5
+ import type { IFieldOption, IFieldOptionComponentProps } from './JobDisruptionBudget';
6
+ import { defaultJobDisruptionBudget } from '../../../serverGroupConfiguration.service';
7
+
8
+ const SelfManagedField = () => (
9
+ <FormikFormField
10
+ name="disruptionBudget.selfManaged.relocationTimeMs"
11
+ label="Relocation Time"
12
+ input={(props) => (
13
+ <div>
14
+ <NumberInput {...props} />
15
+ <HelpField expand={true} content="(milliseconds)" />
16
+ </div>
17
+ )}
18
+ />
19
+ );
20
+
21
+ const UnhealthyTasksLimitsField = () => (
22
+ <FormikFormField
23
+ name="disruptionBudget.unhealthyTasksLimit.limitOfUnhealthyContainers"
24
+ label="Limit of Unhealthy Containers"
25
+ input={(props) => (
26
+ <div>
27
+ <NumberInput {...props} />
28
+ <HelpField expand={true} content="(integer)" />
29
+ </div>
30
+ )}
31
+ />
32
+ );
33
+
34
+ const AvailabilityPercentageLimit = (componentProps: IFieldOptionComponentProps) => (
35
+ <FormikFormField
36
+ name="disruptionBudget.availabilityPercentageLimit.percentageOfHealthyContainers"
37
+ label="Percentage of Healthy Containers"
38
+ input={(props) => (
39
+ <div>
40
+ <NumberInput {...props} disabled={componentProps.isDisabled} />
41
+ <HelpField expand={true} content="0.0-100.0 (double)" />
42
+ </div>
43
+ )}
44
+ />
45
+ );
46
+
47
+ const RelocationLimit = () => (
48
+ <FormikFormField
49
+ name="disruptionBudget.relocationLimit.limit"
50
+ label="Limit"
51
+ input={(props) => (
52
+ <div>
53
+ <NumberInput {...props} />
54
+ <HelpField expand={true} content="(tasks)" />
55
+ </div>
56
+ )}
57
+ />
58
+ );
59
+
60
+ export const policyOptions: IFieldOption[] = [
61
+ {
62
+ field: 'availabilityPercentageLimit',
63
+ label: 'Availability Percentage Limit',
64
+ value: 0,
65
+ description: `
66
+ Lets you specify the required percentage of tasks in a healthy state.
67
+ Tasks will not be terminated by the eviction service if this limit would be violated.
68
+ `,
69
+ defaultValues: defaultJobDisruptionBudget.availabilityPercentageLimit,
70
+ fieldComponent: AvailabilityPercentageLimit,
71
+ },
72
+ {
73
+ field: 'relocationLimit',
74
+ label: 'Relocation Limit',
75
+ value: 1,
76
+ description: `
77
+ Lets you specify the maximum number of times a task can be relocated.
78
+ Should only be used with batch tasks, which have a maximum execution time.
79
+ `,
80
+ defaultValues: {
81
+ limit: 1,
82
+ },
83
+ fieldComponent: RelocationLimit,
84
+ },
85
+ {
86
+ field: 'unhealthyTasksLimit',
87
+ label: 'Unhealthy Tasks Limit',
88
+ value: 2,
89
+ description: `
90
+ Lets you specify the maximum allowed amount of tasks in an unhealthy state.
91
+ Tasks will not be terminated by the eviction service if this limit would be violated.
92
+ `,
93
+ defaultValues: {
94
+ limitOfUnhealthyContainers: 1,
95
+ },
96
+ fieldComponent: UnhealthyTasksLimitsField,
97
+ },
98
+ {
99
+ field: 'selfManaged',
100
+ label: 'Self Managed',
101
+ value: 3,
102
+ description: `
103
+ Requires that you orchestrate custom termination logic.
104
+ If the containers are not terminated within the configured amount of time,
105
+ the system default migration policy is used instead.
106
+ `,
107
+ defaultValues: {
108
+ relocationTimeMs: 24 * 60 * 60 * 1000,
109
+ },
110
+ fieldComponent: SelfManagedField,
111
+ },
112
+ ];