Skip to content

Commit 47dadc6

Browse files
beaglesclaude
andcommitted
Support migration windows for BIND9
The IPs for the BIND9 servers may be in external registries or in other DNS configuration for zone delegation via glue records. This change is part of a series to verify the steps to maintaining records in both the RHOSO system and the legacy system to allow a staged migration of DNS infrastructure. Documentation is enhanced to: - Update the procedure for maintaining a migration window with legacy BIND9 servers, including a reference to additional steps after the standard adoption. - Add tasks to configure and enable the Designate service, including creating a LoadBalancer service for mDNS zone transfers. - Refine task names for clarity and removed unnecessary steps related to external binds secret verification. - Improve the patch file creation process for Designate CR to include necessary configurations for legacy BIND9 integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c2642cf commit 47dadc6

8 files changed

Lines changed: 467 additions & 0 deletions

File tree

docs_dev/assemblies/development_environment.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ done
514514
515515
oc delete --wait=false pod ovn-copy-data || true
516516
oc delete --wait=false pod mariadb-copy-data || true
517+
oc delete secret designate-external-binds || true
518+
oc delete service designate-external-master || true
517519
oc delete secret osp-secret || true
518520
----
519521

docs_user/modules/proc_adopting-the-dns-service.adoc

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
[role="_abstract"]
77
To adopt the {dns_first_ref}, you patch an existing `OpenStackControlPlane` custom resource (CR) where the {dns_service} is disabled. The patch starts the service with the configuration parameters that are provided by the {rhos_prev_long} ({OpenStackShort}) environment.
88

9+
[NOTE]
10+
====
11+
If your {rhos_prev_long} deployment uses BIND9 servers that you want to keep serving DNS during and after adoption, you can include them as external backends alongside the new operator-managed BIND9 instances. In this staged migration model, both the legacy BIND9 servers and the new cluster-hosted BIND9 StatefulSet serve the same pool concurrently. This avoids a disruptive DNS switchover and allows external DNS registries and delegations to be updated to reference the new nameservers at a later date.
12+
13+
After completing the standard adoption procedure, see xref:maintaining-a-migration-window-with-legacy-bind9-servers_{context}[Maintaining a migration window with legacy BIND9 servers] for the additional steps required to enable this transition window.
14+
====
15+
916
.Procedure
1017

1118
. Create an alias for the `openstack` command:
@@ -320,3 +327,232 @@ $ oc patch openstackcontrolplane openstack --type=merge --patch-file /tmp/design
320327
----
321328
$ oc wait --for condition=Ready --timeout=600s designate.designate.openstack.org/designate
322329
----
330+
331+
[id="maintaining-a-migration-window-with-legacy-bind9-servers_{context}"]
332+
== Maintaining a migration window with legacy BIND9 servers
333+
334+
If your {rhos_prev_long} deployment uses BIND9 servers that should continue serving DNS during adoption, follow this procedure after completing the standard {dns_service} adoption. The designate worker sends RNDC commands and DNS NOTIFY messages to the legacy servers, which pull zone data from the mDNS service through AXFR on port 5354.
335+
336+
When external DNS registries and delegations have been updated to reference the new nameservers, follow the steps in xref:completing-the-bind9-migration_{context}[Completing the BIND9 migration] to remove the legacy servers from the pool.
337+
338+
.Procedure
339+
340+
. Extract RNDC credentials from each legacy {rhos_prev_long} controller that runs BIND9 and create the `designate-external-binds` secret. Run this script from the adoption host:
341+
+
342+
----
343+
$ binddata_file=/tmp/binddata.yaml
344+
$ rm $binddata_file
345+
$ for i in {1..3}; do
346+
SSH_CMD=CONTROLLER${i}_SSH
347+
if [ ! -z "${!SSH_CMD}" ]; then
348+
echo "Extracting RNDC credentials from controller $i"
349+
RNDC_SECRET=$(${!SSH_CMD} sudo grep secret /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/"/, "", $2); gsub(/;/, "", $2); print $2}')
350+
RNDC_KEYNAME=$(${!SSH_CMD} sudo grep '^key' /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/"/, "", $2); print $2}' | cut -f 1)
351+
RNDC_ALGORITHM=$(${!SSH_CMD} sudo grep algorithm /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/;/, "", $2); print $2}')
352+
CONTROLLER_IP=$(${!SSH_CMD} sudo grep 'internal_api\"' /etc/puppet/hieradata/net_ip_map.json | awk '{gsub(/"/, "", $2); gsub(/,/, "", $2); print $2}')
353+
cat << BINDATACR >> "$binddata_file"
354+
- name: controller-$i
355+
address: $CONTROLLER_IP
356+
rndcsecret: $RNDC_SECRET
357+
rndckeyname: $RNDC_KEYNAME
358+
rndcalgorithm: $RNDC_ALGORITHM
359+
BINDATACR
360+
fi
361+
done
362+
$ if [ -s "$binddata_file" ]; then
363+
external_binds_secret_file=/tmp/external_binds_secret.yaml
364+
cat << EOSECRETC > "$external_binds_secret_file"
365+
apiVersion: v1
366+
kind: Secret
367+
metadata:
368+
name: designate-external-binds
369+
namespace: openstack
370+
type: Opaque
371+
stringData:
372+
default: |
373+
$(cat "$binddata_file")
374+
EOSECRETC
375+
oc apply -f "$external_binds_secret_file"
376+
fi
377+
----
378+
+
379+
where `CONTROLLER1_SSH`, `CONTROLLER2_SSH`, and `CONTROLLER3_SSH` are the SSH connection variables for each legacy controller that runs BIND9. The script extracts credentials from each available controller and automatically creates and applies the `designate-external-binds` secret in the `openstack` namespace.
380+
381+
. Reconfigure the legacy BIND9 instances to accept RNDC connections and zone transfers from the new {rhos_long} deployment. On each legacy controller, modify the BIND9 configuration. Because the `options` and `controls` blocks cannot be reopened, use the following commands to add the required configuration in-place:
382+
+
383+
384+
[subs="+quotes"]
385+
----
386+
$ INTERNALAPI_CIDR=<internalapi_cidr>
387+
$ for i in {1..3}; do
388+
SSH_CMD=CONTROLLER${i}_SSH
389+
if [ ! -z "${!SSH_CMD}" ]; then
390+
echo "Reconfiguring bind on controller $i"
391+
CONTROLLER_IP=$(${!SSH_CMD} sudo grep 'internal_api\"' /etc/puppet/hieradata/net_ip_map.json | awk '{gsub(/"/, "", $2); gsub(/,/, "", $2); print $2}')
392+
${!SSH_CMD} cp -n /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf.pre-adoption-backup
393+
${!SSH_CMD} "sed -i 's:inet [0-9.]* allow { [0-9./]*; }:inet ${CONTROLLER_IP} allow { ${INTERNALAPI_CIDR}; }:' /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf"
394+
${!SSH_CMD} cp -n /var/lib/config-data/ansible-generated/designate/etc/named/options.conf /var/lib/config-data/ansible-generated/designate/etc/named/options.conf.pre-adoption-backup
395+
${!SSH_CMD} "sed -i 's:allow.notify.*};:allow-notify { $INTERNALAPI_CIDR; };:' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
396+
${!SSH_CMD} "sed -i '/allow.transfer:/d' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
397+
${!SSH_CMD} "sed -i '/^options {/,/^};/{
398+
/^};/ i\\\tallow-transfer { '"$INTERNALAPI_CIDR"'; };
399+
}' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
400+
done
401+
----
402+
+
403+
where:
404+
405+
`CONTROLLER_IP`::
406+
Specifies the internalapi IP address of the legacy controller. This can be retrieved from `/etc/puppet/hieradata/net_ip_map.json` on each controller.
407+
408+
`internalapi_cidr`::
409+
Specifies the internalapi subnet in CIDR notation, for example `172.17.0.0/24`.
410+
This is a CIDR range representing the network from which RHOSO designate worker
411+
pods send requests, not individual IP addresses.
412+
413+
+
414+
Reload the BIND9 configuration:
415+
+
416+
----
417+
$ systemctl restart desginate-designatebackendbind9
418+
----
419+
+
420+
[NOTE]
421+
====
422+
423+
Direct edits to the BIND9 configuration are appropriate because the legacy
424+
control plane ({OpenStackPreviousInstaller}) is being decommissioned and will
425+
no longer manage these files.
426+
427+
====
428+
429+
. Open the firewall on each legacy controller to allow RNDC and DNS traffic from the {rhos_long} pods:
430+
+
431+
[subs="+quotes"]
432+
----
433+
$ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<internalapi_subnet>" port port="953" protocol="tcp" accept'
434+
$ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<internalapi_subnet>" port port="53" protocol="tcp" accept'
435+
$ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<internalapi_subnet>" port port="53" protocol="udp" accept'
436+
$ firewall-cmd --reload
437+
----
438+
+
439+
where:
440+
441+
`<internalapi_subnet>`::
442+
Specifies the internalapi subnet in CIDR notation, for example `172.17.0.0/24`.
443+
444+
. Create a LoadBalancer service to expose the mDNS service on the internalapi
445+
network so that the legacy BIND9 servers can perform AXFR zone transfers: +
446+
----
447+
$ cat << EOF_CAT > /tmp/designate-external-mdns-svc.yaml
448+
apiVersion: v1
449+
kind: Service
450+
metadata:
451+
namespace: openstack
452+
name: designate-external-master
453+
labels:
454+
service: designate-mdns
455+
designate.openstack.org/external_master: "true"
456+
annotations:
457+
core.openstack.org/ingress_create: "false"
458+
metallb.io/ip-allocated-from-pool: internalapi
459+
metallb.universe.tf/address-pool: internalapi
460+
metallb.universe.tf/allow-shared-ip: internalapi
461+
metallb.universe.tf/loadBalancerIPs: 172.17.0.80
462+
designate.openstack.org/external_pool: default
463+
spec:
464+
selector:
465+
service: designate-mdns
466+
ports:
467+
- name: dns-tcp
468+
port: 5354
469+
protocol: TCP
470+
targetPort: 5354
471+
- name: dns
472+
port: 5354
473+
protocol: UDP
474+
targetPort: 5354
475+
ipFamilies:
476+
- IPv4
477+
ipFamilyPolicy: SingleStack
478+
externalTrafficPolicy: Cluster
479+
internalTrafficPolicy: Cluster
480+
type: LoadBalancer
481+
EOF_CAT
482+
$ oc apply -f /tmp/designate-external-mdns-svc.yaml
483+
----
484+
485+
. Patch the {dns_service} CR to reference the external binds secret:
486+
+
487+
----
488+
$ oc patch openstackcontrolplane openstack --type=merge --patch '
489+
spec:
490+
designate:
491+
template:
492+
externalBindsSecret: designate-external-binds
493+
'
494+
----
495+
496+
. Wait for the {dns_service} to reconcile:
497+
+
498+
----
499+
$ oc wait --for condition=Ready --timeout=300s designate.designate.openstack.org/designate
500+
----
501+
502+
. Verify that the external BIND9 targets are included in the pool configuration:
503+
+
504+
----
505+
$ oc get configmap designate-pools-yaml-config-map -o jsonpath='{.data.pools\.yaml}' | grep -A5 'external-bind9'
506+
----
507+
+
508+
The output should list the external BIND9 servers you configured in the external binds secret.
509+
510+
. Verify RNDC connectivity from the designate worker pods to the legacy BIND9 servers:
511+
+
512+
[subs="+quotes"]
513+
----
514+
$ oc exec -it $(oc get pods -l service=designate-worker -o name | head -1) -- \
515+
rndc -s <controller_internalapi_ip> -k /etc/designate/rndc-keys/default-rndc-0 status
516+
----
517+
+
518+
where:
519+
520+
`<controller_internalapi_ip>`::
521+
Specifies the internalapi IP address of a legacy BIND9 server.
522+
+
523+
A successful response indicates that the designate worker can manage the external BIND9 server.
524+
525+
[id="completing-the-bind9-migration_{context}"]
526+
== Completing the BIND9 migration
527+
528+
After external DNS registries and delegations have been updated to reference
529+
the new {rhos_long} nameservers, remove the legacy BIND9 servers from the
530+
{dns_service} pool.
531+
532+
.Procedure
533+
534+
. Remove the external binds secret reference from the {dns_service} CR:
535+
+
536+
----
537+
$ oc patch openstackcontrolplane openstack --type=json --patch '
538+
[{"op": "remove", "path": "/spec/designate/template/externalBindsSecret"}]
539+
'
540+
----
541+
542+
. Wait for the {dns_service} to reconcile:
543+
+
544+
----
545+
$ oc wait --for condition=Ready --timeout=300s designate.designate.openstack.org/designate
546+
----
547+
548+
. Delete the external binds secret:
549+
+
550+
----
551+
$ oc delete secret designate-external-binds -n openstack
552+
----
553+
554+
. Delete the mDNS LoadBalancer service:
555+
+
556+
----
557+
$ oc delete service designate-external-master -n openstack
558+
----
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
designate_adoption: false
2+
designate_external: false
23
designate_retry_delay: 5
4+
designate_external_bind_controllers: []
5+
designate_external_binds: []
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
- name: Extract RNDC credentials from legacy controllers
2+
ansible.builtin.shell: |
3+
{{ shell_header }}
4+
{{ oc_header }}
5+
6+
echo "Extracting BIND9 data from legacy controllers"
7+
binddata_file=/tmp/binddata.yaml
8+
rm -f $binddata_file
9+
for i in {1..3}; do
10+
SSH_CMD=CONTROLLER${i}_SSH
11+
if [ ! -z "${!SSH_CMD}" ]; then
12+
echo "Extracting RNDC credentials from controller $i"
13+
RNDC_SECRET=$(${!SSH_CMD} sudo grep secret /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/"/, "", $2); gsub(/;/, "", $2); print $2}')
14+
RNDC_KEYNAME=$(${!SSH_CMD} sudo grep '^key' /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/"/, "", $2); print $2}' | cut -f 1)
15+
RNDC_ALGORITHM=$(${!SSH_CMD} sudo grep algorithm /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf | awk '{gsub(/;/, "", $2); print $2}')
16+
CONTROLLER_IP=$(${!SSH_CMD} sudo grep 'internal_api\"' /etc/puppet/hieradata/net_ip_map.json | awk '{gsub(/"/, "", $2); gsub(/,/, "", $2); print $2}')
17+
echo "address: $CONTROLLER_IP"
18+
echo "rndcsecret: $RNDC_SECRET"
19+
echo "rndckeyname: $RNDC_KEYNAME"
20+
echo "rndcalgorithm: $RNDC_ALGORITHM"
21+
22+
cat << BINDATACR >> "$binddata_file"
23+
- name: controller-$i
24+
address: $CONTROLLER_IP
25+
rndcsecret: $RNDC_SECRET
26+
rndckeyname: $RNDC_KEYNAME
27+
rndcalgorithm: $RNDC_ALGORITHM
28+
BINDATACR
29+
fi
30+
done
31+
32+
if [ -s "$binddata_file" ]; then
33+
external_binds_secret_file=/tmp/external_binds_secret.yaml
34+
cat << EOSECRETC > "$external_binds_secret_file"
35+
apiVersion: v1
36+
kind: Secret
37+
metadata:
38+
name: designate-external-binds
39+
namespace: openstack
40+
type: Opaque
41+
stringData:
42+
default: |
43+
$(cat "$binddata_file")
44+
EOSECRETC
45+
46+
oc apply -f "$external_binds_secret_file"
47+
fi
48+
49+
- name: Reconfigure Legacy BIND9 instances to talk with Designate on Internal API network.
50+
ansible.builtin.shell: |
51+
{{ shell_header }}
52+
{{ oc_header }}
53+
echo "Configuring BIND9 to integrate via internalapi"
54+
INTERNALAPI_CIDR="{{ internalapi_cidr }}"
55+
for i in {1..3}; do
56+
SSH_CMD=CONTROLLER${i}_SSH
57+
if [ ! -z "${!SSH_CMD}" ]; then
58+
echo "Reconfiguring bind on controller $i"
59+
CONTROLLER_IP=$(${!SSH_CMD} sudo grep 'internal_api\"' /etc/puppet/hieradata/net_ip_map.json | awk '{gsub(/"/, "", $2); gsub(/,/, "", $2); print $2}')
60+
${!SSH_CMD} cp -n /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf.pre-adoption-backup
61+
${!SSH_CMD} "sed -i 's:inet [0-9.]* allow { [0-9./]*; }:inet ${CONTROLLER_IP} allow { ${INTERNALAPI_CIDR}; }:' /var/lib/config-data/ansible-generated/designate/etc/named/rndc.conf"
62+
${!SSH_CMD} cp -n /var/lib/config-data/ansible-generated/designate/etc/named/options.conf /var/lib/config-data/ansible-generated/designate/etc/named/options.conf.pre-adoption-backup
63+
${!SSH_CMD} "sed -i 's:allow.notify.*};:allow-notify { $INTERNALAPI_CIDR; };:' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
64+
${!SSH_CMD} "sed -i '/allow.transfer:/d' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
65+
${!SSH_CMD} "sed '/^options {/,/^};/{
66+
/^};/ i\\\tallow-transfer { '"$INTERNALAPI_CIDR"'; };
67+
}' /var/lib/config-data/ansible-generated/designate/etc/named/options.conf"
68+
echo "Restarting bind on controller $i"
69+
${!SSH_CMD} systemctl restart designate-designatebackendbind9
70+
fi
71+
done
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
- name: Patch Designate CR to reference external binds secret
2+
ansible.builtin.shell: |
3+
{{ shell_header }}
4+
{{ oc_header }}
5+
6+
oc patch openstackcontrolplane openstack --type=merge --patch '
7+
spec:
8+
designate:
9+
template:
10+
externalBindsSecret: designate-external-binds
11+
'
12+
register: designate_external_patch_results
13+
changed_when: true
14+
failed_when: designate_external_patch_results.rc != 0
15+
16+
- name: Wait for the designate service to reconcile after external binds patch
17+
ansible.builtin.shell: |
18+
{{ shell_header }}
19+
{{ oc_header }}
20+
21+
oc wait --for condition=Ready --timeout=300s designates.designate.openstack.org/designate
22+
register: designate_external_ready_result
23+
until: designate_external_ready_result is success
24+
retries: 60
25+
delay: "{{ designate_retry_delay }}"
26+
27+
- name: Verify external BIND9 targets are in pool configuration
28+
ansible.builtin.shell: |
29+
{{ shell_header }}
30+
{{ oc_header }}
31+
32+
oc get configmap designate-pools-yaml-config-map -o jsonpath='{.data.pools\.yaml}' | grep -A5 'external-bind9'
33+
register: external_bind9_pool_check
34+
changed_when: false
35+
failed_when: external_bind9_pool_check.rc != 0

0 commit comments

Comments
 (0)