Skip to content

Commit 74abdbd

Browse files
vakwetuclaude
andcommitted
[skmo] Add Skupper for cross-region RabbitMQ and Keystone internal routing
Refactors Skupper integration to use a single generic skupper-listener.yaml (parameterised via extra_vars) and a shared skupper-connector-tasks.yaml included by service-specific connector wrappers. Adds Keystone internal endpoint routing via Skupper so the leaf region can reach the central Keystone over the secure cross-namespace tunnel. Key changes: - skupper-listener.yaml: generic Listener playbook; cifmw_skupper_listener_* extra_vars control name/cert/port/routing-key; cifmw_skupper_listener_enabled flag skips all tasks when false (disabled case). - skupper-connector-tasks.yaml: shared include-file that creates the Skupper Connector CR and waits for Configured status. - skupper-connector.yaml (RabbitMQ): delegates connector create/wait to the shared task file. - skupper-keystone-connector.yaml: sets keystoneInternalURL in skmo-values.yaml via lineinfile before kustomize runs; discovers the Keystone TLS secret from the KeystoneAPI CR; delegates connector create/wait to the shared task file. Uses keystone-internal.openstack.svc.cluster.local (the actual service name). - skupper-keystone-listener.yaml: deleted; functionality merged into the generic skupper-listener.yaml invoked with Keystone-specific extra_vars. - multi-namespace-skmo.yaml: Keystone Listener/Connector hooks moved to pre_stage_run (before OSCP deployment); RabbitMQ Listener hook converted to use the generic skupper-listener.yaml with extra_vars. Signed-off-by: Ade Lee <alee@redhat.com> Co-Authored-By: Claude <noreply@anthropic.com>
1 parent eb82468 commit 74abdbd

9 files changed

Lines changed: 667 additions & 34 deletions
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
# Patch the leaf/workload region OpenStackControlPlane to use the Skupper
3+
# Listener virtual endpoint for internal Keystone authentication traffic.
4+
#
5+
# The public endpoint override is left unchanged so that end-user traffic and
6+
# the Keystone service catalog continue to reference the central region's
7+
# external (public) URL. Only the *internal* override — used for all
8+
# service-to-service communication inside the workload namespace — is updated
9+
# to point at the Skupper Listener.
10+
#
11+
# Run skupper-keystone-connector.yaml and skupper-keystone-listener.yaml
12+
# before this playbook so that the Skupper virtual service is in place.
13+
#
14+
# Variables:
15+
# cifmw_skupper_leaf_namespace (default: openstack2)
16+
# cifmw_skupper_keystone_listener_host (default: keystone-regionone)
17+
# cifmw_skupper_keystone_port (default: 5000)
18+
- name: Configure leaf region to use Skupper Keystone internal endpoint
19+
hosts: localhost
20+
gather_facts: false
21+
vars:
22+
cifmw_skupper_leaf_namespace: openstack2
23+
cifmw_skupper_keystone_listener_host: keystone-regionone
24+
cifmw_skupper_keystone_port: 5000
25+
tasks:
26+
- name: Build the Skupper Keystone internal URL
27+
ansible.builtin.set_fact:
28+
_skupper_keystone_internal_url: >-
29+
https://{{ cifmw_skupper_keystone_listener_host }}.{{ cifmw_skupper_leaf_namespace }}.svc.cluster.local:{{ cifmw_skupper_keystone_port }}
30+
31+
- name: Patch leaf OSCP internal Keystone override to use Skupper endpoint
32+
# This switches the internal keystone endpoint URL from the central
33+
# region's public URL to the Skupper Listener virtual service. The
34+
# public endpoint override is not touched.
35+
kubernetes.core.k8s:
36+
state: patched
37+
api_version: core.openstack.org/v1beta1
38+
kind: OpenStackControlPlane
39+
name: controlplane
40+
namespace: "{{ cifmw_skupper_leaf_namespace }}"
41+
definition:
42+
spec:
43+
keystone:
44+
template:
45+
override:
46+
service:
47+
internal:
48+
endpointURL: "{{ _skupper_keystone_internal_url }}"
49+
50+
- name: Wait for leaf OSCP to reconcile after Keystone endpoint change
51+
kubernetes.core.k8s_info:
52+
api_version: core.openstack.org/v1beta1
53+
kind: OpenStackControlPlane
54+
name: controlplane
55+
namespace: "{{ cifmw_skupper_leaf_namespace }}"
56+
register: _leaf_oscp
57+
retries: 60
58+
delay: 30
59+
until:
60+
- _leaf_oscp.resources | length > 0
61+
- _leaf_oscp.resources[0].status is defined
62+
- _leaf_oscp.resources[0].status.conditions is defined
63+
- _leaf_oscp.resources[0].status.conditions |
64+
selectattr('type', 'equalto', 'Ready') |
65+
selectattr('status', 'equalto', 'True') | list | length > 0
Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,64 @@
11
---
2-
- name: Patch leaf control plane with barbican-keystone-listener transport URL
2+
# Configure the leaf barbican-keystone-listener to use the Skupper
3+
# application network for cross-region RabbitMQ access.
4+
#
5+
# In the leaf region:
6+
# - Read the RabbitMQ credentials from the dedicated user credentials secret
7+
# created by the RabbitMQ operator when the TransportURL CR is reconciled.
8+
# - Patch barbicanKeystoneListener to connect to the central RabbitMQ via the
9+
# Skupper Listener endpoint using those credentials and its own pool_name.
10+
#
11+
# Variables:
12+
# cifmw_skupper_central_namespace (default: openstack)
13+
# cifmw_skupper_leaf_namespace (default: openstack2)
14+
# cifmw_skupper_listener_host (default: rabbitmq-regionone)
15+
# Must match the host set in skupper-listener.yaml.
16+
# cifmw_skupper_rabbitmq_port (default: 5671)
17+
# cifmw_skupper_transport_url_name (default: barbican-keystone-listener-regiontwo)
18+
# Name of the TransportURL CR created in prepare-leaf.yaml. The operator
19+
# creates a user credentials secret named:
20+
# rabbitmq-user-<name>-<username>-user
21+
# cifmw_skupper_transport_url_username (default: barbican-keystone-listener-regiontwo)
22+
# Must match the username field set on the TransportURL CR in prepare-leaf.yaml.
23+
- name: Configure barbican-keystone-listener to use Skupper for cross-region RabbitMQ
324
hosts: localhost
425
gather_facts: false
526
vars:
6-
central_namespace: openstack
7-
leaf_namespace: openstack2
8-
leaf_transport_url_name: rabbitmq-transport-url-barbican-keystone-listener-regiontwo
27+
cifmw_skupper_central_namespace: openstack
28+
cifmw_skupper_leaf_namespace: openstack2
29+
cifmw_skupper_listener_host: rabbitmq-regionone
30+
cifmw_skupper_rabbitmq_port: 5671
31+
cifmw_skupper_transport_url_name: barbican-keystone-listener-regiontwo
32+
cifmw_skupper_transport_url_username: barbican-keystone-listener-regiontwo
933
tasks:
10-
- name: Get transport URL secret from central namespace
34+
- name: Get RabbitMQ user credentials secret for leaf listener
35+
# The RabbitMQ operator creates a secret named
36+
# rabbitmq-user-<transport-url-name>-<username>-user that contains
37+
# the username and password fields for the dedicated RabbitMQ user.
1138
kubernetes.core.k8s_info:
1239
api_version: v1
1340
kind: Secret
14-
namespace: "{{ central_namespace }}"
15-
name: "{{ leaf_transport_url_name }}"
16-
register: _transport_secret
41+
namespace: "{{ cifmw_skupper_central_namespace }}"
42+
name: "rabbitmq-user-{{ cifmw_skupper_transport_url_name }}-{{ cifmw_skupper_transport_url_username }}-user"
43+
register: _rabbitmq_user_secret
1744

18-
- name: Patch OpenStackControlPlane in leaf region with notifications transport_url
45+
- name: Patch leaf barbicanKeystoneListener to use Skupper RabbitMQ endpoint
1946
vars:
20-
_transport_url: "{{ _transport_secret.resources[0].data['transport_url'] | b64decode }}"
47+
_username: "{{ _rabbitmq_user_secret.resources[0].data['username'] | b64decode }}"
48+
_password: "{{ _rabbitmq_user_secret.resources[0].data['password'] | b64decode }}"
2149
kubernetes.core.k8s:
2250
state: patched
2351
api_version: core.openstack.org/v1beta1
2452
kind: OpenStackControlPlane
2553
name: controlplane
26-
namespace: "{{ leaf_namespace }}"
54+
namespace: "{{ cifmw_skupper_leaf_namespace }}"
2755
definition:
2856
spec:
2957
barbican:
3058
template:
3159
barbicanKeystoneListener:
3260
customServiceConfig: |
3361
[DEFAULT]
34-
transport_url = {{ _transport_url }}
62+
transport_url = rabbit://{{ _username }}:{{ _password }}@{{ cifmw_skupper_listener_host }}:{{ cifmw_skupper_rabbitmq_port }}/?ssl=1
3563
[keystone_notifications]
36-
pool_name = barbican-listener-regionTwo
64+
pool_name = barbican-listener-regiontwo

hooks/playbooks/skmo/prepare-leaf.yaml

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
central_rootca_secret: rootca-public
1111
central_rootca_internal_secret: rootca-internal
1212
leaf_transport_url_name: barbican-keystone-listener-regiontwo
13+
leaf_transport_url_username: barbican-keystone-listener-regiontwo
1314
leaf_transport_url_name_secret: rabbitmq-transport-url-barbican-keystone-listener-regiontwo
14-
leaf_transport_url_secret_copy: barbican-keystone-listener-regiontwo-transport
1515
tasks:
1616
- name: Wait for central Keystone API to be ready
1717
kubernetes.core.k8s_info:
@@ -159,6 +159,7 @@
159159
namespace: "{{ central_namespace }}"
160160
spec:
161161
rabbitmqClusterName: rabbitmq
162+
username: "{{ leaf_transport_url_username }}"
162163

163164
- name: Wait for TransportURL to be ready
164165
kubernetes.core.k8s_info:
@@ -176,23 +177,3 @@
176177
- _transport_url_info.resources[0].status.conditions |
177178
selectattr('type', 'equalto', 'Ready') |
178179
selectattr('status', 'equalto', 'True') | list | length > 0
179-
180-
- name: Get transport URL secret from central namespace
181-
kubernetes.core.k8s_info:
182-
api_version: v1
183-
kind: Secret
184-
namespace: "{{ central_namespace }}"
185-
name: "{{ leaf_transport_url_name_secret }}"
186-
register: _transport_secret
187-
188-
- name: Copy transport URL secret to leaf namespace
189-
kubernetes.core.k8s:
190-
state: present
191-
definition:
192-
apiVersion: v1
193-
kind: Secret
194-
metadata:
195-
name: "{{ leaf_transport_url_secret_copy }}"
196-
namespace: "{{ leaf_namespace }}"
197-
type: "{{ _transport_secret.resources[0].type }}"
198-
data: "{{ _transport_secret.resources[0].data }}"
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
# Shared task file: Create a Skupper Connector CR and wait for it to be
3+
# Configured. Include this from service-specific connector playbooks after
4+
# the TLS credentials have been discovered and stored in the variables below.
5+
#
6+
# Expected variables (set via include_tasks vars: block):
7+
# _cifmw_connector_name Skupper Connector CR name
8+
# _cifmw_connector_namespace Namespace for the Connector
9+
# _cifmw_connector_routing_key Skupper routing key (must match Listener)
10+
# _cifmw_connector_host Backend service hostname
11+
# _cifmw_connector_port Backend service port
12+
# _cifmw_connector_tls_credentials Name of the TLS Secret for the backend
13+
# _cifmw_connector_verify_hostname Whether Skupper verifies the backend cert hostname
14+
# _cifmw_connector_ignore_wait_errors Whether to ignore wait failures
15+
16+
- name: Create Skupper Connector
17+
kubernetes.core.k8s:
18+
state: present
19+
definition:
20+
apiVersion: skupper.io/v2alpha1
21+
kind: Connector
22+
metadata:
23+
name: "{{ _cifmw_connector_name }}"
24+
namespace: "{{ _cifmw_connector_namespace }}"
25+
spec:
26+
routingKey: "{{ _cifmw_connector_routing_key }}"
27+
host: "{{ _cifmw_connector_host }}"
28+
port: "{{ _cifmw_connector_port }}"
29+
type: tcp
30+
tlsCredentials: "{{ _cifmw_connector_tls_credentials }}"
31+
verifyHostname: "{{ _cifmw_connector_verify_hostname }}"
32+
33+
- name: Wait for Skupper Connector to be configured
34+
# A Connector shows "Ready" only after a matching Listener is deployed in
35+
# the remote namespace. Waiting for "Configured" is sufficient here.
36+
ignore_errors: "{{ _cifmw_connector_ignore_wait_errors | bool }}"
37+
kubernetes.core.k8s_info:
38+
api_version: skupper.io/v2alpha1
39+
kind: Connector
40+
name: "{{ _cifmw_connector_name }}"
41+
namespace: "{{ _cifmw_connector_namespace }}"
42+
register: _connector
43+
retries: 30
44+
delay: 10
45+
until:
46+
- _connector.resources | length > 0
47+
- _connector.resources[0].status is defined
48+
- _connector.resources[0].status.conditions is defined
49+
- _connector.resources[0].status.conditions |
50+
selectattr('type', 'equalto', 'Configured') |
51+
selectattr('status', 'equalto', 'True') | list | length > 0
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
# Create a Skupper Connector in the central namespace that exposes the central
3+
# RabbitMQ service to workload regions over the Skupper application network.
4+
#
5+
# The TLS Secret name is auto-discovered from the RabbitmqCluster CR.
6+
# Connector creation and the wait for Configured status are handled by the
7+
# shared skupper-connector-tasks.yaml task file.
8+
#
9+
# Variables:
10+
# cifmw_skupper_central_namespace (default: openstack)
11+
# cifmw_skupper_routing_key (default: rabbit-keystone)
12+
# cifmw_skupper_rabbitmq_port (default: 5671)
13+
- name: Create Skupper Connector for central RabbitMQ
14+
hosts: localhost
15+
gather_facts: false
16+
vars:
17+
cifmw_skupper_central_namespace: openstack
18+
cifmw_skupper_routing_key: rabbit-keystone
19+
cifmw_skupper_rabbitmq_port: 5671
20+
tasks:
21+
- name: Get RabbitMQ TLS certificate secret name from RabbitmqCluster CR
22+
kubernetes.core.k8s_info:
23+
api_version: rabbitmq.com/v1beta1
24+
kind: RabbitmqCluster
25+
name: rabbitmq
26+
namespace: "{{ cifmw_skupper_central_namespace }}"
27+
register: _rabbitmq_cluster
28+
29+
- name: Create Skupper Connector and wait for Configured
30+
ansible.builtin.include_tasks: skupper-connector-tasks.yaml
31+
vars:
32+
_cifmw_connector_name: rabbitmq-keystone
33+
_cifmw_connector_namespace: "{{ cifmw_skupper_central_namespace }}"
34+
_cifmw_connector_routing_key: "{{ cifmw_skupper_routing_key }}"
35+
_cifmw_connector_host: "rabbitmq.{{ cifmw_skupper_central_namespace }}.svc.cluster.local"
36+
_cifmw_connector_port: "{{ cifmw_skupper_rabbitmq_port }}"
37+
_cifmw_connector_tls_credentials: "{{ _rabbitmq_cluster.resources[0].spec.tls.secretName }}"
38+
_cifmw_connector_verify_hostname: true
39+
_cifmw_connector_ignore_wait_errors: false
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
# Install the Skupper operator (cluster-scope) on the current cluster.
3+
#
4+
# Variables:
5+
# cifmw_skupper_install_source (default: upstream)
6+
# upstream - apply the upstream install YAML from skupper.io
7+
# downstream - apply a locally-downloaded Red Hat Service Interconnect YAML
8+
# cifmw_skupper_upstream_install_url (default: https://skupper.io/v2/install.yaml)
9+
# cifmw_skupper_downstream_install_file (no default; required when source=downstream)
10+
- name: Install Skupper operator
11+
hosts: localhost
12+
gather_facts: false
13+
vars:
14+
cifmw_skupper_install_source: upstream
15+
cifmw_skupper_upstream_install_url: "https://skupper.io/v2/install.yaml"
16+
cifmw_skupper_downstream_install_file: ""
17+
tasks:
18+
- name: Check if Skupper CRD is already present
19+
kubernetes.core.k8s_info:
20+
api_version: apiextensions.k8s.io/v1
21+
kind: CustomResourceDefinition
22+
name: sites.skupper.io
23+
register: _skupper_crd
24+
25+
- name: Apply upstream Skupper install YAML
26+
when:
27+
- _skupper_crd.resources | length == 0
28+
- cifmw_skupper_install_source == 'upstream'
29+
ansible.builtin.command:
30+
cmd: "oc apply -f {{ cifmw_skupper_upstream_install_url }}"
31+
32+
- name: Apply downstream Skupper install YAML (Red Hat Service Interconnect)
33+
when:
34+
- _skupper_crd.resources | length == 0
35+
- cifmw_skupper_install_source == 'downstream'
36+
ansible.builtin.assert:
37+
that: cifmw_skupper_downstream_install_file | length > 0
38+
fail_msg: >-
39+
cifmw_skupper_downstream_install_file must be set when
40+
cifmw_skupper_install_source is 'downstream'.
41+
42+
- name: Apply downstream install file
43+
when:
44+
- _skupper_crd.resources | length == 0
45+
- cifmw_skupper_install_source == 'downstream'
46+
- cifmw_skupper_downstream_install_file | length > 0
47+
ansible.builtin.command:
48+
cmd: "oc apply -f {{ cifmw_skupper_downstream_install_file }}"
49+
50+
- name: Wait for Skupper controller to be ready
51+
# The upstream install names the deployment "skupper-controller" while the
52+
# downstream Red Hat Service Interconnect install uses
53+
# "skupper-controller-manager". List all Deployments in the namespace and
54+
# wait until at least one is fully ready, regardless of name.
55+
kubernetes.core.k8s_info:
56+
api_version: apps/v1
57+
kind: Deployment
58+
namespace: skupper
59+
register: _skupper_deploy
60+
retries: 30
61+
delay: 10
62+
until:
63+
- _skupper_deploy.resources | length > 0
64+
- _skupper_deploy.resources |
65+
selectattr('status.readyReplicas', 'defined') |
66+
selectattr('status.readyReplicas', 'ge', 1) | list | length > 0

0 commit comments

Comments
 (0)