Skip to content

Commit 475abf8

Browse files
amasolovcursoragent
andcommitted
feat: support activation job namespace override via env var
Read EDA_ACTIVATION_JOB_NAMESPACE environment variable in _set_namespace() as an override before falling back to the ServiceAccount token namespace file. This allows the eda-server-operator to direct activation job pods into a separate Kubernetes namespace for security isolation, resource quotas, and NetworkPolicy boundaries. Changes: - _set_namespace() checks EDA_ACTIVATION_JOB_NAMESPACE first - Unit tests for override, fallback, whitespace handling, and error case Companion operator PR: ansible/eda-server-operator#345 Signed-off-by: Alexey Masolov <[email protected]> Co-authored-by: Cursor <[email protected]>
1 parent 3680b55 commit 475abf8

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

src/aap_eda/services/activation/engine/kubernetes.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import base64
1616
import json
1717
import logging
18+
import os
1819
from dataclasses import dataclass
1920
from datetime import datetime, timezone
2021

@@ -566,6 +567,15 @@ def _wait_for_pod_to_start(self, log_handler: LogHandler) -> None:
566567
watcher.stop()
567568

568569
def _set_namespace(self) -> None:
570+
ns_override = os.environ.get("EDA_ACTIVATION_JOB_NAMESPACE", "")
571+
if ns_override.strip():
572+
self.namespace = ns_override.strip()
573+
LOGGER.info(
574+
"Using activation job namespace override: %s",
575+
self.namespace,
576+
)
577+
return
578+
569579
namespace_file = (
570580
"/var/run/secrets/kubernetes.io/serviceaccount/namespace"
571581
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Copyright 2026 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
from unittest import mock
17+
18+
import pytest
19+
20+
from aap_eda.services.activation.engine.exceptions import (
21+
ContainerEngineInitError,
22+
)
23+
from aap_eda.services.activation.engine.kubernetes import Engine
24+
25+
26+
@mock.patch.dict("os.environ", {"EDA_ACTIVATION_JOB_NAMESPACE": "eda-jobs"})
27+
def test_set_namespace_env_override():
28+
engine = Engine(
29+
activation_id="1",
30+
resource_prefix="activation",
31+
client=mock.Mock(),
32+
)
33+
assert engine.namespace == "eda-jobs"
34+
35+
36+
@mock.patch.dict(
37+
"os.environ", {"EDA_ACTIVATION_JOB_NAMESPACE": " eda-jobs "}
38+
)
39+
def test_set_namespace_env_override_strips_whitespace():
40+
engine = Engine(
41+
activation_id="1",
42+
resource_prefix="activation",
43+
client=mock.Mock(),
44+
)
45+
assert engine.namespace == "eda-jobs"
46+
47+
48+
@mock.patch.dict("os.environ", {"EDA_ACTIVATION_JOB_NAMESPACE": ""})
49+
def test_set_namespace_empty_env_falls_back_to_file():
50+
with mock.patch("builtins.open", mock.mock_open(read_data="aap-eda")):
51+
engine = Engine(
52+
activation_id="1",
53+
resource_prefix="activation",
54+
client=mock.Mock(),
55+
)
56+
assert engine.namespace == "aap-eda"
57+
58+
59+
def test_set_namespace_unset_env_falls_back_to_file():
60+
env = {
61+
k: v
62+
for k, v in os.environ.items()
63+
if k != "EDA_ACTIVATION_JOB_NAMESPACE"
64+
}
65+
with mock.patch.dict("os.environ", env, clear=True):
66+
with mock.patch(
67+
"builtins.open",
68+
mock.mock_open(read_data="my-namespace"),
69+
):
70+
engine = Engine(
71+
activation_id="1",
72+
resource_prefix="activation",
73+
client=mock.Mock(),
74+
)
75+
assert engine.namespace == "my-namespace"
76+
77+
78+
@mock.patch.dict("os.environ", {"EDA_ACTIVATION_JOB_NAMESPACE": " "})
79+
def test_set_namespace_whitespace_only_env_falls_back_to_file():
80+
with mock.patch("builtins.open", mock.mock_open(read_data="aap-eda")):
81+
engine = Engine(
82+
activation_id="1",
83+
resource_prefix="activation",
84+
client=mock.Mock(),
85+
)
86+
assert engine.namespace == "aap-eda"
87+
88+
89+
def test_set_namespace_no_env_no_file_raises():
90+
with mock.patch.dict("os.environ", {}, clear=True):
91+
with pytest.raises(ContainerEngineInitError):
92+
Engine(
93+
activation_id="1",
94+
resource_prefix="activation",
95+
client=mock.Mock(),
96+
)

0 commit comments

Comments
 (0)