Skip to content

Commit 332a5aa

Browse files
committed
ui: surface OVN as a guest isolation method in the Add Zone wizard
Without this, an operator standing up a new OVN-backed zone has to either pick a different isolation method (forcing the OVN provider into a no-op posture) or fall back to provisioning the zone via the API and registering the OVN provider with addOvnProvider out-of-band. Both Netris and NSX have a dedicated wizard step for the same flow; this commit gives OVN the equivalent. ZoneWizardPhysicalNetworkSetupStep.vue and PhysicalNetworksTab.vue: add "OVN" to the isolation-method dropdown for KVM zones (matching how "Netris" is gated to KVM today). Other hypervisors keep their existing options unchanged. ZoneWizardNetworkSetupStep.vue: - new isOvnZone computed (mirrors isNetrisZone) flips on whenever any declared physical network selects "OVN". - new "ovn" step inserted into allSteps() right after the netris step, between the physical-network grid and the public-traffic configuration. - new ovnFields list mirrors AddOvnProviderCmd's parameters: name, nbConnection (required) sbConnection, externalBridge, localnetName, cacertpath, clientcertpath, clientprivatekeypath (optional). Required-vs-optional matches the Java side; the operator can leave the TLS / bridge-mapping fields blank for simple labs. - ovnSetupDescription points at a new i18n key that explains the bridge mapping requirement on the ovn-controller side. ZoneWizardLaunchZone.vue: - stepData.isOvnZone is set in the existing physical-network creation loop using the same gating as Netris/NSX (only when the OVN physnet carries public or guest traffic - storage-only physnets do not need a provider entry). - stepNetworkingProviderOrStorageTraffic dispatches to the new stepAddOvnProvider when the zone is OVN. - stepAddOvnProvider posts to addOvnProvider with the prefillContent collected by the wizard. Optional fields are only forwarded when the operator filled them in, so a minimal OVN deployment that uses default ovsdb ports / no TLS does not have to clear ghost values. - addOvnProvider is the postAPI wrapper, parallel to addNetrisProvider / addNsxController. ui/public/locales/en.json: - 9 new label.* / message.* keys for the OVN provider step (form labels, install-wizard tooltips, the description shown on the step, and the "Add OVN Provider" header used by the launch progress panel). Tooltip text spells out the connection-string format (tcp/ssl + host + port) and the relationship between the localnet name and ovn-bridge-mappings on the hypervisors.
1 parent 91a9caa commit 332a5aa

3 files changed

Lines changed: 176 additions & 1 deletion

File tree

ui/public/locales/en.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,15 @@
16941694
"label.netris.provider.tenant.name": "Netris provider Admin Tenant name",
16951695
"label.netris.provider.tag": "Netris Tag",
16961696
"label.netris.provider.url": "Netris provider URL",
1697+
"label.ovn.provider": "OVN Provider",
1698+
"label.ovn.provider.name": "OVN provider name",
1699+
"label.ovn.provider.nb.connection": "OVN Northbound DB connection",
1700+
"label.ovn.provider.sb.connection": "OVN Southbound DB connection",
1701+
"label.ovn.provider.external.bridge": "OVN external bridge",
1702+
"label.ovn.provider.localnet.name": "OVN localnet (physical network mapping)",
1703+
"label.ovn.provider.ca.cert.path": "OVN TLS CA certificate path",
1704+
"label.ovn.provider.client.cert.path": "OVN TLS client certificate path",
1705+
"label.ovn.provider.client.private.key.path": "OVN TLS client private key path",
16971706
"label.netscaler": "NetScaler",
16981707
"label.netscaler.mpx": "NetScaler MPX LoadBalancer",
16991708
"label.netscaler.sdx": "NetScaler SDX LoadBalancer",
@@ -1788,7 +1797,6 @@
17881797
"label.nsx.supports.internal.lb": "Enable NSX internal LB service",
17891798
"label.nsx.supports.lb": "Enable NSX LB service",
17901799
"label.ovn": "OVN",
1791-
"label.ovn.provider": "OVN Provider",
17921800
"label.ovnnbconnection": "OVN Northbound connection",
17931801
"label.ovnsbconnection": "OVN Southbound connection",
17941802
"label.ovnexternalbridge": "OVN external bridge",
@@ -3115,6 +3123,7 @@
31153123
"message.add.latest.kubernetes.iso.failed": "Failed to add latest Kubernetes ISO",
31163124
"message.add.minimum.required.compute.offering.kubernetes.cluster.failed": "Failed to add minimum required Compute Offering for Kubernetes cluster nodes",
31173125
"message.add.netris.controller": "Add Netris Provider",
3126+
"message.add.ovn.controller": "Add OVN Provider",
31183127
"message.add.nsx.controller": "Add NSX Provider",
31193128
"message.add.network": "Add a new network for Zone: <b><span id=\"zone_name\"></span></b>",
31203129
"message.add.network.acl.failed": "Adding network ACL failed.",
@@ -3630,6 +3639,7 @@
36303639
"message.info.cloudian.console": "Cloudian Management Console should open in another window.",
36313640
"message.installwizard.cloudstack.helptext.website": " * Project website:\t ",
36323641
"message.infra.setup.netris.description": "This zone must contain a Netris provider because the isolation method is Netris",
3642+
"message.infra.setup.ovn.description": "This zone must contain an OVN provider because the isolation method is OVN. Provide the OVN central NB/SB endpoints and the bridge mapping used by ovn-controller on the hypervisors.",
36333643
"message.infra.setup.nsx.description": "This Zone must contain an NSX provider because the isolation method is NSX",
36343644
"message.infra.setup.tungsten.description": "This Zone must contain a Tungsten-Fabric provider because the isolation method is TF",
36353645
"message.installwizard.cloudstack.helptext.document": " * Documentation:\t ",
@@ -3654,6 +3664,14 @@
36543664
"message.installwizard.tooltip.netris.provider.site": "Netris Provider Site name not provided",
36553665
"message.installwizard.tooltip.netris.provider.tag": "Netris Tag to be assigned to vNets",
36563666
"message.installwizard.tooltip.netris.provider.tenant.name": "Netris Provider Admin Tenant name not provided",
3667+
"message.installwizard.tooltip.ovn.provider.name": "Friendly name for this OVN provider entry, e.g. 'ovn-central-1'",
3668+
"message.installwizard.tooltip.ovn.provider.nb.connection": "OVN Northbound DB connection string. Examples: tcp:10.0.0.10:6641, ssl:nb.ovn.example:6641",
3669+
"message.installwizard.tooltip.ovn.provider.sb.connection": "OVN Southbound DB connection string (recommended). Used to enumerate live Chassis for Gateway_Chassis pinning. Example: tcp:10.0.0.10:6642",
3670+
"message.installwizard.tooltip.ovn.provider.external.bridge": "OVS bridge that ovn-controller uses for the public network. Example: br-ex",
3671+
"message.installwizard.tooltip.ovn.provider.localnet.name": "Logical network name used in ovn-bridge-mappings on each hypervisor. Example: physnet1 (matches ovn-bridge-mappings=physnet1:br-ex)",
3672+
"message.installwizard.tooltip.ovn.provider.ca.cert.path": "Filesystem path to the CA certificate used by OVN OVSDB SSL endpoints. Required only when nb/sb connection uses ssl://",
3673+
"message.installwizard.tooltip.ovn.provider.client.cert.path": "Filesystem path to the client certificate used by CloudStack to authenticate to OVN OVSDB. Required only when ssl:// is in use",
3674+
"message.installwizard.tooltip.ovn.provider.client.private.key.path": "Filesystem path to the client private key paired with the client certificate. Required only when ssl:// is in use",
36573675
"message.installwizard.tooltip.nsx.provider.hostname": "NSX Provider hostname / IP address not provided",
36583676
"message.installwizard.tooltip.nsx.provider.username": "NSX Provider username not provided",
36593677
"message.installwizard.tooltip.nsx.provider.password": "NSX Provider password not provided",

ui/src/views/infra/zone/ZoneWizardLaunchZone.vue

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,13 @@ export default {
493493
physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public' || traffic.type === 'guest') > -1) {
494494
this.stepData.isNetrisZone = true
495495
}
496+
// Same gating as Netris/NSX: only flag the zone as OVN when the physical
497+
// network actually carries public or guest traffic. Storage- or management-
498+
// only physnets that happen to be tagged OVN do not need a provider entry.
499+
if (physicalNetwork.isolationMethod.toLowerCase() === 'ovn' &&
500+
physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public' || traffic.type === 'guest') > -1) {
501+
this.stepData.isOvnZone = true
502+
}
496503
} else {
497504
this.stepData.physicalNetworkReturned = this.stepData.physicalNetworkItem['createPhysicalNetwork' + index]
498505
}
@@ -910,6 +917,8 @@ export default {
910917
await this.stepAddNsxController()
911918
} else if (this.stepData.isNetrisZone) {
912919
await this.stepAddNetrisProvider()
920+
} else if (this.stepData.isOvnZone) {
921+
await this.stepAddOvnProvider()
913922
} else {
914923
await this.stepConfigureStorageTraffic()
915924
}
@@ -1157,6 +1166,54 @@ export default {
11571166
this.setStepStatus(STATUS_FAILED)
11581167
}
11591168
},
1169+
async stepAddOvnProvider () {
1170+
// Mirror of stepAddNetrisProvider: register the OVN central (NB/SB) endpoints with
1171+
// the zone via addOvnProvider so OvnGuestNetworkGuru can resolve the provider when
1172+
// a network is implemented. Only `name` and `nbconnection` are mandatory; the rest
1173+
// are optional and skipped when the operator left the field blank in the wizard.
1174+
this.setStepStatus(STATUS_FINISH)
1175+
this.currentStep++
1176+
this.addStep('message.add.ovn.controller', 'ovn')
1177+
if (this.stepData.stepMove.includes('ovn')) {
1178+
await this.stepConfigureStorageTraffic()
1179+
return
1180+
}
1181+
try {
1182+
if (!this.stepData.stepMove.includes('addOvnProvider')) {
1183+
const providerParams = {}
1184+
providerParams.zoneid = this.stepData.zoneReturned.id
1185+
providerParams.name = this.prefillContent?.ovnName || ''
1186+
providerParams.nbconnection = this.prefillContent?.ovnNbConnection || ''
1187+
if (this.prefillContent?.ovnSbConnection) {
1188+
providerParams.sbconnection = this.prefillContent.ovnSbConnection
1189+
}
1190+
if (this.prefillContent?.ovnExternalBridge) {
1191+
providerParams.externalbridge = this.prefillContent.ovnExternalBridge
1192+
}
1193+
if (this.prefillContent?.ovnLocalnetName) {
1194+
providerParams.localnetname = this.prefillContent.ovnLocalnetName
1195+
}
1196+
if (this.prefillContent?.ovnCaCertPath) {
1197+
providerParams.cacertpath = this.prefillContent.ovnCaCertPath
1198+
}
1199+
if (this.prefillContent?.ovnClientCertPath) {
1200+
providerParams.clientcertpath = this.prefillContent.ovnClientCertPath
1201+
}
1202+
if (this.prefillContent?.ovnClientPrivateKeyPath) {
1203+
providerParams.clientprivatekeypath = this.prefillContent.ovnClientPrivateKeyPath
1204+
}
1205+
1206+
await this.addOvnProvider(providerParams)
1207+
this.stepData.stepMove.push('addOvnProvider')
1208+
}
1209+
this.stepData.stepMove.push('ovn')
1210+
await this.stepConfigureStorageTraffic()
1211+
} catch (e) {
1212+
this.messageError = e
1213+
this.processStatus = STATUS_FAILED
1214+
this.setStepStatus(STATUS_FAILED)
1215+
}
1216+
},
11601217
async stepConfigureStorageTraffic () {
11611218
let targetNetwork = false
11621219
this.prefillContent.physicalNetworks.forEach(physicalNetwork => {
@@ -2339,6 +2396,16 @@ export default {
23392396
})
23402397
})
23412398
},
2399+
addOvnProvider (args) {
2400+
return new Promise((resolve, reject) => {
2401+
postAPI('addOvnProvider', args).then(json => {
2402+
resolve()
2403+
}).catch(error => {
2404+
const message = error.response.headers['x-description']
2405+
reject(message)
2406+
})
2407+
})
2408+
},
23422409
configTungstenFabricService (args) {
23432410
return new Promise((resolve, reject) => {
23442411
postAPI('configTungstenFabricService', args).then(json => {

ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@
102102
:isFixError="isFixError"
103103
/>
104104

105+
<static-inputs-form
106+
v-if="steps && steps[currentStep].formKey === 'ovn'"
107+
@nextPressed="nextPressed"
108+
@backPressed="handleBack"
109+
@fieldsChanged="fieldsChanged"
110+
@submitLaunchZone="submitLaunchZone"
111+
:fields="ovnFields"
112+
:prefillContent="prefillContent"
113+
:description="ovnSetupDescription"
114+
:isFixError="isFixError"
115+
/>
116+
105117
<static-inputs-form
106118
v-if="steps && steps[currentStep].formKey === 'pod'"
107119
@nextPressed="nextPressed"
@@ -237,6 +249,15 @@ export default {
237249
}
238250
return isNetris
239251
},
252+
isOvnZone () {
253+
// The physical-network grid stores the user's selection as the literal label of the
254+
// dropdown option. The OVN option is registered as value="OVN" in
255+
// ZoneWizardPhysicalNetworkSetupStep.vue, so match on that exact string.
256+
if (!this.prefillContent.physicalNetworks) {
257+
return false
258+
}
259+
return this.prefillContent.physicalNetworks.findIndex(network => network.isolationMethod === 'OVN') > -1
260+
},
240261
allSteps () {
241262
const steps = []
242263
steps.push({
@@ -261,6 +282,12 @@ export default {
261282
formKey: 'netris'
262283
})
263284
}
285+
if (this.isOvnZone) {
286+
steps.push({
287+
title: 'label.ovn.provider',
288+
formKey: 'ovn'
289+
})
290+
}
264291
if (this.havingNetscaler) {
265292
steps.push({
266293
title: 'label.netScaler',
@@ -523,6 +550,68 @@ export default {
523550
]
524551
return fields
525552
},
553+
ovnFields () {
554+
// Mirrors the AddOvnProviderCmd parameters in
555+
// plugins/network-elements/ovn/.../api/command/AddOvnProviderCmd.java.
556+
// Only `name` and `nbConnection` are mandatory on the API; everything else is
557+
// optional but operator-recommended for a usable zone:
558+
// - sbConnection lets us prune stale Gateway_Chassis rows (PR-2a/PR-2b)
559+
// - externalBridge / localnetName are how the public LS bridges to the
560+
// physical network via ovn-bridge-mappings
561+
// - the three TLS paths are required when the operator has secured the
562+
// OVSDB endpoints with TLS (NB/SB on ssl:host:6641|6642).
563+
const fields = [
564+
{
565+
title: 'label.ovn.provider.name',
566+
key: 'ovnName',
567+
placeHolder: 'message.installwizard.tooltip.ovn.provider.name',
568+
required: true
569+
},
570+
{
571+
title: 'label.ovn.provider.nb.connection',
572+
key: 'ovnNbConnection',
573+
placeHolder: 'message.installwizard.tooltip.ovn.provider.nb.connection',
574+
required: true
575+
},
576+
{
577+
title: 'label.ovn.provider.sb.connection',
578+
key: 'ovnSbConnection',
579+
placeHolder: 'message.installwizard.tooltip.ovn.provider.sb.connection',
580+
required: false
581+
},
582+
{
583+
title: 'label.ovn.provider.external.bridge',
584+
key: 'ovnExternalBridge',
585+
placeHolder: 'message.installwizard.tooltip.ovn.provider.external.bridge',
586+
required: false
587+
},
588+
{
589+
title: 'label.ovn.provider.localnet.name',
590+
key: 'ovnLocalnetName',
591+
placeHolder: 'message.installwizard.tooltip.ovn.provider.localnet.name',
592+
required: false
593+
},
594+
{
595+
title: 'label.ovn.provider.ca.cert.path',
596+
key: 'ovnCaCertPath',
597+
placeHolder: 'message.installwizard.tooltip.ovn.provider.ca.cert.path',
598+
required: false
599+
},
600+
{
601+
title: 'label.ovn.provider.client.cert.path',
602+
key: 'ovnClientCertPath',
603+
placeHolder: 'message.installwizard.tooltip.ovn.provider.client.cert.path',
604+
required: false
605+
},
606+
{
607+
title: 'label.ovn.provider.client.private.key.path',
608+
key: 'ovnClientPrivateKeyPath',
609+
placeHolder: 'message.installwizard.tooltip.ovn.provider.client.private.key.path',
610+
required: false
611+
}
612+
]
613+
return fields
614+
},
526615
guestTrafficFields () {
527616
const fields = [
528617
{
@@ -594,6 +683,7 @@ export default {
594683
tungstenSetupDescription: 'message.infra.setup.tungsten.description',
595684
nsxSetupDescription: 'message.infra.setup.nsx.description',
596685
netrisSetupDescription: 'message.infra.setup.netris.description',
686+
ovnSetupDescription: 'message.infra.setup.ovn.description',
597687
netscalerSetupDescription: 'label.please.specify.netscaler.info',
598688
storageTrafficDescription: 'label.zonewizard.traffictype.storage',
599689
podFields: [

0 commit comments

Comments
 (0)