Skip to content
11 changes: 11 additions & 0 deletions .ci/eda_v1alpha1_eda.activation_job_namespace.ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: eda.ansible.com/v1alpha1
kind: EDA
metadata:
name: eda-demo
annotations:
"ansible.sdk.operatorframework.io/verbosity": "5"
spec:
no_log: false
automation_server_url: http://foo.bar
activation_worker:
activation_job_namespace: "eda-jobs"
5 changes: 5 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
- SCENARIO: externaldb
- SCENARIO: ingress
- SCENARIO: event_persistence
- SCENARIO: activation_job_namespace
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand Down Expand Up @@ -68,6 +69,10 @@ jobs:
run: kubectl apply -f .ci/eda-event-stream-external-database.secret.yaml
if: ${{ matrix.SCENARIO == 'externaldb' }}

- name: Create activation job namespace
run: kubectl create namespace eda-jobs
if: ${{ matrix.SCENARIO == 'activation_job_namespace' }}

- name: Create the EDA demo CR
run: |
kubectl apply -f .ci/eda_v1alpha1_eda.${{ matrix.SCENARIO }}.ci.yaml
Expand Down
7 changes: 7 additions & 0 deletions config/crd/bases/eda.ansible.com_edas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2943,6 +2943,13 @@ spec:
activation_worker:
description: Defines desired state of eda-activation-worker resources
properties:
activation_job_namespace:
description: Kubernetes namespace where activation job pods are
created. When set, jobs run in this namespace instead of the
EDA operator namespace. The operator creates the necessary
RBAC to allow the EDA service account to manage resources
in the target namespace.
type: string
node_selector:
additionalProperties:
type: string
Expand Down
43 changes: 43 additions & 0 deletions config/rbac/activation_job_namespace_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# Cluster-scoped because the target namespace is user-configurable at
# runtime via spec.activation_worker.activation_job_namespace. The
# operator must be able to create Role/RoleBinding resources in whatever
# namespace the user specifies.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: eda-activation-job-namespace-manager
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- list
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- bind
- create
- delete
- escalate
- get
- list
- patch
- update
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
Comment thread
coderabbitai[bot] marked this conversation as resolved.
13 changes: 13 additions & 0 deletions config/rbac/activation_job_namespace_role_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: eda-activation-job-namespace-manager-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: eda-activation-job-namespace-manager
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
2 changes: 2 additions & 0 deletions config/rbac/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ resources:
- metrics_auth_role.yaml
- metrics_auth_role_binding.yaml
- metrics_reader_role.yaml
- activation_job_namespace_role.yaml
- activation_job_namespace_role_binding.yaml
1 change: 1 addition & 0 deletions roles/eda/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ _activation_worker:
node_selector: {}
tolerations: []
affinity: {}
activation_job_namespace: ""

# Note: Deprecated "worker: {}" is intentionally excluded here so we know if the user set it
_worker: {}
Expand Down
37 changes: 37 additions & 0 deletions roles/eda/tasks/deploy_eda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,43 @@
event_stream_mtls_base_url: "{{ public_base_url.rstrip('/') }}/{{ event_stream_mtls_prefix_path }}"
when: public_base_url | default('') | length > 0

- name: Look up existing ConfigMap for previous activation_job_namespace
kubernetes.core.k8s_info:
api_version: v1
kind: ConfigMap
namespace: "{{ ansible_operator_meta.namespace }}"
name: "{{ ansible_operator_meta.name }}-{{ deployment_type }}-env-properties"
register: _eda_env_cm

- name: Record previous activation_job_namespace from ConfigMap
ansible.builtin.set_fact:
_previous_activation_job_namespace: >-
{{ (_eda_env_cm.resources | first).data.EDA_ACTIVATION_JOB_NAMESPACE | default('') }}
when:
- _eda_env_cm.resources | length > 0
- (_eda_env_cm.resources | first).data is defined

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Apply cross-namespace RBAC for activation job pods
k8s:
apply: yes
definition: "{{ lookup('template', 'eda-activation-job-namespace-rbac.yaml.j2') }}"
wait: yes
when: combined_activation_worker.activation_job_namespace | default('') | length > 0

- name: Remove cross-namespace RBAC from previous namespace
k8s:
state: absent
api_version: rbac.authorization.k8s.io/v1
kind: "{{ item.kind }}"
name: "{{ ansible_operator_meta.name }}-activation-job-manager"
namespace: "{{ _previous_activation_job_namespace }}"
loop:
- { kind: RoleBinding }
- { kind: Role }
when:
- _previous_activation_job_namespace | default('') | length > 0
- combined_activation_worker.activation_job_namespace | default('') != _previous_activation_job_namespace

- name: Apply ConfigMap resources
k8s:
apply: yes
Expand Down
65 changes: 65 additions & 0 deletions roles/eda/templates/eda-activation-job-namespace-rbac.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# RBAC resources for cross-namespace activation job pods.
# Created when activation_job_namespace is set on the EDA CR.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: '{{ ansible_operator_meta.name }}-activation-job-manager'
namespace: '{{ combined_activation_worker.activation_job_namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(width=4) | trim }}
rules:
- apiGroups:
- ""
resources:
- secrets
- pods
- pods/log
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
Comment thread
coderabbitai[bot] marked this conversation as resolved.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: '{{ ansible_operator_meta.name }}-activation-job-manager'
namespace: '{{ combined_activation_worker.activation_job_namespace }}'
labels:
{{ lookup("template", "../common/templates/labels/common.yaml.j2") | indent(width=4) | trim }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: '{{ ansible_operator_meta.name }}-activation-job-manager'
subjects:
- kind: ServiceAccount
name: '{{ ansible_operator_meta.name }}'
namespace: '{{ ansible_operator_meta.namespace }}'
11 changes: 10 additions & 1 deletion roles/eda/templates/eda-api.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,22 @@ spec:
- protocol: TCP
port: {{ websocket_port }}
# Allow traffic from activation Job pods (created at runtime by activation
# workers, not operator-managed carry only app: eda).
# workers, not operator-managed, carry only app: eda).
# ansible_rulebook connects to daphne (websocket_port) for rulebook
# execution and to the API (api_nginx_port) for token refresh.
- from:
{% if combined_activation_worker.activation_job_namespace | default('') | length > 0 %}
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: '{{ combined_activation_worker.activation_job_namespace }}'
podSelector:
matchLabels:
app: eda
{% else %}
- podSelector:
matchLabels:
app: eda
{% endif %}
ports:
- protocol: TCP
port: {{ websocket_port }}
Expand Down
4 changes: 4 additions & 0 deletions roles/eda/templates/eda.configmap.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ data:
{% endif %}
{% endif %}

{% if combined_activation_worker.activation_job_namespace | default('') | length > 0 %}
EDA_ACTIVATION_JOB_NAMESPACE: "{{ combined_activation_worker.activation_job_namespace }}"
{% endif %}

# Custom user variables
{% for item in extra_settings | default([]) %}
{{ item.setting | upper }}: "{{ item.value }}"
Expand Down
11 changes: 10 additions & 1 deletion roles/postgres/templates/postgres.networkpolicy.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,20 @@ spec:
matchLabels:
control-plane: controller-manager
# EDA activation Job pods (created at runtime by activation workers,
# not operator-managed carry only app: eda, no managed-by label).
# not operator-managed, carry only app: eda, no managed-by label).
# Event stream activations connect to Postgres via pg_notify.
{% if combined_activation_worker.activation_job_namespace | default('') | length > 0 %}
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: '{{ combined_activation_worker.activation_job_namespace }}'
podSelector:
matchLabels:
app: eda
{% else %}
- podSelector:
matchLabels:
app: eda
{% endif %}
ports:
- protocol: TCP
port: {{ eda_postgres_port | default('5432') }}
Expand Down
Loading