|
43 | 43 | EOF |
44 | 44 | when: configure_ipam | bool |
45 | 45 |
|
| 46 | +# DCN requires routes in the internalapi NAD so OVN SB pods can reach DCN compute nodes. |
| 47 | +# Macvlan pods don't inherit routes from the node interface, so we add them to the NAD. |
| 48 | +- name: Patch internalapi NAD with routes to DCN subnets |
| 49 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 50 | + no_log: "{{ use_no_log }}" |
| 51 | + ansible.builtin.shell: | |
| 52 | + {{ shell_header }} |
| 53 | + {{ oc_header }} |
| 54 | +
|
| 55 | + # Get current NAD config |
| 56 | + CURRENT_CONFIG=$(oc get net-attach-def internalapi -n openstack -o jsonpath='{.spec.config}') |
| 57 | +
|
| 58 | + # Check if routes already exist |
| 59 | + if echo "$CURRENT_CONFIG" | grep -q '"routes"'; then |
| 60 | + echo "Routes already exist in internalapi NAD, skipping" |
| 61 | + exit 0 |
| 62 | + fi |
| 63 | +
|
| 64 | + # Build routes array for DCN subnets |
| 65 | + # DCN1: 172.17.10.0/24, DCN2: 172.17.20.0/24, gateway: 172.17.0.1 |
| 66 | + ROUTES='[{"dst":"172.17.10.0/24","gw":"172.17.0.1"},{"dst":"172.17.20.0/24","gw":"172.17.0.1"}]' |
| 67 | +
|
| 68 | + # Add routes to IPAM config |
| 69 | + NEW_CONFIG=$(echo "$CURRENT_CONFIG" | python3 -c " |
| 70 | + import json, sys |
| 71 | + config = json.load(sys.stdin) |
| 72 | + config['ipam']['routes'] = json.loads('$ROUTES') |
| 73 | + print(json.dumps(config)) |
| 74 | + ") |
| 75 | +
|
| 76 | + # Apply updated NAD |
| 77 | + oc apply -f - <<EOF |
| 78 | + apiVersion: k8s.cni.cncf.io/v1 |
| 79 | + kind: NetworkAttachmentDefinition |
| 80 | + metadata: |
| 81 | + name: internalapi |
| 82 | + namespace: openstack |
| 83 | + labels: |
| 84 | + osp/net: internalapi |
| 85 | + osp/net-attach-def-type: standard |
| 86 | + spec: |
| 87 | + config: | |
| 88 | + $NEW_CONFIG |
| 89 | + EOF |
| 90 | + register: nad_patch_result |
| 91 | + |
| 92 | +- name: Restart OVN SB pods to pick up new NAD routes |
| 93 | + when: |
| 94 | + - edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 95 | + - nad_patch_result.changed |
| 96 | + - "'skipping' not in nad_patch_result.stdout" |
| 97 | + no_log: "{{ use_no_log }}" |
| 98 | + ansible.builtin.shell: | |
| 99 | + {{ shell_header }} |
| 100 | + {{ oc_header }} |
| 101 | +
|
| 102 | + # Delete OVN SB pods so they restart with new routes |
| 103 | + oc delete pod -n openstack -l service=ovsdbserver-sb --wait=false |
| 104 | +
|
| 105 | + # Wait for pods to be ready again |
| 106 | + sleep 10 |
| 107 | + oc wait --for=condition=Ready pod -n openstack -l service=ovsdbserver-sb --timeout=120s |
| 108 | +
|
46 | 109 | - name: Slurp the private key |
47 | 110 | no_log: "{{ use_no_log }}" |
48 | 111 | ansible.builtin.slurp: |
|
258 | 321 | {% endif %} |
259 | 322 | {% endfor %} |
260 | 323 |
|
| 324 | +- name: Get OVN SB internalapi IPs for DCN nodesets |
| 325 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 326 | + no_log: "{{ use_no_log }}" |
| 327 | + ansible.builtin.shell: | |
| 328 | + {{ shell_header }} |
| 329 | + {{ oc_header }} |
| 330 | +
|
| 331 | + # Get internalapi IPs from OVN SB pods |
| 332 | + OVN_SB_IPS="" |
| 333 | + for pod in ovsdbserver-sb-0 ovsdbserver-sb-1 ovsdbserver-sb-2; do |
| 334 | + IP=$(oc get pod -n openstack $pod -o jsonpath='{.metadata.annotations.k8s\.v1\.cni\.cncf\.io/network-status}' | \ |
| 335 | + python3 -c "import sys, json; data=json.load(sys.stdin); print([n for n in data if 'internalapi' in n.get('name','')][0]['ips'][0])") |
| 336 | + if [ -z "$OVN_SB_IPS" ]; then |
| 337 | + OVN_SB_IPS="\"$IP\"" |
| 338 | + else |
| 339 | + OVN_SB_IPS="$OVN_SB_IPS, \"$IP\"" |
| 340 | + fi |
| 341 | + done |
| 342 | +
|
| 343 | + echo "[$OVN_SB_IPS]" |
| 344 | + register: ovn_sb_ips_result |
| 345 | + |
| 346 | +- name: Set OVN SB IPs fact for DCN nodesets |
| 347 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 348 | + ansible.builtin.set_fact: |
| 349 | + edpm_ovn_dbs_dcn: "{{ ovn_sb_ips_result.stdout | trim | from_json }}" |
| 350 | + |
| 351 | +- name: Create DCN OVN controller ConfigMap with direct IPs |
| 352 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 353 | + no_log: "{{ use_no_log }}" |
| 354 | + ansible.builtin.shell: | |
| 355 | + {{ shell_header }} |
| 356 | + {{ oc_header }} |
| 357 | +
|
| 358 | + # Build ovn-remote connection string from internalapi IPs |
| 359 | + OVN_REMOTE="{% for ip in edpm_ovn_dbs_dcn %}tcp:{{ ip }}:6642{% if not loop.last %},{% endif %}{% endfor %}" |
| 360 | +
|
| 361 | + # Create ConfigMap for DCN nodes with direct IPs |
| 362 | + oc apply -f - <<EOF |
| 363 | + apiVersion: v1 |
| 364 | + kind: ConfigMap |
| 365 | + metadata: |
| 366 | + name: ovncontroller-config-dcn |
| 367 | + namespace: openstack |
| 368 | + data: |
| 369 | + ovsdb-config: | |
| 370 | + ovn-remote: $OVN_REMOTE |
| 371 | + EOF |
| 372 | +
|
| 373 | +- name: Create DCN-specific OVN DataPlaneService |
| 374 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 375 | + no_log: "{{ use_no_log }}" |
| 376 | + ansible.builtin.shell: | |
| 377 | + {{ shell_header }} |
| 378 | + {{ oc_header }} |
| 379 | +
|
| 380 | + # Create OpenStackDataPlaneService for DCN that uses the DCN ConfigMap |
| 381 | + oc apply -f - <<EOF |
| 382 | + apiVersion: dataplane.openstack.org/v1beta1 |
| 383 | + kind: OpenStackDataPlaneService |
| 384 | + metadata: |
| 385 | + name: ovn-dcn |
| 386 | + namespace: openstack |
| 387 | + spec: |
| 388 | + addCertMounts: false |
| 389 | + caCerts: combined-ca-bundle |
| 390 | + containerImageFields: |
| 391 | + - OvnControllerImage |
| 392 | + dataSources: |
| 393 | + - configMapRef: |
| 394 | + name: ovncontroller-config-dcn |
| 395 | + edpmServiceType: ovn |
| 396 | + playbook: osp.edpm.ovn |
| 397 | + tlsCerts: |
| 398 | + default: |
| 399 | + contents: |
| 400 | + - dnsnames |
| 401 | + - ips |
| 402 | + issuer: osp-rootca-issuer-ovn |
| 403 | + keyUsages: |
| 404 | + - digital signature |
| 405 | + - key encipherment |
| 406 | + - server auth |
| 407 | + - client auth |
| 408 | + networks: |
| 409 | + - ctlplane |
| 410 | + EOF |
| 411 | +
|
261 | 412 | - name: Create OpenStackDataPlaneNodeSet_dcn1 |
262 | 413 | when: edpm_nodes_dcn1 is defined |
263 | 414 | no_log: "{{ use_no_log }}" |
264 | 415 | vars: |
265 | 416 | edpm_ovn_bridge_mappings_nodeset: "{{ edpm_ovn_bridge_mappings_dcn1|default(omit) }}" |
| 417 | + edpm_ovn_dbs_nodeset: "{{ edpm_ovn_dbs_dcn }}" |
266 | 418 | ansible.builtin.shell: | |
267 | 419 | {{ shell_header }} |
268 | 420 | CELL=cell1 |
|
279 | 431 | no_log: "{{ use_no_log }}" |
280 | 432 | vars: |
281 | 433 | edpm_ovn_bridge_mappings_nodeset: "{{ edpm_ovn_bridge_mappings_dcn2|default(omit) }}" |
| 434 | + edpm_ovn_dbs_nodeset: "{{ edpm_ovn_dbs_dcn }}" |
282 | 435 | ansible.builtin.shell: | |
283 | 436 | {{ shell_header }} |
284 | 437 | CELL=cell1 |
|
336 | 489 | cat nodeset-cell1-dcn2.yaml | oc apply -f - |
337 | 490 | {%+ endif +%} |
338 | 491 |
|
| 492 | +- name: Patch DCN nodesets to use ovn-dcn service instead of ovn |
| 493 | + when: edpm_nodes_dcn1 is defined or edpm_nodes_dcn2 is defined |
| 494 | + no_log: "{{ use_no_log }}" |
| 495 | + ansible.builtin.shell: | |
| 496 | + {{ shell_header }} |
| 497 | + {{ oc_header }} |
| 498 | +
|
| 499 | + # Patch dcn1 nodeset if it exists |
| 500 | + {% if edpm_nodes_dcn1 is defined %} |
| 501 | + if oc get openstackdataplanenodeset dcn1 -n openstack &>/dev/null; then |
| 502 | + # Get current services list and replace 'ovn' with 'ovn-dcn' |
| 503 | + SERVICES=$(oc get openstackdataplanenodeset dcn1 -n openstack -o jsonpath='{.spec.services}' | \ |
| 504 | + sed 's/"ovn"/"ovn-dcn"/g') |
| 505 | +
|
| 506 | + # Apply the patch |
| 507 | + oc patch openstackdataplanenodeset dcn1 -n openstack --type=merge --patch " |
| 508 | + spec: |
| 509 | + services: $SERVICES |
| 510 | + " |
| 511 | + echo "Patched dcn1 nodeset to use ovn-dcn service" |
| 512 | + fi |
| 513 | + {% endif %} |
| 514 | +
|
| 515 | + # Patch dcn2 nodeset if it exists |
| 516 | + {% if edpm_nodes_dcn2 is defined %} |
| 517 | + if oc get openstackdataplanenodeset dcn2 -n openstack &>/dev/null; then |
| 518 | + # Get current services list and replace 'ovn' with 'ovn-dcn' |
| 519 | + SERVICES=$(oc get openstackdataplanenodeset dcn2 -n openstack -o jsonpath='{.spec.services}' | \ |
| 520 | + sed 's/"ovn"/"ovn-dcn"/g') |
| 521 | +
|
| 522 | + # Apply the patch |
| 523 | + oc patch openstackdataplanenodeset dcn2 -n openstack --type=merge --patch " |
| 524 | + spec: |
| 525 | + services: $SERVICES |
| 526 | + " |
| 527 | + echo "Patched dcn2 nodeset to use ovn-dcn service" |
| 528 | + fi |
| 529 | + {% endif %} |
| 530 | +
|
339 | 531 | # TODO(bogdando): Apply the ceph backend config for Cinder in the original openstack CR, via kustomize perhaps? |
340 | 532 | - name: prepare the adopted data plane workloads to use Ceph backend for Cinder, if configured so |
341 | 533 | no_log: "{{ use_no_log }}" |
|
0 commit comments