OpenStack Plugin RHOSO 18 Installation#
This guide provides step-by-step instructions for installing the Nokia EDA Connect OpenStack plugin on Red Hat OpenStack Services on OpenShift (RHOSO) 18.0 using the OpenStack Operator on Red Hat OpenShift Container Platform (RHOCP).
Warning
Before proceeding with this installation method, ensure you have completed all the prerequisites and preparation steps described in the OpenStack Plugin Installation guide.
Prerequisites#
- All prerequisites from the OpenStack Plugin Installation guide must be met
- EDA Kubernetes preparation steps (Service Account and Token) must be completed
- A RHOCP cluster that meets RHOSO 18.0 requirements. Red Hat documents validated combinations for each RHOSO release; plan the cluster using Planning your deployment and Preparing RHOCP for RHOSO
- OpenStack Operator installed in the
openstack-operatorsnamespace (see Installing and preparing the OpenStack Operator) - Access to Nokia EDA Connect container images on
registry.connect.redhat.com/nokia-nifor the Neutron API andopenstackclientimages used on RHOSO 18 - Administrative access to the OpenShift cluster (
oc) and to the EDA Kubernetes cluster (kubectl)
Getting the container registry credentials
Contact your Red Hat representative to obtain credentials for accessing the Nokia container images in the Red Hat Container Catalog. Configure registry.connect.redhat.com in the cluster pull secret (or equivalent image pull authentication for the openstack namespace) so worker nodes can pull the Neutron and openstackclient images after you reference them in OpenStackVersion.
RHOSP 17.1 vs. RHOSO 18
| Aspect | RHOSP 17.1 (TripleO) | RHOSO 18 (OCP) |
|---|---|---|
| Neutron deployment | Podman containers via Heat | Kubernetes pods via OpenStack Operator |
| EDA ML2 settings | TripleO environment file | Kubernetes Secret mounted into Neutron pods |
| Nokia container images | container-image-prepare overrides | OpenStackVersion.spec.customContainerImages |
| CA certificate | inject-trust-anchor Heat environment | Kubernetes Secret and volume mount |
| LLDP on computes | Post-deploy Ansible playbook | OpenStackDataPlaneService on the data plane |
Installation Steps#
Step 1: Prepare EDA specific artifacts#
EDA CA Certificate Secret (If Required)#
If the EDA K8S API uses a self-signed certificate, store the CA in a Secret in the openstack namespace. The file should contain the PEM CA Certificate you retrieved earlier (see also OpenStack Plugin Installation).
Trusted public CA
If EDA uses certificates signed by a well-known certificate authority, skip creating eda-ca-secret, omit the CA volume from extraMounts, and remove the ca_cert_path setting from the ML2 fragment in Step 5.
Replace /path/to/eda.crt with the path to the saved CA certificate.
Neutron ML2 EDA Connect Secret#
Create a Secret that holds the [ml2_eda_connect] configuration consumed by Neutron. Use a temporary file, then create the secret:
cat > /tmp/eda-ml2.conf <<'EOF'
[DEFAULT]
nic_mapping_provisioning = True
[ml2_eda_connect]
plugin_name = <OPENSTACK_PLUGIN_NAME>
api_host = https://<EDA_API_HOST>:6443
api_namespace = <EDA_NAMESPACE>
api_token = <SERVICE_ACCOUNT_TOKEN>
ca_cert_path = /etc/pki/ca-trust/source/anchors/eda.crt
heartbeat_interval = 10
EOF
oc create secret generic nokia-eda-ml2-config \
--from-file=eda.conf=/tmp/eda-ml2.conf \
-n openstack
rm /tmp/eda-ml2.conf
Update the placeholders in the fragment before creating the secret:
plugin_name- A unique name for this OpenStack deployment in EDA (for example
rhoso-prod)
Plugin name requirements
The plugin name must comply with the regex '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]', contain only alphanumerics and ., _, -, start with an alphanumeric, and be at most 63 characters.
api_host- EDA Kubernetes API hostname (for example
api.eda.example.com); the URI in the file must includehttps://and port:6443as shown api_namespace- Namespace where the fabric is configured in EDA
api_token- Bearer token from the Create a Service Account Token section
ca_cert_path- Use
/etc/pki/ca-trust/source/anchors/eda.crtwhen usingeda-ca-secret; omit the line entirely if EDA uses a public CA heartbeat_interval- Optional; shown as
10seconds in the example
Step 2: OpenStack Operator and Namespaces#
On the OpenShift cluster, create the operator and workload namespaces and install the OpenStack Operator following Red Hat's guide:
Use the YAML from the current RHOSO documentation for your release rather than copying abbreviated examples here. Follow chapters 1, 2 and 3 in the guide, continue here once you get to Chapter 4: "Creating the control plane".
Step 3: OpenStack Control Plane — Neutron and EDA Mounts#
During chapter 4 of the Red Hat guide, you will have to adjust some steps as detailed below.
Build your OpenStackControlPlane custom resource from Creating the control plane. Merge Red Hat’s full control plane spec (DNS, Keystone, Nova, Cinder, Glance, storage class, secrets, and so on) with the adjusted Neutron settings below.
For EDA Connect, we will heavily modify the neutron section of the OpenStackControlPlane custom resource, as touched upon in the Red Hat Configuring network services and Integrating partner content]guide:
Configuration example
The below configuration is an example of the neutron section of the OpenStackControlPlane custom resource. Adapt it to your environment. Important elements of the configuration have been annotated with (+) to explain their purpose.
apiVersion: core.openstack.org/v1beta1
kind: OpenStackControlPlane
metadata:
name: openstack
namespace: openstack
spec:
secret: osp-secret
storageClass: <STORAGE_CLASS> # e.g. ocs-storagecluster-ceph-rbd
# ... (DNS, Keystone, Nova, Cinder, Glance, etc. — see upstream guide)
# https://docs.redhat.com/en/documentation/red_hat_openstack_services_on_openshift/18.0/html/deploying_red_hat_openstack_services_on_openshift/assembly_creating-the-control-plane
neutron:
enabled: true
apiOverride:
route: {}
template:
databaseInstance: openstack
secret: neutron-secret
networkAttachments:
- internalapi
replicas: 3
customServiceConfig: | #(2)!
[DEFAULT]
debug = True
service_plugins = segments,trunk,qos,port_forwarding,placement,nic_mapping
[ml2]
type_drivers = flat,vlan,vxlan
tenant_network_types = vlan,vxlan
mechanism_drivers = ovn,eda_connect,sriovnicswitch
extension_drivers = eda_network,port_security,qos,uplink_status_propagation,dns_domain_keywords
[ml2_type_vlan]
network_vlan_ranges = datacentre:1:4094
# Mount the EDA ML2 config secret and CA cert into the Neutron pod
extraMounts:
- extraVol:
- mounts:
- name: nokia-eda-config #(3)!
mountPath: /etc/neutron/neutron.conf.d/ml2_eda_connect.conf
subPath: ml2_eda_connect.conf
readOnly: true
- name: eda-ca-cert #(4)!
mountPath: /etc/pki/ca-trust/source/anchors/eda.crt
subPath: eda.crt
readOnly: true
volumes:
- name: nokia-eda-config #(3)!
secret:
secretName: nokia-eda-ml2-config
- name: eda-ca-cert #(4)!
secret:
secretName: eda-ca-secret
- Custom Neutron image from registry.connect.redhat.com/nokia-ni that includes the eda_connect ML2 driver, adjust the image tag to the appropriate one for your environment.
- We override the configuration of the Neutron service to include the eda_connect mechanism driver and the eda_network extension driver. Note that all other configuration should be adapted to your environment, you can omit any entries to use the default values. Note that layer 3 OVN functionality is not supported together with the EDA Connect OpenStack driver.
- We mount the nokia-eda-ml2-config from Step 1 to provide the EDA Connect OpenStack ML2 plugin with its configuration.
- If the EDA K8S API uses a self-signed CA, we mount that CA in the pod to validate communication with the EDA K8S API. Leave this block out if the EDA K8S API is signed by an official CA.
Do not set a custom Neutron containerImage on the control plane for the Nokia image. Image overrides are applied in Step 8 via OpenStackVersion so they persist across operator reconciliation.
Apply your control plane manifest with the configuration for all other services as normal and continue with step 4.
Step 4: Nokia Container Images Override#
To adapt the deployment with the correct images for the EDA Connect OpenStack driver, adapt the OpenStackVersion CR. The OpenStackVersion object is created when the OpenStack Operator reconciles the control plane. Wait until it exists, then patch spec.customContainerImages so Neutron API and the openstackclient deployment use Nokia images that include the EDA mechanism driver and the python-eda-openstackclient extension.
oc patch openstackversion openstack -n openstack \
--type merge -p '{
"spec": {
"customContainerImages": {
"neutronAPIImage": "registry.connect.redhat.com/nokia-ni/rhoso18-openstack-neutron-server-nokia-eda:<TAG>",
"openstackClientImage": "registry.connect.redhat.com/nokia-ni/rhoso18-openstack-openstackclient-nokia-eda:<TAG>"
}
}
}'
Replace <TAG> with the image tags supplied by Nokia or Red Hat. Ensure the cluster can authenticate to registry.connect.redhat.com (for example via the global pull secret), as described under Getting the container registry credentials in the prerequisites.
Verify the patch of the OpenStackVersion CR:
Wait for the control plane to become ready after the patch:
Verify the EDA Connect ML2 driver was loaded:
# Get the neutron-server pod name
NEUTRON_POD=$(oc get pods -n openstack -l service=neutron -o jsonpath='{.items[0].metadata.name}')
# Check logs for EDA Connect initialization
oc logs ${NEUTRON_POD} -n openstack | grep -i "eda_connect"
Step 5: Data Plane#
Continue with chapter 5 Creating the data plane in the Red Hat guide.
EDA Connect requires LLDP on data plane interfaces of compute nodes. On RHOSO 18, model that with an OpenStackDataPlaneService before proceeding beyond step 5.3 "Creating the data plane secrets":
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneService
metadata:
name: edpm-lldp-service
namespace: openstack
spec:
edpmServiceType: edpm-lldp-service
addCertMounts: false
playbookContents: |
---
- name: Configure LLDP on EDPM compute nodes
hosts: all
become: true
tasks:
- name: Install lldpd package
ansible.builtin.package:
name: lldpd
state: present
- name: Enable and start lldpd service
ansible.builtin.systemd:
name: lldpd
state: started
enabled: true
- name: Create lldpd config directory
ansible.builtin.file:
path: /etc/lldpd.d
state: directory
mode: '0755'
- name: Write persistent lldpd configuration
ansible.builtin.copy:
dest: /etc/lldpd.d/eda-connect.conf
content: |
configure lldp portidsubtype ifname
configure system interface pattern em*,en*,p*,!en*v*,!p*v*
mode: '0644'
notify: restart lldpd
handlers:
- name: restart lldpd
ansible.builtin.systemd:
name: lldpd
state: restarted
oc apply -f - <<'EOF'
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneService
metadata:
name: edpm-lldp-service
namespace: openstack
spec:
edpmServiceType: edpm-lldp-service
addCertMounts: false
playbookContents: |
---
- name: Configure LLDP on EDPM compute nodes
hosts: all
become: true
tasks:
- name: Install lldpd package
ansible.builtin.package:
name: lldpd
state: present
- name: Enable and start lldpd service
ansible.builtin.systemd:
name: lldpd
state: started
enabled: true
- name: Create lldpd config directory
ansible.builtin.file:
path: /etc/lldpd.d
state: directory
mode: '0755'
- name: Write persistent lldpd configuration
ansible.builtin.copy:
dest: /etc/lldpd.d/eda-connect.conf
content: |
configure lldp portidsubtype ifname
configure system interface pattern em*,en*,p*,!en*v*,!p*v*
mode: '0644'
notify: restart lldpd
handlers:
- name: restart lldpd
ansible.builtin.systemd:
name: lldpd
state: restarted
EOF
Interface pattern
The default pattern em*,en*,p*,!en*v*,!p*v* matches most physical interfaces while excluding common virtual patterns. Override the playbook content if your NIC naming differs.
Step 6: Creating the OpenStackDataPlaneNodeSet#
Define your OpenStackDataPlaneNodeSet following Creating the data plane and, if applicable, Deploying an NFV environment with SR-IOV and DPDK.
Include the previously created edpm-lldp-service in spec.services after the standard services that should run before LLDP (for example after ovn and Neutron metadata services). Exact ordering should follow your validated service list from Red Hat; a typical pattern is to add edpm-lldp-service alongside other post-network services.
Example OpenStackDataPlaneNodeSet YAML
Example only
Node network templates, SR-IOV mappings, repositories, and node addresses are environment-specific. Do not copy values from examples without aligning them to your hardware and RHOSO network design.
apiVersion: dataplane.openstack.org/v1beta1
kind: OpenStackDataPlaneNodeSet
metadata:
name: openstack-data-plane
namespace: openstack
spec:
preProvisioned: true
networkAttachments:
- ctlplane
services:
- redhat
- download-cache
- bootstrap
- configure-network
- validate-network
- install-os
- configure-os
- ssh-known-hosts
- run-os
- reboot-os
- install-certs
- ovn
- neutron-metadata
- neutron-sriov # Include if SR-IOV is used
- edpm-lldp-service # EDA: LLDP for topology discovery
- libvirt
- nova-custom-sriov # Include if SR-IOV is used
- telemetry
nodeTemplate:
ansibleSSHPrivateKeySecret: dataplane-ansible-ssh-private-key-secret
managementNetwork: ctlplane
ansible:
ansibleUser: cloud-admin
ansiblePort: 22
ansibleVarsFrom:
- secretRef:
name: subscription-manager
- secretRef:
name: redhat-registry
ansibleVars:
rhc_release: "9.4"
rhc_repositories:
- {name: "*", state: disabled}
- {name: "rhel-9-for-x86_64-baseos-eus-rpms", state: enabled}
- {name: "rhel-9-for-x86_64-appstream-eus-rpms", state: enabled}
- {name: "rhel-9-for-x86_64-highavailability-eus-rpms", state: enabled}
- {name: "fast-datapath-for-rhel-9-x86_64-rpms", state: enabled}
- {name: "rhoso-18.0-for-rhel-9-x86_64-rpms", state: enabled}
- {name: "rhceph-7-tools-for-rhel-9-x86_64-rpms", state: enabled}
edpm_bootstrap_release_version_package: []
# Kernel args required for SR-IOV PCI passthrough (IOMMU)
edpm_kernel_args: "iommu=pt intel_iommu=on"
# SR-IOV NIC configuration (adapt interface names and VF counts)
edpm_neutron_sriov_agent_SRIOV_NIC_physical_device_mappings: "datacentre:ens1f0np0,datacentre:ens1f1np1"
edpm_nova_libvirt_SRIOV_numvfs:
ens1f0np0: 8
ens1f1np1: 8
# NTP
edpm_chrony_ntp_servers:
- <NTP_SERVER_1>
- <NTP_SERVER_2>
# Network config (adapt MACs/interfaces to your hardware)
neutron_physical_bridge_name: br-ex
edpm_network_config_nmstate: true
edpm_network_config_update: false
edpm_network_config_template: |
---
network_config:
- type: ovs_bridge
name: {{ neutron_physical_bridge_name }}
use_dhcp: false
addresses:
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_cidr }}
members:
- type: linux_bond
name: bond0
bonding_options: "mode=802.3ad lacp_rate=fast updelay=1000 miimon=100 xmit_hash_policy=layer3+4"
members:
- type: interface
name: nic1
primary: true
- type: interface
name: nic2
{% for network in nodeset_networks %}
- type: vlan
vlan_id: {{ lookup('vars', networks_lower[network] ~ '_vlan_id') }}
addresses:
- ip_netmask: {{ lookup('vars', networks_lower[network] ~ '_ip') }}/{{ lookup('vars', networks_lower[network] ~ '_cidr') }}
{% endfor %}
nodes:
edpm-compute-0:
hostName: edpm-compute-0
ansible:
ansibleHost: <COMPUTE_0_CTLPLANE_IP>
networks:
- name: ctlplane
subnetName: subnet1
fixedIP: <COMPUTE_0_CTLPLANE_IP>
- name: internalapi
subnetName: subnet1
- name: storage
subnetName: subnet1
- name: tenant
subnetName: subnet1
edpm-compute-1:
hostName: edpm-compute-1
ansible:
ansibleHost: <COMPUTE_1_CTLPLANE_IP>
networks:
- name: ctlplane
subnetName: subnet1
fixedIP: <COMPUTE_1_CTLPLANE_IP>
- name: internalapi
subnetName: subnet1
- name: storage
subnetName: subnet1
- name: tenant
subnetName: subnet1
Apply the nodeset as normal and wait for it to complete.
Step 7: Deploy the Data Plane#
After the nodeset is deployed, continue deploying the data plane following the steps in Deploying the data plane in the Red Hat guide.
Post-Installation Configuration#
Verify the EDA mechanism driver in Neutron#
NEUTRON_POD=$(oc get pods -n openstack -l service=neutron -o jsonpath='{.items[0].metadata.name}')
oc logs ${NEUTRON_POD} -n openstack | grep -iE "eda_connect|eda connect"
You should see log lines indicating the EDA Connect mechanism driver initialized and registered with EDA.
Verify the EDA CLI extension (openstackclient)#
oc rsh -n openstack "$(oc get pod -n openstack -l app=openstackclient -o jsonpath='{.items[0].metadata.name}')" \
openstack eda interface mapping --help
Verify LLDP on EDPM nodes#
On a compute node (SSH as your EDPM user, for example cloud-admin):
Verify topology discovery#
From a host or pod where the OpenStack CLI is configured with credentials for the RHOSO cloud (including the openstackclient pod if you use the Nokia client image there):
Verify registration in EDA#
On the EDA cluster:
Troubleshooting#
Neutron pods fail or restart#
oc describe pod -n openstack -l service=neutron
oc logs -n openstack -l service=neutron --tail=200 --previous
Common causes:
- Invalid or expired API token: Recreate the
nokia-eda-ml2-configsecret with an updated ML2 fragment, then restart Neutron API pods so they load the new secret (for exampleoc delete pod -n openstack -l service=neutron, oroc rollout restarton the Neutron API workload if your RHOSO revision exposes it as aDeployment). - Unreachable EDA API: Confirm routes and DNS from OpenShift worker nodes to the host in
api_host. - TLS errors: Confirm
eda-ca-secretmatchesca_cert_pathand the mount path inextraMounts.
LLDP does not show fabric neighbors#
- Confirm
lldpdis running on the EDPM node. - Inspect
/etc/lldpd.d/eda-connect.confand adjust the interface pattern if NIC names do not match. - Confirm LLDP is enabled on the fabric ports toward the servers.
VLAN networks do not create BridgeDomain objects in EDA#
- Networks must use
provider-network-type vlanfor EDA orchestration. - Check Neutron logs for EDA-related errors.
- In EDA:
kubectl get connectplugins -n <eda-namespace> -o yamland verify status.
SR-IOV kernel arguments not active#
If IOMMU flags are not present in /proc/cmdline after deployment, run a data plane deployment that includes the reboot-os service (see Red Hat EDPM documentation) so nodes reboot into the configured kernel.