@spinnaker/appengine 2026.2.2 → 2026.3.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.
- package/dist/appengine.module.d.ts +7 -1
- package/dist/domain/index.d.ts +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/instance/details/AppengineInstanceDetails.d.ts +11 -0
- package/dist/loadBalancer/configure/AppengineCreateLoadBalancerModal.d.ts +29 -0
- package/dist/loadBalancer/details/AppengineLoadBalancerActions.d.ts +5 -0
- package/dist/loadBalancer/details/AppengineLoadBalancerDetailsSection.d.ts +3 -0
- package/dist/loadBalancer/details/index.d.ts +3 -0
- package/dist/loadBalancer/details/useAppengineLoadBalancerDetails.d.ts +3 -0
- package/dist/loadBalancer/transformer.d.ts +2 -6
- package/dist/pipeline/stages/AppengineExecutionDetails.d.ts +15 -0
- package/dist/pipeline/stages/AppengineServerGroupStageConfig.d.ts +12 -0
- package/dist/pipeline/stages/destroyAsg/appengineDestroyAsgStage.d.ts +1 -1
- package/dist/pipeline/stages/disableAsg/appengineDisableAsgStage.d.ts +1 -1
- package/dist/pipeline/stages/editLoadBalancer/AppengineEditLoadBalancerStageConfig.d.ts +3 -0
- package/dist/pipeline/stages/editLoadBalancer/appengineEditLoadBalancerStage.d.ts +1 -1
- package/dist/pipeline/stages/enableAsg/appengineEnableAsgStage.d.ts +1 -1
- package/dist/pipeline/stages/shrinkCluster/appengineShrinkClusterStage.d.ts +1 -1
- package/dist/pipeline/stages/startServerGroup/appengineStartServerGroupStage.d.ts +1 -1
- package/dist/pipeline/stages/stopServerGroup/appengineStopServerGroupStage.d.ts +1 -1
- package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +5 -9
- package/dist/serverGroup/configure/wizard/AppengineCloneServerGroupModal.d.ts +22 -0
- package/dist/serverGroup/details/AppengineServerGroupActions.d.ts +12 -0
- package/dist/serverGroup/details/AppengineServerGroupDetailsSection.d.ts +3 -0
- package/dist/serverGroup/details/appengineServerGroupDetailsGetter.d.ts +4 -0
- package/dist/serverGroup/details/index.d.ts +3 -0
- package/dist/serverGroup/transformer.d.ts +1 -5
- package/dist/serverGroup/writer/serverGroup.write.service.d.ts +15 -4
- package/package.json +4 -8
- package/src/appengine.module.spec.ts +194 -0
- package/src/appengine.module.ts +47 -58
- package/src/domain/index.ts +0 -1
- package/src/index.ts +1 -1
- package/src/instance/details/AppengineInstanceDetails.tsx +33 -0
- package/src/loadBalancer/configure/AppengineCreateLoadBalancerModal.tsx +342 -0
- package/src/loadBalancer/details/AppengineLoadBalancerActions.tsx +66 -0
- package/src/loadBalancer/details/AppengineLoadBalancerDetailsSection.tsx +42 -0
- package/src/loadBalancer/details/index.ts +3 -0
- package/src/loadBalancer/details/useAppengineLoadBalancerDetails.ts +37 -0
- package/src/loadBalancer/transformer.ts +3 -14
- package/src/pipeline/stages/AppengineExecutionDetails.tsx +90 -0
- package/src/pipeline/stages/AppengineServerGroupStageConfig.tsx +190 -0
- package/src/pipeline/stages/destroyAsg/appengineDestroyAsgStage.ts +17 -43
- package/src/pipeline/stages/disableAsg/appengineDisableAsgStage.ts +18 -53
- package/src/pipeline/stages/editLoadBalancer/AppengineEditLoadBalancerStageConfig.tsx +94 -0
- package/src/pipeline/stages/editLoadBalancer/appengineEditLoadBalancerStage.ts +14 -74
- package/src/pipeline/stages/enableAsg/appengineEnableAsgStage.ts +13 -48
- package/src/pipeline/stages/shrinkCluster/appengineShrinkClusterStage.ts +13 -61
- package/src/pipeline/stages/startServerGroup/appengineStartServerGroupStage.ts +17 -54
- package/src/pipeline/stages/stopServerGroup/appengineStopServerGroupStage.ts +17 -54
- package/src/serverGroup/configure/serverGroupCommandBuilder.service.ts +20 -19
- package/src/serverGroup/configure/wizard/AppengineCloneServerGroupModal.tsx +119 -0
- package/src/serverGroup/configure/wizard/serverGroupWizard.less +0 -8
- package/src/serverGroup/details/AppengineServerGroupActions.tsx +245 -0
- package/src/serverGroup/details/AppengineServerGroupDetailsSection.tsx +27 -0
- package/src/serverGroup/details/appengineServerGroupDetailsGetter.ts +62 -0
- package/src/serverGroup/details/index.ts +3 -0
- package/src/serverGroup/transformer.ts +3 -15
- package/src/serverGroup/writer/serverGroup.write.service.ts +57 -8
- package/dist/common/componentUrlDetails.component.d.ts +0 -1
- package/dist/common/conditionalDescriptionListItem.component.d.ts +0 -1
- package/dist/common/loadBalancerMessage.component.d.ts +0 -1
- package/dist/domain/IAppengineStageScope.d.ts +0 -18
- package/dist/instance/details/details.controller.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/advancedSettings.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/allocationConfigurationRow.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/basicSettings.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/wizard.controller.d.ts +0 -2
- package/dist/loadBalancer/details/details.controller.d.ts +0 -1
- package/dist/loadBalancer/loadBalancer.module.d.ts +0 -1
- package/dist/pipeline/pipeline.module.d.ts +0 -1
- package/dist/pipeline/stages/appengineStage.controller.d.ts +0 -12
- package/dist/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.controller.d.ts +0 -1
- package/dist/serverGroup/configure/wizard/basicSettings.controller.d.ts +0 -1
- package/dist/serverGroup/configure/wizard/cloneServerGroup.controller.d.ts +0 -2
- package/dist/serverGroup/configure/wizard/configFileArtifactList.module.d.ts +0 -1
- package/dist/serverGroup/configure/wizard/configFiles.component.d.ts +0 -20
- package/dist/serverGroup/configure/wizard/dynamicBranchLabel.component.d.ts +0 -1
- package/dist/serverGroup/details/details.controller.d.ts +0 -1
- package/src/common/componentUrlDetails.component.ts +0 -29
- package/src/common/conditionalDescriptionListItem.component.ts +0 -37
- package/src/common/loadBalancerMessage.component.html +0 -33
- package/src/common/loadBalancerMessage.component.ts +0 -13
- package/src/domain/IAppengineStageScope.ts +0 -22
- package/src/instance/details/details.controller.ts +0 -116
- package/src/instance/details/details.html +0 -99
- package/src/loadBalancer/configure/wizard/advancedSettings.component.ts +0 -56
- package/src/loadBalancer/configure/wizard/allocationConfigurationRow.component.ts +0 -70
- package/src/loadBalancer/configure/wizard/basicSettings.component.html +0 -65
- package/src/loadBalancer/configure/wizard/basicSettings.component.ts +0 -98
- package/src/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.html +0 -117
- package/src/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.ts +0 -108
- package/src/loadBalancer/configure/wizard/wizard.controller.ts +0 -163
- package/src/loadBalancer/configure/wizard/wizard.html +0 -44
- package/src/loadBalancer/configure/wizard/wizard.less +0 -17
- package/src/loadBalancer/details/details.controller.ts +0 -151
- package/src/loadBalancer/details/details.html +0 -102
- package/src/loadBalancer/loadBalancer.module.ts +0 -21
- package/src/pipeline/pipeline.module.ts +0 -20
- package/src/pipeline/stages/appengineStage.controller.ts +0 -45
- package/src/pipeline/stages/destroyAsg/destroyAsgStage.html +0 -16
- package/src/pipeline/stages/destroyAsg/destroyAsgStepLabel.html +0 -1
- package/src/pipeline/stages/disableAsg/disableAsgStage.html +0 -18
- package/src/pipeline/stages/disableAsg/disableAsgStepLabel.html +0 -1
- package/src/pipeline/stages/editLoadBalancer/editLoadBalancerExecutionDetails.html +0 -33
- package/src/pipeline/stages/editLoadBalancer/editLoadBalancerStage.html +0 -51
- package/src/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.controller.ts +0 -65
- package/src/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.html +0 -45
- package/src/pipeline/stages/enableAsg/enableAsgStage.html +0 -18
- package/src/pipeline/stages/enableAsg/enableAsgStepLabel.html +0 -1
- package/src/pipeline/stages/shrinkCluster/shrinkClusterStage.html +0 -41
- package/src/pipeline/stages/startServerGroup/startServerGroupExecutionDetails.html +0 -26
- package/src/pipeline/stages/startServerGroup/startServerGroupStage.html +0 -18
- package/src/pipeline/stages/startServerGroup/startServerGroupStepLabel.html +0 -1
- package/src/pipeline/stages/stopServerGroup/stopServerGroupExecutionDetails.html +0 -26
- package/src/pipeline/stages/stopServerGroup/stopServerGroupStage.html +0 -18
- package/src/pipeline/stages/stopServerGroup/stopServerGroupStepLabel.html +0 -1
- package/src/serverGroup/configure/wizard/advancedSettings.html +0 -33
- package/src/serverGroup/configure/wizard/basicSettings.controller.ts +0 -151
- package/src/serverGroup/configure/wizard/basicSettings.html +0 -287
- package/src/serverGroup/configure/wizard/cloneServerGroup.controller.ts +0 -103
- package/src/serverGroup/configure/wizard/configFileArtifactList.module.ts +0 -18
- package/src/serverGroup/configure/wizard/configFiles.component.html +0 -81
- package/src/serverGroup/configure/wizard/configFiles.component.ts +0 -121
- package/src/serverGroup/configure/wizard/dynamicBranchLabel.component.ts +0 -19
- package/src/serverGroup/configure/wizard/serverGroupWizard.html +0 -39
- package/src/serverGroup/details/details.controller.ts +0 -463
- package/src/serverGroup/details/details.html +0 -229
|
@@ -1,54 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
super.setStageCloudProvider();
|
|
19
|
-
super.setTargets();
|
|
20
|
-
super.setStageCredentials();
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
$scope.stage.isNew &&
|
|
24
|
-
$scope.application.attributes.platformHealthOnlyShowOverride &&
|
|
25
|
-
$scope.application.attributes.platformHealthOnly
|
|
26
|
-
) {
|
|
27
|
-
$scope.stage.interestingHealthProviderNames = [AppengineHealth.PLATFORM];
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const APPENGINE_START_SERVER_GROUP_STAGE = 'spinnaker.appengine.pipeline.stage.startServerGroupStage';
|
|
33
|
-
|
|
34
|
-
module(APPENGINE_START_SERVER_GROUP_STAGE, [])
|
|
35
|
-
.config(() => {
|
|
36
|
-
Registry.pipeline.registerStage({
|
|
37
|
-
label: 'Start Server Group',
|
|
38
|
-
description: 'Starts a server group.',
|
|
39
|
-
key: 'startAppEngineServerGroup',
|
|
40
|
-
templateUrl: require('./startServerGroupStage.html'),
|
|
41
|
-
executionDetailsUrl: require('./startServerGroupExecutionDetails.html'),
|
|
42
|
-
executionConfigSections: ['startServerGroupConfig', 'taskStatus'],
|
|
43
|
-
executionStepLabelUrl: require('./startServerGroupStepLabel.html'),
|
|
44
|
-
controller: 'appengineStartServerGroupStageCtrl',
|
|
45
|
-
controllerAs: 'startServerGroupStageCtrl',
|
|
46
|
-
validators: [
|
|
47
|
-
{ type: 'requiredField', fieldName: 'cluster' },
|
|
48
|
-
{ type: 'requiredField', fieldName: 'target' },
|
|
49
|
-
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
|
|
50
|
-
],
|
|
51
|
-
cloudProvider: 'appengine',
|
|
52
|
-
});
|
|
53
|
-
})
|
|
54
|
-
.controller('appengineStartServerGroupStageCtrl', AppengineStartServerGroupStageCtrl);
|
|
1
|
+
import { ExecutionDetailsTasks, Registry } from '@spinnaker/core';
|
|
2
|
+
import { AppengineStartServerGroupExecutionDetails } from '../AppengineExecutionDetails';
|
|
3
|
+
import { AppengineServerGroupStageConfigWithHealthOverride } from '../AppengineServerGroupStageConfig';
|
|
4
|
+
|
|
5
|
+
Registry.pipeline.registerStage({
|
|
6
|
+
label: 'Start Server Group',
|
|
7
|
+
description: 'Starts a server group.',
|
|
8
|
+
key: 'startAppEngineServerGroup',
|
|
9
|
+
component: AppengineServerGroupStageConfigWithHealthOverride,
|
|
10
|
+
executionDetailsSections: [AppengineStartServerGroupExecutionDetails, ExecutionDetailsTasks],
|
|
11
|
+
validators: [
|
|
12
|
+
{ type: 'requiredField', fieldName: 'cluster' },
|
|
13
|
+
{ type: 'requiredField', fieldName: 'target' },
|
|
14
|
+
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
|
|
15
|
+
],
|
|
16
|
+
cloudProvider: 'appengine',
|
|
17
|
+
});
|
|
@@ -1,54 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
super.setStageCloudProvider();
|
|
19
|
-
super.setTargets();
|
|
20
|
-
super.setStageCredentials();
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
$scope.stage.isNew &&
|
|
24
|
-
$scope.application.attributes.platformHealthOnlyShowOverride &&
|
|
25
|
-
$scope.application.attributes.platformHealthOnly
|
|
26
|
-
) {
|
|
27
|
-
$scope.stage.interestingHealthProviderNames = [AppengineHealth.PLATFORM];
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const APPENGINE_STOP_SERVER_GROUP_STAGE = 'spinnaker.appengine.pipeline.stage.stopServerGroupStage';
|
|
33
|
-
|
|
34
|
-
module(APPENGINE_STOP_SERVER_GROUP_STAGE, [])
|
|
35
|
-
.config(() => {
|
|
36
|
-
Registry.pipeline.registerStage({
|
|
37
|
-
label: 'Stop Server Group',
|
|
38
|
-
description: 'Stops a server group.',
|
|
39
|
-
key: 'stopAppEngineServerGroup',
|
|
40
|
-
templateUrl: require('./stopServerGroupStage.html'),
|
|
41
|
-
executionDetailsUrl: require('./stopServerGroupExecutionDetails.html'),
|
|
42
|
-
executionConfigSections: ['stopServerGroupConfig', 'taskStatus'],
|
|
43
|
-
executionStepLabelUrl: require('./stopServerGroupStepLabel.html'),
|
|
44
|
-
controller: 'appengineStopServerGroupStageCtrl',
|
|
45
|
-
controllerAs: 'stopServerGroupStageCtrl',
|
|
46
|
-
validators: [
|
|
47
|
-
{ type: 'requiredField', fieldName: 'cluster' },
|
|
48
|
-
{ type: 'requiredField', fieldName: 'target' },
|
|
49
|
-
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
|
|
50
|
-
],
|
|
51
|
-
cloudProvider: 'appengine',
|
|
52
|
-
});
|
|
53
|
-
})
|
|
54
|
-
.controller('appengineStopServerGroupStageCtrl', AppengineStopServerGroupStageCtrl);
|
|
1
|
+
import { ExecutionDetailsTasks, Registry } from '@spinnaker/core';
|
|
2
|
+
import { AppengineStopServerGroupExecutionDetails } from '../AppengineExecutionDetails';
|
|
3
|
+
import { AppengineServerGroupStageConfigWithHealthOverride } from '../AppengineServerGroupStageConfig';
|
|
4
|
+
|
|
5
|
+
Registry.pipeline.registerStage({
|
|
6
|
+
label: 'Stop Server Group',
|
|
7
|
+
description: 'Stops a server group.',
|
|
8
|
+
key: 'stopAppEngineServerGroup',
|
|
9
|
+
component: AppengineServerGroupStageConfigWithHealthOverride,
|
|
10
|
+
executionDetailsSections: [AppengineStopServerGroupExecutionDetails, ExecutionDetailsTasks],
|
|
11
|
+
validators: [
|
|
12
|
+
{ type: 'requiredField', fieldName: 'cluster' },
|
|
13
|
+
{ type: 'requiredField', fieldName: 'target' },
|
|
14
|
+
{ type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
|
|
15
|
+
],
|
|
16
|
+
cloudProvider: 'appengine',
|
|
17
|
+
});
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { IQService } from 'angular';
|
|
2
|
-
import { module } from 'angular';
|
|
3
|
-
|
|
4
1
|
import type {
|
|
5
2
|
Application,
|
|
6
3
|
IArtifact,
|
|
@@ -95,14 +92,11 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
95
92
|
return pipeline.expectedArtifacts || [];
|
|
96
93
|
}
|
|
97
94
|
|
|
98
|
-
public static $inject = ['$q'];
|
|
99
|
-
constructor(private $q: IQService) {}
|
|
100
|
-
|
|
101
95
|
public buildNewServerGroupCommand(
|
|
102
96
|
app: Application,
|
|
103
97
|
selectedProvider: string,
|
|
104
98
|
mode = 'create',
|
|
105
|
-
):
|
|
99
|
+
): Promise<IAppengineServerGroupCommand> {
|
|
106
100
|
if (selectedProvider == null) {
|
|
107
101
|
selectedProvider = 'appengine';
|
|
108
102
|
}
|
|
@@ -117,7 +111,7 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
117
111
|
disableStrategySelection: mode === 'create',
|
|
118
112
|
};
|
|
119
113
|
|
|
120
|
-
return this
|
|
114
|
+
return this.resolveAll(dataToFetch).then((backingData: any) => {
|
|
121
115
|
const credentials = this.getCredentials(backingData.accounts);
|
|
122
116
|
const region = this.getRegion(backingData.accounts, credentials);
|
|
123
117
|
|
|
@@ -129,6 +123,9 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
129
123
|
credentials,
|
|
130
124
|
region,
|
|
131
125
|
selectedProvider,
|
|
126
|
+
configArtifacts: [],
|
|
127
|
+
configFilepaths: [],
|
|
128
|
+
configFiles: [],
|
|
132
129
|
interestingHealthProviderNames: [],
|
|
133
130
|
sourceType: AppengineSourceType.GIT,
|
|
134
131
|
} as IAppengineServerGroupCommand;
|
|
@@ -138,7 +135,7 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
138
135
|
public buildServerGroupCommandFromExisting(
|
|
139
136
|
app: Application,
|
|
140
137
|
serverGroup: IAppengineServerGroup,
|
|
141
|
-
):
|
|
138
|
+
): Promise<IAppengineServerGroupCommand> {
|
|
142
139
|
return this.buildNewServerGroupCommand(app, 'appengine', 'clone').then((command) => {
|
|
143
140
|
command.stack = serverGroup.stack;
|
|
144
141
|
command.freeFormDetails = serverGroup.detail;
|
|
@@ -149,7 +146,7 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
149
146
|
public buildNewServerGroupCommandForPipeline(
|
|
150
147
|
_stage: IStage,
|
|
151
148
|
pipeline: IPipeline,
|
|
152
|
-
):
|
|
149
|
+
): Promise<{
|
|
153
150
|
viewState: {
|
|
154
151
|
stage: IStage;
|
|
155
152
|
pipeline: IPipeline;
|
|
@@ -161,7 +158,7 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
161
158
|
}> {
|
|
162
159
|
// We can't copy server group configuration for App Engine, and can't build the full command here because we don't have
|
|
163
160
|
// access to the application.
|
|
164
|
-
return
|
|
161
|
+
return Promise.resolve({
|
|
165
162
|
viewState: {
|
|
166
163
|
pipeline,
|
|
167
164
|
stage: _stage,
|
|
@@ -178,7 +175,7 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
178
175
|
cluster: AppengineDeployDescription,
|
|
179
176
|
_stage: IStage,
|
|
180
177
|
pipeline: IPipeline,
|
|
181
|
-
):
|
|
178
|
+
): Promise<IAppengineServerGroupCommand> {
|
|
182
179
|
return this.buildNewServerGroupCommand(app, 'appengine', 'editPipeline').then(
|
|
183
180
|
(command: IAppengineServerGroupCommand) => {
|
|
184
181
|
command = {
|
|
@@ -225,11 +222,15 @@ export class AppengineServerGroupCommandBuilder {
|
|
|
225
222
|
return 'Create';
|
|
226
223
|
}
|
|
227
224
|
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export const APPENGINE_SERVER_GROUP_COMMAND_BUILDER = 'spinnaker.appengine.serverGroupCommandBuilder.service';
|
|
231
225
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
);
|
|
226
|
+
private resolveAll<T extends Record<string, PromiseLike<any>>>(
|
|
227
|
+
dataToFetch: T,
|
|
228
|
+
): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
|
|
229
|
+
const entries = Object.entries(dataToFetch);
|
|
230
|
+
return Promise.all(entries.map(([, promise]) => promise)).then((values) => {
|
|
231
|
+
return entries.reduce((result, [key], index) => ({ ...result, [key]: values[index] }), {}) as {
|
|
232
|
+
[K in keyof T]: Awaited<T[K]>;
|
|
233
|
+
};
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal } from 'react-bootstrap';
|
|
3
|
+
|
|
4
|
+
import type { Application, IModalComponentProps } from '@spinnaker/core';
|
|
5
|
+
import { ModalClose, noop, ReactModal, TaskMonitor, TaskMonitorWrapper } from '@spinnaker/core';
|
|
6
|
+
|
|
7
|
+
import type { IAppengineServerGroupCommand } from '../serverGroupCommandBuilder.service';
|
|
8
|
+
import { AppengineSourceType } from '../serverGroupCommandBuilder.service';
|
|
9
|
+
import { AppengineServerGroupWriter } from '../../writer/serverGroup.write.service';
|
|
10
|
+
|
|
11
|
+
export interface IAppengineCloneServerGroupModalProps extends Partial<IModalComponentProps> {
|
|
12
|
+
application: Application;
|
|
13
|
+
command: IAppengineServerGroupCommand;
|
|
14
|
+
title: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IAppengineCloneServerGroupModalState {
|
|
18
|
+
taskMonitor: TaskMonitor;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const writer = new AppengineServerGroupWriter();
|
|
22
|
+
|
|
23
|
+
export function normalizeAppengineServerGroupCommandForSubmit(
|
|
24
|
+
command: IAppengineServerGroupCommand,
|
|
25
|
+
): IAppengineServerGroupCommand {
|
|
26
|
+
return {
|
|
27
|
+
...command,
|
|
28
|
+
configArtifacts: command.configArtifacts || [],
|
|
29
|
+
configFilepaths: command.configFilepaths || [],
|
|
30
|
+
configFiles: command.configFiles || [],
|
|
31
|
+
interestingHealthProviderNames: command.interestingHealthProviderNames || [],
|
|
32
|
+
fromArtifact: command.fromArtifact || false,
|
|
33
|
+
sourceType: command.sourceType || AppengineSourceType.GIT,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class AppengineCloneServerGroupModal extends React.Component<
|
|
38
|
+
IAppengineCloneServerGroupModalProps,
|
|
39
|
+
IAppengineCloneServerGroupModalState
|
|
40
|
+
> {
|
|
41
|
+
public static defaultProps: Partial<IAppengineCloneServerGroupModalProps> = {
|
|
42
|
+
closeModal: noop,
|
|
43
|
+
dismissModal: noop,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
public static show(props: IAppengineCloneServerGroupModalProps): Promise<IAppengineServerGroupCommand> {
|
|
47
|
+
return ReactModal.show(AppengineCloneServerGroupModal, props, { dialogClassName: 'modal-lg' });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public state: IAppengineCloneServerGroupModalState = {
|
|
51
|
+
taskMonitor: new TaskMonitor({
|
|
52
|
+
application: this.props.application,
|
|
53
|
+
title: 'Creating your server group',
|
|
54
|
+
onDismiss: () => this.props.dismissModal(),
|
|
55
|
+
onTaskComplete: () => this.props.application.serverGroups.refresh(),
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
private update = (field: keyof IAppengineServerGroupCommand, value: any) => {
|
|
60
|
+
(this.props.command as any)[field] = value;
|
|
61
|
+
this.forceUpdate();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
private submit = () => {
|
|
65
|
+
const { command } = this.props;
|
|
66
|
+
if (command.viewState.mode === 'editPipeline' || command.viewState.mode === 'createPipeline') {
|
|
67
|
+
this.props.closeModal(command);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.state.taskMonitor.submit(() =>
|
|
72
|
+
writer.cloneServerGroup(normalizeAppengineServerGroupCommandForSubmit(command), this.props.application),
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
public render() {
|
|
77
|
+
const { command, dismissModal, title } = this.props;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div>
|
|
81
|
+
<ModalClose dismiss={dismissModal} />
|
|
82
|
+
<Modal.Header>
|
|
83
|
+
<Modal.Title>{title}</Modal.Title>
|
|
84
|
+
</Modal.Header>
|
|
85
|
+
<Modal.Body>
|
|
86
|
+
<div className="form-horizontal">
|
|
87
|
+
<label>Account</label>
|
|
88
|
+
<input
|
|
89
|
+
className="form-control input-sm"
|
|
90
|
+
onChange={(event) => this.update('credentials', event.target.value)}
|
|
91
|
+
value={command.credentials || ''}
|
|
92
|
+
/>
|
|
93
|
+
<label>Region</label>
|
|
94
|
+
<input
|
|
95
|
+
className="form-control input-sm"
|
|
96
|
+
onChange={(event) => this.update('region', event.target.value)}
|
|
97
|
+
value={command.region || ''}
|
|
98
|
+
/>
|
|
99
|
+
<label>Branch</label>
|
|
100
|
+
<input
|
|
101
|
+
className="form-control input-sm"
|
|
102
|
+
onChange={(event) => this.update('branch', event.target.value)}
|
|
103
|
+
value={command.branch || ''}
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
</Modal.Body>
|
|
107
|
+
<TaskMonitorWrapper monitor={this.state.taskMonitor} />
|
|
108
|
+
<Modal.Footer>
|
|
109
|
+
<button className="btn btn-default" onClick={() => dismissModal()} type="button">
|
|
110
|
+
Cancel
|
|
111
|
+
</button>
|
|
112
|
+
<button className="btn btn-primary" onClick={this.submit} type="button">
|
|
113
|
+
{command.viewState?.submitButtonLabel || 'Clone'}
|
|
114
|
+
</button>
|
|
115
|
+
</Modal.Footer>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Application, IConfirmationModalParams, IServerGroup, IServerGroupActionsProps } from '@spinnaker/core';
|
|
4
|
+
import { ConfirmationModalService, ServerGroupWarningMessageService } from '@spinnaker/core';
|
|
5
|
+
|
|
6
|
+
import { AppengineHealth } from '../../common/appengineHealth';
|
|
7
|
+
import { AppengineServerGroupCommandBuilder } from '../configure/serverGroupCommandBuilder.service';
|
|
8
|
+
import { AppengineCloneServerGroupModal } from '../configure/wizard/AppengineCloneServerGroupModal';
|
|
9
|
+
import type { IAppengineServerGroup } from '../../domain';
|
|
10
|
+
import { AppengineServerGroupWriter } from '../writer/serverGroup.write.service';
|
|
11
|
+
|
|
12
|
+
const writer = new AppengineServerGroupWriter();
|
|
13
|
+
const commandBuilder = new AppengineServerGroupCommandBuilder();
|
|
14
|
+
|
|
15
|
+
export function canStartOrStopServerGroup(serverGroup: IAppengineServerGroup): boolean {
|
|
16
|
+
return serverGroup.env === 'FLEXIBLE' || ['MANUAL', 'BASIC'].includes(serverGroup.scalingPolicy?.type);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function canStartServerGroup(serverGroup: IAppengineServerGroup): boolean {
|
|
20
|
+
return canStartOrStopServerGroup(serverGroup) && serverGroup.servingStatus === 'STOPPED';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function canStopServerGroup(serverGroup: IAppengineServerGroup): boolean {
|
|
24
|
+
return canStartOrStopServerGroup(serverGroup) && serverGroup.servingStatus === 'SERVING';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function expectedAllocationsAfterDisableOperation(
|
|
28
|
+
serverGroup: IServerGroup,
|
|
29
|
+
loadBalancers: any[] = [],
|
|
30
|
+
): { [key: string]: number } {
|
|
31
|
+
const loadBalancer = loadBalancers.find((toCheck) => {
|
|
32
|
+
return Object.keys(toCheck.split?.allocations || {}).includes(serverGroup.name);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!loadBalancer) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const allocations: { [key: string]: number } = { ...loadBalancer.split.allocations };
|
|
40
|
+
delete allocations[serverGroup.name];
|
|
41
|
+
const denominator = Object.values(allocations).reduce((sum, allocation) => sum + allocation, 0);
|
|
42
|
+
if (!denominator) {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const precision = loadBalancer.split.shardBy === 'COOKIE' ? 1000 : 100;
|
|
47
|
+
Object.keys(allocations).forEach((serverGroupName) => {
|
|
48
|
+
allocations[serverGroupName] = Math.round((allocations[serverGroupName] / denominator) * precision) / precision;
|
|
49
|
+
});
|
|
50
|
+
return allocations;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function canDisableServerGroup(serverGroup: IAppengineServerGroup, loadBalancers: any[] = []): boolean {
|
|
54
|
+
if (!serverGroup || serverGroup.disabled) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return Object.keys(expectedAllocationsAfterDisableOperation(serverGroup, loadBalancers) || {}).length > 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function canDestroyServerGroup(serverGroup: IAppengineServerGroup, loadBalancers: any[] = []): boolean {
|
|
62
|
+
if (!serverGroup) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
serverGroup.disabled ||
|
|
68
|
+
Object.keys(expectedAllocationsAfterDisableOperation(serverGroup, loadBalancers) || {}).length > 0
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function buildExpectedAllocationsTable(expectedAllocations: { [key: string]: number }): string {
|
|
73
|
+
const rows = Object.keys(expectedAllocations || {})
|
|
74
|
+
.map(
|
|
75
|
+
(serverGroupName) =>
|
|
76
|
+
`<tr><td>${serverGroupName}</td><td>${expectedAllocations[serverGroupName] * 100}%</td></tr>`,
|
|
77
|
+
)
|
|
78
|
+
.join('');
|
|
79
|
+
|
|
80
|
+
return `<table class="table table-condensed"><thead><tr><th>Server Group</th><th>Allocation</th></tr></thead><tbody>${rows}</tbody></table>`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getLoadBalancers(app: Application): any[] {
|
|
84
|
+
return app.getDataSource?.('loadBalancers')?.data || [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function platformHealthParams(app: Application): Partial<IConfirmationModalParams> {
|
|
88
|
+
const params: Partial<IConfirmationModalParams> = {
|
|
89
|
+
platformHealthOnlyShowOverride: app.attributes?.platformHealthOnlyShowOverride,
|
|
90
|
+
platformHealthType: AppengineHealth.PLATFORM,
|
|
91
|
+
interestingHealthProviderNames: [],
|
|
92
|
+
};
|
|
93
|
+
if (app.attributes?.platformHealthOnlyShowOverride && app.attributes?.platformHealthOnly) {
|
|
94
|
+
params.interestingHealthProviderNames = [AppengineHealth.PLATFORM];
|
|
95
|
+
}
|
|
96
|
+
return params;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getDisableBody(serverGroup: IAppengineServerGroup, loadBalancers: any[]): string {
|
|
100
|
+
const expectedAllocations = expectedAllocationsAfterDisableOperation(serverGroup, loadBalancers);
|
|
101
|
+
return `<div class="well well-sm">
|
|
102
|
+
<p>For App Engine, a disable operation sets this server group's allocation to 0% and redistributes traffic to the other enabled server groups.</p>
|
|
103
|
+
<p>If you would like more fine-grained control, edit <b>${
|
|
104
|
+
serverGroup.loadBalancers?.[0]
|
|
105
|
+
}</b> under the <b>Load Balancers</b> tab.</p>
|
|
106
|
+
<div class="row"><div class="col-md-12">${buildExpectedAllocationsTable(expectedAllocations)}</div></div>
|
|
107
|
+
</div>`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getDestroyBody(app: Application, serverGroup: IAppengineServerGroup, loadBalancers: any[]): string {
|
|
111
|
+
let body = '';
|
|
112
|
+
const params: IConfirmationModalParams = {} as IConfirmationModalParams;
|
|
113
|
+
ServerGroupWarningMessageService.addDestroyWarningMessage(app, serverGroup, params);
|
|
114
|
+
if (params.body) {
|
|
115
|
+
body += params.body;
|
|
116
|
+
}
|
|
117
|
+
if (!serverGroup.disabled) {
|
|
118
|
+
body += `<div class="well well-sm">
|
|
119
|
+
<p>A destroy operation will first disable this server group.</p>
|
|
120
|
+
<p>For App Engine, a disable operation sets this server group's allocation to 0% and redistributes traffic to the other enabled server groups.</p>
|
|
121
|
+
<p>If you would like more fine-grained control, edit <b>${
|
|
122
|
+
serverGroup.loadBalancers?.[0]
|
|
123
|
+
}</b> under the <b>Load Balancers</b> tab.</p>
|
|
124
|
+
<div class="row"><div class="col-md-12">${buildExpectedAllocationsTable(
|
|
125
|
+
expectedAllocationsAfterDisableOperation(serverGroup, loadBalancers),
|
|
126
|
+
)}</div></div>
|
|
127
|
+
</div>`;
|
|
128
|
+
}
|
|
129
|
+
return body;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function AppengineServerGroupActions({ app, serverGroup }: IServerGroupActionsProps) {
|
|
133
|
+
const appengineServerGroup = serverGroup as IAppengineServerGroup;
|
|
134
|
+
const loadBalancers = getLoadBalancers(app);
|
|
135
|
+
|
|
136
|
+
const clone = () => {
|
|
137
|
+
commandBuilder.buildServerGroupCommandFromExisting(app, appengineServerGroup).then((command) => {
|
|
138
|
+
AppengineCloneServerGroupModal.show({ application: app, command, title: `Clone ${serverGroup.name}` });
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const start = () =>
|
|
143
|
+
ConfirmationModalService.confirm({
|
|
144
|
+
header: `Really start ${serverGroup.name}?`,
|
|
145
|
+
buttonText: `Start ${serverGroup.name}`,
|
|
146
|
+
account: appengineServerGroup.account,
|
|
147
|
+
taskMonitorConfig: { application: app, title: `Starting ${serverGroup.name}` },
|
|
148
|
+
submitMethod: () => writer.startServerGroup(appengineServerGroup, app),
|
|
149
|
+
askForReason: true,
|
|
150
|
+
...platformHealthParams(app),
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const stop = () =>
|
|
154
|
+
ConfirmationModalService.confirm({
|
|
155
|
+
header: `Really stop ${serverGroup.name}?`,
|
|
156
|
+
buttonText: `Stop ${serverGroup.name}`,
|
|
157
|
+
account: appengineServerGroup.account,
|
|
158
|
+
body: !appengineServerGroup.disabled
|
|
159
|
+
? `<div class="alert alert-danger"><p>Stopping this server group will scale it down to zero instances.</p><p>This server group is currently serving traffic from <b>${appengineServerGroup.loadBalancers?.[0]}</b>. Traffic directed to this server group after it has been stopped will not be handled.</p></div>`
|
|
160
|
+
: undefined,
|
|
161
|
+
taskMonitorConfig: { application: app, title: `Stopping ${serverGroup.name}` },
|
|
162
|
+
submitMethod: () => writer.stopServerGroup(appengineServerGroup, app),
|
|
163
|
+
askForReason: true,
|
|
164
|
+
...platformHealthParams(app),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const enable = () =>
|
|
168
|
+
ConfirmationModalService.confirm({
|
|
169
|
+
header: `Really enable ${serverGroup.name}?`,
|
|
170
|
+
buttonText: `Enable ${serverGroup.name}`,
|
|
171
|
+
account: appengineServerGroup.account,
|
|
172
|
+
body: `<div class="well well-sm"><p>Enabling <b>${serverGroup.name}</b> will set its traffic allocation for <b>${appengineServerGroup.loadBalancers?.[0]}</b> to 100%.</p><p>If you would like more fine-grained control, edit <b>${appengineServerGroup.loadBalancers?.[0]}</b> under the <b>Load Balancers</b> tab.</p></div>`,
|
|
173
|
+
taskMonitorConfig: { application: app, title: `Enabling ${serverGroup.name}` },
|
|
174
|
+
submitMethod: (params: any) => writer.enableServerGroup(appengineServerGroup, app, params),
|
|
175
|
+
askForReason: true,
|
|
176
|
+
...platformHealthParams(app),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const disable = () =>
|
|
180
|
+
ConfirmationModalService.confirm({
|
|
181
|
+
header: `Really disable ${serverGroup.name}?`,
|
|
182
|
+
buttonText: `Disable ${serverGroup.name}`,
|
|
183
|
+
account: appengineServerGroup.account,
|
|
184
|
+
body: getDisableBody(appengineServerGroup, loadBalancers),
|
|
185
|
+
taskMonitorConfig: { application: app, title: `Disabling ${serverGroup.name}` },
|
|
186
|
+
submitMethod: (params: any) => writer.disableServerGroup(appengineServerGroup, app, params),
|
|
187
|
+
askForReason: true,
|
|
188
|
+
...platformHealthParams(app),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const destroy = () =>
|
|
192
|
+
ConfirmationModalService.confirm({
|
|
193
|
+
header: `Really destroy ${serverGroup.name}?`,
|
|
194
|
+
buttonText: `Destroy ${serverGroup.name}`,
|
|
195
|
+
account: appengineServerGroup.account,
|
|
196
|
+
body: getDestroyBody(app, appengineServerGroup, loadBalancers),
|
|
197
|
+
taskMonitorConfig: { application: app, title: `Destroying ${serverGroup.name}` },
|
|
198
|
+
submitMethod: (params: any) => writer.destroyServerGroup(appengineServerGroup, app, params),
|
|
199
|
+
askForReason: true,
|
|
200
|
+
...platformHealthParams(app),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<div className="actions">
|
|
205
|
+
<button className="btn btn-sm btn-default" onClick={clone} type="button">
|
|
206
|
+
Clone
|
|
207
|
+
</button>
|
|
208
|
+
<button
|
|
209
|
+
className="btn btn-sm btn-default"
|
|
210
|
+
disabled={!canStartServerGroup(appengineServerGroup)}
|
|
211
|
+
onClick={start}
|
|
212
|
+
type="button"
|
|
213
|
+
>
|
|
214
|
+
Start
|
|
215
|
+
</button>
|
|
216
|
+
<button
|
|
217
|
+
className="btn btn-sm btn-default"
|
|
218
|
+
disabled={!canStopServerGroup(appengineServerGroup)}
|
|
219
|
+
onClick={stop}
|
|
220
|
+
type="button"
|
|
221
|
+
>
|
|
222
|
+
Stop
|
|
223
|
+
</button>
|
|
224
|
+
<button className="btn btn-sm btn-default" onClick={enable} type="button">
|
|
225
|
+
Enable
|
|
226
|
+
</button>
|
|
227
|
+
<button
|
|
228
|
+
className="btn btn-sm btn-default"
|
|
229
|
+
disabled={!canDisableServerGroup(appengineServerGroup, loadBalancers)}
|
|
230
|
+
onClick={disable}
|
|
231
|
+
type="button"
|
|
232
|
+
>
|
|
233
|
+
Disable
|
|
234
|
+
</button>
|
|
235
|
+
<button
|
|
236
|
+
className="btn btn-sm btn-default"
|
|
237
|
+
disabled={!canDestroyServerGroup(appengineServerGroup, loadBalancers)}
|
|
238
|
+
onClick={destroy}
|
|
239
|
+
type="button"
|
|
240
|
+
>
|
|
241
|
+
Destroy
|
|
242
|
+
</button>
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { IServerGroupDetailsSectionProps } from '@spinnaker/core';
|
|
4
|
+
|
|
5
|
+
import type { IAppengineServerGroup } from '../../domain';
|
|
6
|
+
|
|
7
|
+
export function AppengineServerGroupDetailsSection({ serverGroup }: IServerGroupDetailsSectionProps) {
|
|
8
|
+
const appengineServerGroup = serverGroup as IAppengineServerGroup;
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div className="content-section">
|
|
12
|
+
<div className="content-section-heading">App Engine Details</div>
|
|
13
|
+
<dl className="dl-horizontal dl-narrow">
|
|
14
|
+
<dt>Account</dt>
|
|
15
|
+
<dd>{appengineServerGroup.account}</dd>
|
|
16
|
+
<dt>Region</dt>
|
|
17
|
+
<dd>{appengineServerGroup.region}</dd>
|
|
18
|
+
<dt>Status</dt>
|
|
19
|
+
<dd>{appengineServerGroup.servingStatus || appengineServerGroup.status || 'Unknown'}</dd>
|
|
20
|
+
<dt>Environment</dt>
|
|
21
|
+
<dd>{appengineServerGroup.env || 'Unknown'}</dd>
|
|
22
|
+
<dt>Scaling</dt>
|
|
23
|
+
<dd>{appengineServerGroup.scalingPolicy?.type || 'Unknown'}</dd>
|
|
24
|
+
</dl>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|