@spinnaker/azure 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.
Files changed (215) hide show
  1. package/dist/azure.module.d.ts +3 -1
  2. package/dist/image/image.reader.d.ts +4 -2
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/instance/azureInstanceType.service.d.ts +6 -2
  6. package/dist/instance/details/AzureInstanceDetails.d.ts +67 -0
  7. package/dist/loadBalancer/configure/AzureLoadBalancerChoiceModal.d.ts +10 -5
  8. package/dist/loadBalancer/configure/AzureLoadBalancerModal.d.ts +102 -0
  9. package/dist/loadBalancer/details/azureLoadBalancerDetails.d.ts +26 -0
  10. package/dist/loadBalancer/loadBalancer.transformer.d.ts +45 -2
  11. package/dist/pipeline/stages/AzureAccountRegionClusterSelector.d.ts +32 -0
  12. package/dist/pipeline/stages/bake/azureBakeStage.d.ts +46 -2
  13. package/dist/pipeline/stages/destroyAsg/azureDestroyAsgStage.d.ts +14 -2
  14. package/dist/pipeline/stages/disableAsg/azureDisableAsgStage.d.ts +4 -2
  15. package/dist/pipeline/stages/enableAsg/azureEnableAsgStage.d.ts +4 -2
  16. package/dist/securityGroup/configure/AzureSecurityGroupModal.d.ts +70 -0
  17. package/dist/securityGroup/details/AzureSecurityGroupDetails.d.ts +51 -0
  18. package/dist/securityGroup/securityGroup.reader.d.ts +3 -2
  19. package/dist/securityGroup/securityGroup.transformer.d.ts +3 -2
  20. package/dist/securityGroup/securityGroup.write.service.d.ts +9 -2
  21. package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +88 -2
  22. package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +30 -2
  23. package/dist/serverGroup/configure/wizard/AzureCloneServerGroupModal.d.ts +44 -0
  24. package/dist/serverGroup/configure/wizard/pages/ServerGroupAdvancedSettings.d.ts +8 -0
  25. package/dist/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.d.ts +12 -0
  26. package/dist/serverGroup/configure/wizard/pages/ServerGroupCapacityAndZones.d.ts +11 -0
  27. package/dist/serverGroup/configure/wizard/pages/ServerGroupHealthSettings.d.ts +10 -0
  28. package/dist/serverGroup/configure/wizard/pages/ServerGroupImageSettings.d.ts +12 -0
  29. package/dist/serverGroup/configure/wizard/pages/ServerGroupInstanceType.d.ts +9 -0
  30. package/dist/serverGroup/configure/wizard/pages/ServerGroupLoadBalancers.d.ts +14 -0
  31. package/dist/serverGroup/configure/wizard/pages/ServerGroupNetworkSettings.d.ts +10 -0
  32. package/dist/serverGroup/configure/wizard/pages/ServerGroupSecurityGroups.d.ts +6 -0
  33. package/dist/serverGroup/configure/wizard/pages/ServerGroupTags.d.ts +9 -0
  34. package/dist/serverGroup/configure/wizard/pages/common.d.ts +14 -0
  35. package/dist/serverGroup/configure/wizard/pages/index.d.ts +10 -0
  36. package/dist/serverGroup/details/azureServerGroupDetails.d.ts +13 -0
  37. package/dist/serverGroup/details/rollback/RollbackServerGroupModal.d.ts +6 -4
  38. package/dist/serverGroup/serverGroup.transformer.d.ts +61 -2
  39. package/dist/validation/applicationName.validator.d.ts +6 -2
  40. package/package.json +5 -8
  41. package/src/azure.module.spec.ts +921 -0
  42. package/src/azure.module.ts +56 -68
  43. package/src/image/image.reader.js +4 -15
  44. package/src/image/image.reader.spec.js +4 -7
  45. package/src/instance/azureInstanceType.service.js +8 -16
  46. package/src/instance/azureInstanceType.service.spec.js +5 -13
  47. package/src/instance/details/AzureInstanceDetails.spec.tsx +364 -0
  48. package/src/instance/details/AzureInstanceDetails.tsx +533 -0
  49. package/src/loadBalancer/configure/AzureLoadBalancerChoiceModal.spec.tsx +125 -0
  50. package/src/loadBalancer/configure/AzureLoadBalancerChoiceModal.tsx +46 -26
  51. package/src/loadBalancer/configure/AzureLoadBalancerModal.spec.tsx +658 -0
  52. package/src/loadBalancer/configure/AzureLoadBalancerModal.tsx +960 -0
  53. package/src/loadBalancer/details/azureLoadBalancerDetails.spec.tsx +470 -0
  54. package/src/loadBalancer/details/azureLoadBalancerDetails.tsx +412 -0
  55. package/src/loadBalancer/loadBalancer.transformer.js +83 -93
  56. package/src/pipeline/stages/AzureAccountRegionClusterSelector.tsx +238 -0
  57. package/src/pipeline/stages/bake/azureBakeStage.tsx +723 -0
  58. package/src/pipeline/stages/destroyAsg/azureDestroyAsgStage.tsx +128 -0
  59. package/src/pipeline/stages/disableAsg/azureDisableAsgStage.tsx +92 -0
  60. package/src/pipeline/stages/enableAsg/azureEnableAsgStage.tsx +87 -0
  61. package/src/routerConsumers.spec.tsx +69 -0
  62. package/src/securityGroup/configure/AzureSecurityGroupModal.spec.tsx +558 -0
  63. package/src/securityGroup/configure/AzureSecurityGroupModal.tsx +782 -0
  64. package/src/securityGroup/details/AzureSecurityGroupDetails.spec.tsx +291 -0
  65. package/src/securityGroup/details/AzureSecurityGroupDetails.tsx +354 -0
  66. package/src/securityGroup/securityGroup.reader.js +3 -13
  67. package/src/securityGroup/securityGroup.transformer.js +3 -13
  68. package/src/securityGroup/securityGroup.write.service.spec.ts +105 -0
  69. package/src/securityGroup/securityGroup.write.service.ts +73 -0
  70. package/src/serverGroup/configure/serverGroupCommandBuilder.service.js +167 -166
  71. package/src/serverGroup/configure/serverGroupCommandBuilder.service.spec.js +63 -0
  72. package/src/serverGroup/configure/serverGroupConfiguration.service.js +325 -309
  73. package/src/serverGroup/configure/serverGroupConfiguration.service.spec.js +57 -53
  74. package/src/serverGroup/configure/wizard/AzureCloneServerGroupModal.spec.tsx +758 -0
  75. package/src/serverGroup/configure/wizard/AzureCloneServerGroupModal.tsx +349 -0
  76. package/src/serverGroup/configure/wizard/pages/ServerGroupAdvancedSettings.tsx +208 -0
  77. package/src/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.tsx +122 -0
  78. package/src/serverGroup/configure/wizard/pages/ServerGroupCapacityAndZones.tsx +80 -0
  79. package/src/serverGroup/configure/wizard/pages/ServerGroupHealthSettings.tsx +97 -0
  80. package/src/serverGroup/configure/wizard/pages/ServerGroupImageSettings.tsx +151 -0
  81. package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.tsx +41 -0
  82. package/src/serverGroup/configure/wizard/pages/ServerGroupLoadBalancers.tsx +214 -0
  83. package/src/serverGroup/configure/wizard/pages/ServerGroupNetworkSettings.tsx +119 -0
  84. package/src/serverGroup/configure/wizard/pages/ServerGroupSecurityGroups.tsx +54 -0
  85. package/src/serverGroup/configure/wizard/pages/ServerGroupTags.tsx +40 -0
  86. package/src/serverGroup/configure/wizard/pages/common.tsx +72 -0
  87. package/src/serverGroup/configure/wizard/pages/index.ts +10 -0
  88. package/src/serverGroup/details/azureServerGroupDetails.spec.tsx +263 -0
  89. package/src/serverGroup/details/azureServerGroupDetails.tsx +318 -0
  90. package/src/serverGroup/details/rollback/RollbackServerGroupModal.tsx +24 -30
  91. package/src/serverGroup/serverGroup.transformer.js +11 -19
  92. package/src/serverGroup/serverGroup.transformer.spec.js +2 -6
  93. package/src/validation/applicationName.validator.js +14 -29
  94. package/dist/instance/details/instance.details.controller.d.ts +0 -2
  95. package/dist/loadBalancer/configure/createLoadBalancer.controller.d.ts +0 -2
  96. package/dist/loadBalancer/details/loadBalancerDetail.controller.d.ts +0 -2
  97. package/dist/pipeline/stages/bake/bakeExecutionDetails.controller.d.ts +0 -2
  98. package/dist/securityGroup/clone/cloneSecurityGroup.controller.d.ts +0 -2
  99. package/dist/securityGroup/configure/CreateSecurityGroupCtrl.d.ts +0 -2
  100. package/dist/securityGroup/configure/EditSecurityGroupCtrl.d.ts +0 -2
  101. package/dist/securityGroup/details/securityGroupDetail.controller.d.ts +0 -2
  102. package/dist/serverGroup/configure/serverGroup.configure.azure.module.d.ts +0 -2
  103. package/dist/serverGroup/configure/wizard/CloneServerGroup.azure.controller.d.ts +0 -2
  104. package/dist/serverGroup/configure/wizard/ServerGroupInstanceArchetype.controller.d.ts +0 -2
  105. package/dist/serverGroup/configure/wizard/ServerGroupInstanceType.controller.d.ts +0 -2
  106. package/dist/serverGroup/configure/wizard/advancedSettings/ServerGroupAdvancedSettings.controller.d.ts +0 -2
  107. package/dist/serverGroup/configure/wizard/advancedSettings/advancedSettingsSelector.directive.d.ts +0 -2
  108. package/dist/serverGroup/configure/wizard/basicSettings/ServerGroupBasicSettings.controller.d.ts +0 -2
  109. package/dist/serverGroup/configure/wizard/basicSettings/image.regional.filter.d.ts +0 -2
  110. package/dist/serverGroup/configure/wizard/capacity/capacitySelector.directive.d.ts +0 -2
  111. package/dist/serverGroup/configure/wizard/healthSettings/ServerGroupHealthSettings.controller.d.ts +0 -2
  112. package/dist/serverGroup/configure/wizard/healthSettings/healthSettingsSelector.directive.d.ts +0 -2
  113. package/dist/serverGroup/configure/wizard/image/ServerGroupImageSettings.controller.d.ts +0 -2
  114. package/dist/serverGroup/configure/wizard/image/imageSettingsSelector.directive.d.ts +0 -2
  115. package/dist/serverGroup/configure/wizard/loadBalancers/ServerGroupLoadBalancers.controller.d.ts +0 -2
  116. package/dist/serverGroup/configure/wizard/loadBalancers/serverGroupLoadBalancersSelector.directive.d.ts +0 -2
  117. package/dist/serverGroup/configure/wizard/networkSettings/ServerGroupNetworkSettings.controller.d.ts +0 -2
  118. package/dist/serverGroup/configure/wizard/networkSettings/ServerGroupNetworkSettingsSelector.directive.d.ts +0 -2
  119. package/dist/serverGroup/configure/wizard/securityGroup/ServerGroupSecurityGroups.controller.d.ts +0 -2
  120. package/dist/serverGroup/configure/wizard/securityGroup/serverGroupSecurityGroupsSelector.directive.d.ts +0 -2
  121. package/dist/serverGroup/configure/wizard/tags/tagsSelector.directive.d.ts +0 -2
  122. package/dist/serverGroup/configure/wizard/zones/zoneSelector.directive.d.ts +0 -2
  123. package/dist/serverGroup/details/serverGroup.details.module.d.ts +0 -2
  124. package/dist/serverGroup/details/serverGroupDetails.azure.controller.d.ts +0 -2
  125. package/src/instance/details/instance.details.controller.js +0 -371
  126. package/src/instance/details/instance.details.controller.spec.js +0 -129
  127. package/src/instance/details/instanceDetails.html +0 -43
  128. package/src/loadBalancer/configure/advancedSettings.html +0 -95
  129. package/src/loadBalancer/configure/createLoadBalancer.controller.js +0 -275
  130. package/src/loadBalancer/configure/createLoadBalancer.controller.spec.js +0 -39
  131. package/src/loadBalancer/configure/createLoadBalancer.html +0 -25
  132. package/src/loadBalancer/configure/createLoadBalancerProperties.html +0 -128
  133. package/src/loadBalancer/configure/editLoadBalancer.html +0 -26
  134. package/src/loadBalancer/configure/healthCheck.html +0 -74
  135. package/src/loadBalancer/configure/listeners.html +0 -50
  136. package/src/loadBalancer/details/loadBalancerDetail.controller.js +0 -181
  137. package/src/loadBalancer/details/loadBalancerDetail.controller.spec.js +0 -39
  138. package/src/loadBalancer/details/loadBalancerDetail.html +0 -128
  139. package/src/pipeline/stages/bake/azureBakeStage.js +0 -276
  140. package/src/pipeline/stages/bake/bakeExecutionDetails.controller.js +0 -40
  141. package/src/pipeline/stages/bake/bakeExecutionDetails.html +0 -50
  142. package/src/pipeline/stages/bake/bakeStage.html +0 -187
  143. package/src/pipeline/stages/destroyAsg/azureDestroyAsgStage.js +0 -73
  144. package/src/pipeline/stages/destroyAsg/destroyAsgStage.html +0 -9
  145. package/src/pipeline/stages/destroyAsg/destroyAsgStepLabel.html +0 -1
  146. package/src/pipeline/stages/disableAsg/azureDisableAsgStage.js +0 -65
  147. package/src/pipeline/stages/disableAsg/disableAsgStage.html +0 -11
  148. package/src/pipeline/stages/disableAsg/disableAsgStepLabel.html +0 -1
  149. package/src/pipeline/stages/enableAsg/azureEnableAsgStage.js +0 -70
  150. package/src/pipeline/stages/enableAsg/enableAsgStage.html +0 -11
  151. package/src/pipeline/stages/enableAsg/enableAsgStepLabel.html +0 -1
  152. package/src/securityGroup/clone/cloneSecurityGroup.controller.js +0 -162
  153. package/src/securityGroup/clone/cloneSecurityGroup.html +0 -8
  154. package/src/securityGroup/configure/CreateSecurityGroup.controller.spec.js +0 -78
  155. package/src/securityGroup/configure/CreateSecurityGroupCtrl.js +0 -265
  156. package/src/securityGroup/configure/EditSecurityGroupCtrl.js +0 -222
  157. package/src/securityGroup/configure/configSecurityGroup.mixin.controller.js +0 -262
  158. package/src/securityGroup/configure/createSecurityGroup.html +0 -20
  159. package/src/securityGroup/configure/createSecurityGroupIngress.html +0 -75
  160. package/src/securityGroup/configure/createSecurityGroupProperties.html +0 -88
  161. package/src/securityGroup/configure/editSecurityGroup.html +0 -19
  162. package/src/securityGroup/details/securityGroupDetail.controller.js +0 -142
  163. package/src/securityGroup/details/securityGroupDetail.html +0 -78
  164. package/src/securityGroup/securityGroup.write.service.js +0 -57
  165. package/src/serverGroup/configure/serverGroup.configure.azure.module.js +0 -47
  166. package/src/serverGroup/configure/wizard/CloneServerGroup.azure.controller.js +0 -247
  167. package/src/serverGroup/configure/wizard/ServerGroupInstanceArchetype.controller.js +0 -35
  168. package/src/serverGroup/configure/wizard/ServerGroupInstanceType.controller.js +0 -15
  169. package/src/serverGroup/configure/wizard/advancedSettings/ServerGroupAdvancedSettings.controller.js +0 -25
  170. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettings.html +0 -5
  171. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettingsSelector.directive.html +0 -138
  172. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettingsSelector.directive.js +0 -43
  173. package/src/serverGroup/configure/wizard/basicSettings/ServerGroupBasicSettings.controller.js +0 -71
  174. package/src/serverGroup/configure/wizard/basicSettings/basicSettings.html +0 -131
  175. package/src/serverGroup/configure/wizard/basicSettings/image.regional.filter.js +0 -15
  176. package/src/serverGroup/configure/wizard/basicSettings/image.regional.filter.spec.js +0 -42
  177. package/src/serverGroup/configure/wizard/capacity/capacity.html +0 -5
  178. package/src/serverGroup/configure/wizard/capacity/capacitySelector.directive.html +0 -20
  179. package/src/serverGroup/configure/wizard/capacity/capacitySelector.directive.js +0 -21
  180. package/src/serverGroup/configure/wizard/capacity/zones.html +0 -5
  181. package/src/serverGroup/configure/wizard/healthSettings/ServerGroupHealthSettings.controller.js +0 -38
  182. package/src/serverGroup/configure/wizard/healthSettings/healthSettings.html +0 -5
  183. package/src/serverGroup/configure/wizard/healthSettings/healthSettingsSelector.directive.html +0 -32
  184. package/src/serverGroup/configure/wizard/healthSettings/healthSettingsSelector.directive.js +0 -22
  185. package/src/serverGroup/configure/wizard/image/ServerGroupImageSettings.controller.js +0 -34
  186. package/src/serverGroup/configure/wizard/image/imageSettings.html +0 -5
  187. package/src/serverGroup/configure/wizard/image/imageSettingsSelector.directive.html +0 -33
  188. package/src/serverGroup/configure/wizard/image/imageSettingsSelector.directive.js +0 -22
  189. package/src/serverGroup/configure/wizard/instanceArchetype.html +0 -33
  190. package/src/serverGroup/configure/wizard/instanceType/instanceType.html +0 -10
  191. package/src/serverGroup/configure/wizard/instanceType.html +0 -33
  192. package/src/serverGroup/configure/wizard/loadBalancers/ServerGroupLoadBalancers.controller.js +0 -137
  193. package/src/serverGroup/configure/wizard/loadBalancers/loadBalancers.html +0 -3
  194. package/src/serverGroup/configure/wizard/loadBalancers/serverGroupLoadBalancersSelector.directive.html +0 -41
  195. package/src/serverGroup/configure/wizard/loadBalancers/serverGroupLoadBalancersSelector.directive.js +0 -22
  196. package/src/serverGroup/configure/wizard/networkSettings/ServerGroupNetworkSettings.controller.js +0 -44
  197. package/src/serverGroup/configure/wizard/networkSettings/ServerGroupNetworkSettingsSelector.directive.html +0 -54
  198. package/src/serverGroup/configure/wizard/networkSettings/ServerGroupNetworkSettingsSelector.directive.js +0 -19
  199. package/src/serverGroup/configure/wizard/networkSettings/networkSettings.html +0 -3
  200. package/src/serverGroup/configure/wizard/securityGroup/ServerGroupSecurityGroups.controller.js +0 -28
  201. package/src/serverGroup/configure/wizard/securityGroup/securityGroups.html +0 -3
  202. package/src/serverGroup/configure/wizard/securityGroup/serverGroupSecurityGroupsSelector.directive.html +0 -40
  203. package/src/serverGroup/configure/wizard/securityGroup/serverGroupSecurityGroupsSelector.directive.js +0 -38
  204. package/src/serverGroup/configure/wizard/serverGroupWizard.html +0 -61
  205. package/src/serverGroup/configure/wizard/tags/tags.html +0 -5
  206. package/src/serverGroup/configure/wizard/tags/tagsSelector.directive.html +0 -16
  207. package/src/serverGroup/configure/wizard/tags/tagsSelector.directive.js +0 -30
  208. package/src/serverGroup/configure/wizard/templateSelection.html +0 -9
  209. package/src/serverGroup/configure/wizard/zones/zoneSelector.directive.html +0 -21
  210. package/src/serverGroup/configure/wizard/zones/zoneSelector.directive.js +0 -28
  211. package/src/serverGroup/details/serverGroup.details.module.js +0 -11
  212. package/src/serverGroup/details/serverGroupDetails.azure.controller.js +0 -260
  213. package/src/serverGroup/details/serverGroupDetails.html +0 -98
  214. package/src/subnet/subnetSelectField.directive.html +0 -28
  215. package/src/subnet/subnetSelectField.directive.js +0 -35
@@ -0,0 +1,119 @@
1
+ import React from 'react';
2
+
3
+ import { AzureWizardPage } from './common';
4
+
5
+ function getVnetSelectValue(vnet: any): string {
6
+ return `${vnet.name}|${vnet.resourceGroup || ''}`;
7
+ }
8
+
9
+ function getVnetSelectLabel(vnet: any): string {
10
+ return vnet.resourceGroup ? `${vnet.name} (${vnet.resourceGroup})` : vnet.name;
11
+ }
12
+
13
+ export class ServerGroupNetworkSettings extends AzureWizardPage {
14
+ public validate(values: any): { [key: string]: any } {
15
+ const errors: { [key: string]: any } = {};
16
+
17
+ if (!values.viewState?.networkSettingsConfigured) {
18
+ return errors;
19
+ }
20
+
21
+ if (!values.selectedVnet) {
22
+ errors.selectedVnet = 'Virtual network required.';
23
+ }
24
+
25
+ if (!values.subnet) {
26
+ errors.selectedSubnet = 'Subnet required.';
27
+ }
28
+
29
+ return errors;
30
+ }
31
+
32
+ private selectedVnetChanged = (selected: string) => {
33
+ const vnets = this.props.formik.values.allVnets || this.props.formik.values.backingData?.filtered?.vnets || [];
34
+ const vnet = vnets.find((candidate: any) => getVnetSelectValue(candidate) === selected);
35
+ const selectedVnetSubnets = (vnet?.subnets || [])
36
+ .filter((subnet: any) =>
37
+ (subnet.devices || []).every((device: any) => !device || device.type !== 'applicationGateways'),
38
+ )
39
+ .map((subnet: any) => subnet.name || subnet);
40
+ this.props.formik.values.selectedVnet = vnet || null;
41
+ this.props.formik.values.vnet = vnet?.name || null;
42
+ this.props.formik.values.vnetResourceGroup = vnet?.resourceGroup || null;
43
+ this.props.formik.values.selectedSubnet = null;
44
+ this.props.formik.values.subnet = null;
45
+ this.props.formik.values.selectedVnetSubnets = selectedVnetSubnets;
46
+ this.props.formik.setFieldValue('selectedVnet', vnet || null);
47
+ this.props.formik.setFieldValue('vnet', vnet?.name || null);
48
+ this.props.formik.setFieldValue('vnetResourceGroup', vnet?.resourceGroup || null);
49
+ this.props.formik.setFieldValue('selectedSubnet', null);
50
+ this.props.formik.setFieldValue('subnet', null);
51
+ this.props.formik.setFieldValue('selectedVnetSubnets', selectedVnetSubnets);
52
+ };
53
+
54
+ private selectedSubnetChanged = (subnet: string) => {
55
+ this.props.formik.values.selectedSubnet = subnet || null;
56
+ this.props.formik.values.subnet = subnet || null;
57
+ this.props.formik.setFieldValue('selectedSubnet', subnet || null);
58
+ this.props.formik.setFieldValue('subnet', subnet || null);
59
+ };
60
+
61
+ public render() {
62
+ const { values } = this.props.formik;
63
+ const vnets = values.allVnets || values.backingData?.filtered?.vnets || [];
64
+ const subnets =
65
+ values.selectedVnetSubnets || (values.selectedVnet?.subnets || []).map((subnet: any) => subnet.name || subnet);
66
+ const showVnetSelect = values.loadBalancerType === 'Azure Load Balancer' || !values.loadBalancerType;
67
+
68
+ if (!values.viewState?.networkSettingsConfigured) {
69
+ return <h5 className="text-center">Please select an account, a region and a load balancer first.</h5>;
70
+ }
71
+
72
+ return (
73
+ <div className="container-fluid form-horizontal">
74
+ {showVnetSelect && (
75
+ <div className="form-group">
76
+ <div className="col-md-3 sm-label-right">Virtual Network</div>
77
+ <div className="col-md-7">
78
+ <select
79
+ className="form-control input-sm"
80
+ onChange={(event) => this.selectedVnetChanged(event.target.value)}
81
+ value={values.selectedVnet ? getVnetSelectValue(values.selectedVnet) : ''}
82
+ >
83
+ <option value="">Select...</option>
84
+ {vnets.map((vnet: any) => (
85
+ <option key={getVnetSelectValue(vnet)} value={getVnetSelectValue(vnet)}>
86
+ {getVnetSelectLabel(vnet)}
87
+ </option>
88
+ ))}
89
+ </select>
90
+ </div>
91
+ </div>
92
+ )}
93
+ <div className="form-group">
94
+ <div className="col-md-3 sm-label-right">Subnets</div>
95
+ <div className="col-md-7">
96
+ <select
97
+ className="form-control input-sm"
98
+ onChange={(event) => this.selectedSubnetChanged(event.target.value)}
99
+ value={values.subnet || ''}
100
+ >
101
+ <option value="">Select...</option>
102
+ {subnets.map((subnet: string) => (
103
+ <option key={subnet} value={subnet}>
104
+ {subnet}
105
+ </option>
106
+ ))}
107
+ </select>
108
+ </div>
109
+ </div>
110
+ {!values.viewState?.hideClusterNamePreview && (
111
+ <div className="well-compact text-center">
112
+ <p>Your server group will be using a subnet in virtual network:</p>
113
+ <strong>{values.selectedVnet?.name || 'Virtual network was not selected'}</strong>
114
+ </div>
115
+ )}
116
+ </div>
117
+ );
118
+ }
119
+ }
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+
3
+ import { AzureWizardPage } from './common';
4
+
5
+ export class ServerGroupSecurityGroups extends AzureWizardPage {
6
+ private securityGroupChanged = (securityGroupId: string) => {
7
+ const securityGroups = this.props.formik.values.backingData?.filtered?.securityGroups || [];
8
+ const selectedSecurityGroup = securityGroups.find(
9
+ (securityGroup: any) => (securityGroup.id || securityGroup.name) === securityGroupId,
10
+ );
11
+ this.props.formik.values.selectedSecurityGroup = selectedSecurityGroup || null;
12
+ this.props.formik.values.securityGroupName = securityGroupId || null;
13
+ this.props.formik.setFieldValue('selectedSecurityGroup', selectedSecurityGroup || null);
14
+ this.props.formik.setFieldValue('securityGroupName', securityGroupId || null);
15
+ };
16
+
17
+ public render() {
18
+ const { values } = this.props.formik;
19
+ const securityGroups = values.backingData?.filtered?.securityGroups || [];
20
+ if (!values.viewState?.securityGroupsConfigured) {
21
+ return <h5 className="text-center">Please select an account and region.</h5>;
22
+ }
23
+
24
+ return (
25
+ <div className="container-fluid form-horizontal">
26
+ <div className="form-group">
27
+ <div className="col-md-3 sm-label-right">Firewall</div>
28
+ <div className="col-md-7">
29
+ <select
30
+ className="form-control input-sm"
31
+ onChange={(event) => this.securityGroupChanged(event.target.value)}
32
+ value={values.selectedSecurityGroup?.id || values.securityGroupName || ''}
33
+ >
34
+ <option value="">Select...</option>
35
+ {securityGroups.map((securityGroup: any) => {
36
+ const securityGroupId = securityGroup.id || securityGroup.name || securityGroup;
37
+ return (
38
+ <option key={securityGroupId} value={securityGroupId}>
39
+ {securityGroupId}
40
+ </option>
41
+ );
42
+ })}
43
+ </select>
44
+ </div>
45
+ </div>
46
+ <div className="form-group small" style={{ marginTop: '20px' }}>
47
+ <div className="col-md-9 col-md-offset-3">
48
+ <p>If you're not finding a firewall that was recently added, refresh the list and reopen this dialog.</p>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ );
53
+ }
54
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+
3
+ import { MapEditor } from '@spinnaker/core';
4
+
5
+ import { AzureWizardPage } from './common';
6
+ import Utility from '../../../../utility';
7
+
8
+ export class ServerGroupTags extends AzureWizardPage {
9
+ public validate(values: any): { [key: string]: any } {
10
+ const tagResult = Utility.checkTags(values.instanceTags);
11
+ return tagResult.isValid ? {} : { instanceTags: tagResult.errorMessage };
12
+ }
13
+
14
+ private tagsChanged = (instanceTags: any) => {
15
+ this.props.formik.values.instanceTags = instanceTags;
16
+ this.props.formik.setFieldValue('instanceTags', instanceTags);
17
+ };
18
+
19
+ public render() {
20
+ const tagResult = Utility.checkTags(this.props.formik.values.instanceTags);
21
+ return (
22
+ <div className="container-fluid form-horizontal">
23
+ {!tagResult.isValid && <div className="col-md-12 text-danger">{tagResult.errorMessage}</div>}
24
+ <div className="form-group">
25
+ <div className="col-md-4 sm-label-left">
26
+ <b>Custom Tags</b>
27
+ </div>
28
+ <div className="col-md-12">
29
+ <MapEditor
30
+ addButtonLabel="Add New Tags"
31
+ allowEmpty={true}
32
+ model={this.props.formik.values.instanceTags || {}}
33
+ onChange={this.tagsChanged}
34
+ />
35
+ </div>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
40
+ }
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+
3
+ import type { IWizardPageComponent } from '@spinnaker/core';
4
+
5
+ export interface IAzureWizardPageProps {
6
+ formik: any;
7
+ app?: any;
8
+ }
9
+
10
+ export abstract class AzureWizardPage<P extends IAzureWizardPageProps = IAzureWizardPageProps>
11
+ extends React.Component<P>
12
+ implements IWizardPageComponent<any> {
13
+ public validate(_values: any): { [key: string]: any } {
14
+ return {};
15
+ }
16
+
17
+ protected setField = (field: string, value: any) => {
18
+ const path = field.split('.');
19
+ const leaf = path.pop();
20
+ const target = path.reduce((acc: any, key) => {
21
+ acc[key] = acc[key] || {};
22
+ return acc[key];
23
+ }, this.props.formik.values);
24
+ target[leaf] = value;
25
+ this.props.formik.setFieldValue(field, value);
26
+ };
27
+
28
+ protected textField(label: string, field: string, type = 'text') {
29
+ const value = this.props.formik.values[field] ?? '';
30
+ return (
31
+ <div className="form-group">
32
+ <div className="col-md-3 sm-label-right">{label}</div>
33
+ <div className="col-md-7">
34
+ <input
35
+ className="form-control input-sm"
36
+ name={field}
37
+ onChange={(event) => this.setField(field, event.target.value)}
38
+ type={type}
39
+ value={value}
40
+ />
41
+ </div>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ protected selectField(label: string, field: string, options: any[], labeler: (option: any) => string = String) {
47
+ const value = this.props.formik.values[field] ?? '';
48
+ return (
49
+ <div className="form-group">
50
+ <div className="col-md-3 sm-label-right">{label}</div>
51
+ <div className="col-md-7">
52
+ <select
53
+ className="form-control input-sm"
54
+ name={field}
55
+ onChange={(event) => this.setField(field, event.target.value)}
56
+ value={value}
57
+ >
58
+ <option value="">Select...</option>
59
+ {(options || []).map((option) => {
60
+ const optionValue = typeof option === 'string' ? option : option.name;
61
+ return (
62
+ <option key={optionValue} value={optionValue}>
63
+ {labeler(option)}
64
+ </option>
65
+ );
66
+ })}
67
+ </select>
68
+ </div>
69
+ </div>
70
+ );
71
+ }
72
+ }
@@ -0,0 +1,10 @@
1
+ export * from './ServerGroupAdvancedSettings';
2
+ export * from './ServerGroupBasicSettings';
3
+ export * from './ServerGroupCapacityAndZones';
4
+ export * from './ServerGroupHealthSettings';
5
+ export * from './ServerGroupImageSettings';
6
+ export * from './ServerGroupInstanceType';
7
+ export * from './ServerGroupLoadBalancers';
8
+ export * from './ServerGroupNetworkSettings';
9
+ export * from './ServerGroupSecurityGroups';
10
+ export * from './ServerGroupTags';
@@ -0,0 +1,263 @@
1
+ import { mount } from 'enzyme';
2
+ import React from 'react';
3
+
4
+ import {
5
+ CloudProviderRegistry,
6
+ ConfirmationModalService,
7
+ DeckRuntimeContext,
8
+ nativePromiseService,
9
+ ServerGroupReader,
10
+ ServerGroupWarningMessageService,
11
+ } from '@spinnaker/core';
12
+
13
+ import { AzureImageReader } from '../../image/image.reader';
14
+ import { registerAzureProvider } from '../../azure.module';
15
+ import { AzureServerGroupCommandBuilder } from '../configure/serverGroupCommandBuilder.service';
16
+ import { AzureCloneServerGroupModal } from '../configure/wizard/AzureCloneServerGroupModal';
17
+ import {
18
+ AzureServerGroupActions as RoutedAzureServerGroupActions,
19
+ AzureServerGroupActionsComponent as AzureServerGroupActions,
20
+ azureServerGroupDetailsGetter,
21
+ azureServerGroupDetailsSections,
22
+ } from './azureServerGroupDetails';
23
+
24
+ describe('Azure server group details', () => {
25
+ let runtimeServices: any;
26
+ const stateService = { go: jasmine.createSpy('go'), includes: jasmine.createSpy('includes').and.returnValue(true) };
27
+ const routerProps = { router: {} as any, stateParams: {}, stateService: stateService as any };
28
+ const serverGroupParams = {
29
+ name: 'azure-v001',
30
+ accountId: 'test-account',
31
+ region: 'westus',
32
+ };
33
+
34
+ function buildApp(overrides: any = {}): any {
35
+ return {
36
+ name: 'fnord',
37
+ serverGroups: { data: [], refresh: jasmine.createSpy('refresh') },
38
+ loadBalancers: { data: [] },
39
+ securityGroups: { data: [] },
40
+ clusters: [],
41
+ ready: () => Promise.resolve(),
42
+ ...overrides,
43
+ };
44
+ }
45
+
46
+ function subscribeToGetter(props: any, autoClose = jasmine.createSpy('autoClose')): Promise<any> {
47
+ return new Promise((resolve, reject) => {
48
+ azureServerGroupDetailsGetter(props, autoClose).subscribe({
49
+ next: resolve,
50
+ error: reject,
51
+ });
52
+ });
53
+ }
54
+
55
+ function mountActions(app: any, serverGroup: any) {
56
+ runtimeServices = {
57
+ serverGroupCommandBuilder: new AzureServerGroupCommandBuilder(nativePromiseService),
58
+ serverGroupWriter: {
59
+ destroyServerGroup: jasmine.createSpy('destroyServerGroup'),
60
+ disableServerGroup: jasmine.createSpy('disableServerGroup'),
61
+ enableServerGroup: jasmine.createSpy('enableServerGroup'),
62
+ },
63
+ };
64
+ return mount(
65
+ <DeckRuntimeContext.Provider value={{ services: runtimeServices }}>
66
+ <AzureServerGroupActions {...routerProps} app={app} serverGroup={serverGroup} />
67
+ </DeckRuntimeContext.Provider>,
68
+ );
69
+ }
70
+
71
+ beforeEach(() => {
72
+ spyOn(ServerGroupReader, 'getServerGroup').and.returnValue(
73
+ Promise.resolve({
74
+ name: 'azure-v001',
75
+ account: 'test-account',
76
+ region: 'westus',
77
+ image: { imageName: 'ubuntu' },
78
+ launchConfig: { securityGroups: ['sg-1'] },
79
+ }) as any,
80
+ );
81
+ });
82
+
83
+ it('finds summaries in application server groups, fetches details, and merges summary fields', async () => {
84
+ const summary = {
85
+ name: 'azure-v001',
86
+ account: 'test-account',
87
+ region: 'westus',
88
+ type: 'azure',
89
+ cluster: 'azure',
90
+ createdTime: 123,
91
+ instanceCounts: { total: 1, up: 1 },
92
+ instances: [{ id: 'i-1' }],
93
+ };
94
+ const app = buildApp({ serverGroups: { data: [summary] } });
95
+
96
+ const result = await subscribeToGetter({ app, serverGroup: serverGroupParams });
97
+
98
+ expect(ServerGroupReader.getServerGroup).toHaveBeenCalledWith('fnord', 'test-account', 'westus', 'azure-v001');
99
+ expect(result).toEqual(jasmine.objectContaining(summary));
100
+ expect(result.account).toBe('test-account');
101
+ expect(result.image.imageName).toBe('ubuntu');
102
+ });
103
+
104
+ it('falls back to summaries on matching load balancers', async () => {
105
+ const loadBalancerSummary = {
106
+ name: 'azure-v001',
107
+ account: 'test-account',
108
+ region: 'westus',
109
+ cluster: 'azure',
110
+ loadBalancers: ['lb-1'],
111
+ };
112
+ const app = buildApp({
113
+ loadBalancers: {
114
+ data: [
115
+ { account: 'other-account', region: 'westus', serverGroups: [{ name: 'azure-v001' }] },
116
+ { account: 'test-account', region: 'westus', serverGroups: [loadBalancerSummary] },
117
+ ],
118
+ },
119
+ });
120
+
121
+ const result = await subscribeToGetter({ app, serverGroup: serverGroupParams });
122
+
123
+ expect(result).toEqual(jasmine.objectContaining(loadBalancerSummary));
124
+ });
125
+
126
+ it('auto-closes when the summary is missing', async () => {
127
+ const autoClose = jasmine.createSpy('autoClose');
128
+ const app = buildApp();
129
+
130
+ await new Promise<void>((resolve) => {
131
+ azureServerGroupDetailsGetter({ app, serverGroup: serverGroupParams }, autoClose).subscribe({
132
+ next: () => fail('should not emit a server group'),
133
+ complete: resolve,
134
+ });
135
+ });
136
+
137
+ expect(autoClose).toHaveBeenCalled();
138
+ expect(ServerGroupReader.getServerGroup).not.toHaveBeenCalled();
139
+ });
140
+
141
+ it('auto-closes when server group details are missing', async () => {
142
+ (ServerGroupReader.getServerGroup as jasmine.Spy).and.returnValue(Promise.resolve(null) as any);
143
+ const autoClose = jasmine.createSpy('autoClose');
144
+ const app = buildApp({ serverGroups: { data: [{ ...serverGroupParams, account: 'test-account' }] } });
145
+
146
+ await new Promise<void>((resolve) => {
147
+ azureServerGroupDetailsGetter({ app, serverGroup: serverGroupParams }, autoClose).subscribe({
148
+ next: () => fail('should not emit a server group'),
149
+ complete: resolve,
150
+ });
151
+ });
152
+
153
+ expect(autoClose).toHaveBeenCalled();
154
+ });
155
+
156
+ it('registers React server group details', () => {
157
+ registerAzureProvider();
158
+
159
+ expect(CloudProviderRegistry.getValue('azure', 'serverGroup.detailsGetter')).toBe(azureServerGroupDetailsGetter);
160
+ expect(CloudProviderRegistry.getValue('azure', 'serverGroup.detailsActions').render).toBe(
161
+ (RoutedAzureServerGroupActions as any).render,
162
+ );
163
+ expect(CloudProviderRegistry.getValue('azure', 'serverGroup.detailsSections')).toEqual(
164
+ azureServerGroupDetailsSections,
165
+ );
166
+ });
167
+
168
+ it('wires destroy, disable, and enable actions to confirmation modals', () => {
169
+ const app = buildApp();
170
+ const serverGroup = { name: 'azure-v001', account: 'test-account', region: 'westus', isDisabled: false };
171
+ spyOn(ConfirmationModalService, 'confirm');
172
+ spyOn(ServerGroupWarningMessageService, 'addDestroyWarningMessage');
173
+ spyOn(ServerGroupWarningMessageService, 'addDisableWarningMessage');
174
+
175
+ const wrapper = mountActions(app, serverGroup);
176
+ wrapper
177
+ .find('a')
178
+ .filterWhere((node) => node.text() === 'Destroy')
179
+ .simulate('click');
180
+ wrapper
181
+ .find('a')
182
+ .filterWhere((node) => node.text() === 'Disable')
183
+ .simulate('click');
184
+ wrapper
185
+ .find('a')
186
+ .filterWhere((node) => node.text() === 'Enable')
187
+ .simulate('click');
188
+
189
+ expect(ServerGroupWarningMessageService.addDestroyWarningMessage).toHaveBeenCalled();
190
+ expect(ServerGroupWarningMessageService.addDisableWarningMessage).toHaveBeenCalled();
191
+ expect(
192
+ (ConfirmationModalService.confirm as jasmine.Spy).calls.allArgs().map(([params]) => params.buttonText),
193
+ ).toEqual(['Destroy azure-v001', 'Disable azure-v001', 'Enable azure-v001']);
194
+ (ConfirmationModalService.confirm as jasmine.Spy).calls.first().args[0].taskMonitorConfig.onTaskComplete();
195
+ expect(stateService.go).toHaveBeenCalledWith('^');
196
+ });
197
+
198
+ it('builds a clone command before opening the clone wizard', async () => {
199
+ registerAzureProvider();
200
+ const app = buildApp();
201
+ const serverGroup = { name: 'azure-v001', account: 'test-account', region: 'westus' };
202
+ const command = { viewState: { mode: 'clone' }, source: { serverGroupName: 'azure-v001' } };
203
+ spyOn(AzureServerGroupCommandBuilder.prototype as any, 'buildServerGroupCommandFromExisting').and.returnValue(
204
+ Promise.resolve(command),
205
+ );
206
+ spyOn(AzureCloneServerGroupModal, 'show').and.returnValue(Promise.resolve());
207
+
208
+ const wrapper = mountActions(app, serverGroup);
209
+ wrapper
210
+ .find('a')
211
+ .filterWhere((node) => node.text() === 'Clone')
212
+ .simulate('click');
213
+ await Promise.resolve();
214
+
215
+ expect(AzureServerGroupCommandBuilder.prototype.buildServerGroupCommandFromExisting).toHaveBeenCalledWith(
216
+ app,
217
+ serverGroup,
218
+ );
219
+ expect(AzureCloneServerGroupModal.show).toHaveBeenCalledWith(
220
+ {
221
+ application: app,
222
+ command,
223
+ title: 'Clone azure-v001',
224
+ },
225
+ runtimeServices,
226
+ );
227
+ });
228
+
229
+ it('opens the clone wizard with image data seeded on the built command', async () => {
230
+ registerAzureProvider();
231
+ const images = [{ imageName: 'ubuntu-west', amis: { westus: ['ami-west'] } }];
232
+ const app = buildApp();
233
+ const serverGroup = {
234
+ name: 'azure-v001',
235
+ account: 'test-account',
236
+ region: 'westus',
237
+ image: { imageName: 'ubuntu-west' },
238
+ loadBalancers: [],
239
+ selectedVnetSubnets: [],
240
+ selectedVnet: { name: 'vnet-a' },
241
+ securityGroups: [],
242
+ zones: [],
243
+ dataDisks: [],
244
+ sku: { name: 'Standard_DS1_v2', capacity: 1 },
245
+ capacity: { min: 1, max: 1, desired: 1 },
246
+ };
247
+ spyOn(AzureImageReader.prototype, 'findImages').and.returnValue(Promise.resolve(images));
248
+ spyOn(AzureCloneServerGroupModal, 'show').and.returnValue(Promise.resolve());
249
+
250
+ const wrapper = mountActions(app, serverGroup);
251
+ wrapper
252
+ .find('a')
253
+ .filterWhere((node) => node.text() === 'Clone')
254
+ .simulate('click');
255
+ await Promise.resolve();
256
+ await Promise.resolve();
257
+
258
+ const props = (AzureCloneServerGroupModal.show as jasmine.Spy).calls.mostRecent().args[0];
259
+ expect(props.command.images).toBe(images);
260
+ expect(props.command.imageName).toBe('ubuntu-west');
261
+ expect(props.command.selectedImage).toBe(images[0]);
262
+ });
263
+ });