krkn-lib 5.1.11__py3-none-any.whl → 6.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- krkn_lib/aws_tests/__init__.py +1 -1
- krkn_lib/elastic/krkn_elastic.py +3 -1
- krkn_lib/k8s/krkn_kubernetes.py +408 -20
- krkn_lib/k8s/pod_monitor/__init__.py +1 -2
- krkn_lib/k8s/pod_monitor/pod_monitor.py +146 -56
- krkn_lib/k8s/templates/snapshot.j2 +10 -0
- krkn_lib/models/elastic/models.py +24 -1
- krkn_lib/models/k8s/models.py +1 -1
- krkn_lib/models/pod_monitor/models.py +2 -2
- krkn_lib/models/telemetry/models.py +9 -0
- krkn_lib/ocp/krkn_openshift.py +4 -4
- krkn_lib/prometheus/krkn_prometheus.py +1 -1
- krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +1 -1
- krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +1 -1
- krkn_lib/tests/base_test.py +16 -3
- krkn_lib/tests/test_krkn_elastic_models.py +23 -4
- krkn_lib/tests/test_krkn_kubernetes_check.py +3 -2
- krkn_lib/tests/test_krkn_kubernetes_create.py +5 -3
- krkn_lib/tests/test_krkn_kubernetes_delete.py +3 -2
- krkn_lib/tests/test_krkn_kubernetes_get.py +5 -4
- krkn_lib/tests/test_krkn_kubernetes_misc.py +3 -3
- krkn_lib/tests/test_krkn_kubernetes_models.py +1 -1
- krkn_lib/tests/test_krkn_kubernetes_pods_monitor_models.py +3 -4
- krkn_lib/tests/test_krkn_kubernetes_virt.py +735 -0
- krkn_lib/tests/test_krkn_openshift.py +571 -48
- krkn_lib/tests/test_krkn_telemetry_kubernetes.py +848 -0
- krkn_lib/tests/test_safe_logger.py +496 -0
- krkn_lib/tests/test_utils.py +4 -5
- krkn_lib/utils/functions.py +4 -3
- krkn_lib/version/version.py +5 -2
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/METADATA +5 -8
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/RECORD +34 -30
- {krkn_lib-5.1.11.dist-info → krkn_lib-6.0.0.dist-info}/WHEEL +1 -1
- {krkn_lib-5.1.11.dist-info/licenses → krkn_lib-6.0.0.dist-info}/LICENSE +0 -0
|
@@ -1,34 +1,551 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comprehensive tests for KrknOpenshift class.
|
|
3
|
+
|
|
4
|
+
This test suite includes both unit tests (mocked) and integration tests
|
|
5
|
+
(requiring actual testdata or clusters).
|
|
6
|
+
|
|
7
|
+
Unit tests use mocks to test all methods without requiring
|
|
8
|
+
actual OpenShift clusters or external services.
|
|
9
|
+
|
|
10
|
+
Integration tests use BaseTest and require actual testdata files
|
|
11
|
+
or cluster connections.
|
|
12
|
+
|
|
13
|
+
Assisted By: Claude Code
|
|
14
|
+
"""
|
|
15
|
+
|
|
1
16
|
import os
|
|
17
|
+
import tempfile
|
|
18
|
+
import unittest
|
|
2
19
|
from datetime import datetime
|
|
20
|
+
from unittest.mock import Mock, PropertyMock, patch
|
|
3
21
|
|
|
22
|
+
from krkn_lib.ocp.krkn_openshift import KrknOpenshift
|
|
4
23
|
from krkn_lib.tests import BaseTest
|
|
5
24
|
from krkn_lib.utils import SafeLogger
|
|
6
25
|
|
|
26
|
+
# ==============================================================================
|
|
27
|
+
# UNIT TESTS (Mocked - No external dependencies)
|
|
28
|
+
# ==============================================================================
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TestKrknOpenshiftInit(unittest.TestCase):
|
|
32
|
+
"""Test KrknOpenshift initialization."""
|
|
33
|
+
|
|
34
|
+
@patch("krkn_lib.k8s.krkn_kubernetes.config")
|
|
35
|
+
def test_init_with_kubeconfig(self, mock_config):
|
|
36
|
+
"""Test initialization with kubeconfig path."""
|
|
37
|
+
mock_config.load_kube_config = Mock()
|
|
38
|
+
|
|
39
|
+
with tempfile.NamedTemporaryFile(delete=False) as f:
|
|
40
|
+
temp_kubeconfig = f.name
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
ocp = KrknOpenshift(kubeconfig_path=temp_kubeconfig)
|
|
44
|
+
|
|
45
|
+
self.assertIsNotNone(ocp)
|
|
46
|
+
# Should inherit from KrknKubernetes
|
|
47
|
+
self.assertTrue(hasattr(ocp, "api_client"))
|
|
48
|
+
finally:
|
|
49
|
+
if os.path.exists(temp_kubeconfig):
|
|
50
|
+
os.unlink(temp_kubeconfig)
|
|
51
|
+
|
|
52
|
+
@patch("krkn_lib.k8s.krkn_kubernetes.config")
|
|
53
|
+
def test_init_without_kubeconfig(self, mock_config):
|
|
54
|
+
"""Test initialization without kubeconfig path."""
|
|
55
|
+
mock_config.load_kube_config = Mock()
|
|
56
|
+
|
|
57
|
+
ocp = KrknOpenshift()
|
|
58
|
+
|
|
59
|
+
self.assertIsNotNone(ocp)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TestGetClusterversionString(unittest.TestCase):
|
|
63
|
+
"""Test get_clusterversion_string method."""
|
|
64
|
+
|
|
65
|
+
def setUp(self):
|
|
66
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
67
|
+
self.ocp = KrknOpenshift()
|
|
68
|
+
|
|
69
|
+
@patch.object(KrknOpenshift, "_get_clusterversion_string")
|
|
70
|
+
def test_get_clusterversion_string_success(
|
|
71
|
+
self, mock_get_clusterversion_string
|
|
72
|
+
):
|
|
73
|
+
"""Test successful retrieval of clusterversion string."""
|
|
74
|
+
mock_get_clusterversion_string.return_value = "4.13.0"
|
|
75
|
+
|
|
76
|
+
result = self.ocp.get_clusterversion_string()
|
|
77
|
+
|
|
78
|
+
self.assertEqual(result, "4.13.0")
|
|
79
|
+
mock_get_clusterversion_string.assert_called_once()
|
|
80
|
+
|
|
81
|
+
@patch.object(KrknOpenshift, "_get_clusterversion_string")
|
|
82
|
+
def test_get_clusterversion_string_empty(
|
|
83
|
+
self, mock_get_clusterversion_string
|
|
84
|
+
):
|
|
85
|
+
"""Test when clusterversion string is empty."""
|
|
86
|
+
mock_get_clusterversion_string.return_value = ""
|
|
87
|
+
|
|
88
|
+
result = self.ocp.get_clusterversion_string()
|
|
89
|
+
|
|
90
|
+
self.assertEqual(result, "")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class TestIsOpenshift(unittest.TestCase):
|
|
94
|
+
"""Test is_openshift method."""
|
|
95
|
+
|
|
96
|
+
def setUp(self):
|
|
97
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
98
|
+
self.ocp = KrknOpenshift()
|
|
99
|
+
|
|
100
|
+
@patch.object(KrknOpenshift, "_get_clusterversion_string")
|
|
101
|
+
def test_is_openshift_true(self, mock_get_clusterversion_string):
|
|
102
|
+
"""Test is_openshift returns True for OpenShift cluster."""
|
|
103
|
+
mock_get_clusterversion_string.return_value = "4.13.0"
|
|
104
|
+
|
|
105
|
+
result = self.ocp.is_openshift()
|
|
106
|
+
|
|
107
|
+
self.assertTrue(result)
|
|
108
|
+
|
|
109
|
+
@patch.object(KrknOpenshift, "_get_clusterversion_string")
|
|
110
|
+
def test_is_openshift_false_empty(self, mock_get_clusterversion_string):
|
|
111
|
+
"""Test is_openshift returns False when version is empty."""
|
|
112
|
+
mock_get_clusterversion_string.return_value = ""
|
|
113
|
+
|
|
114
|
+
result = self.ocp.is_openshift()
|
|
115
|
+
|
|
116
|
+
self.assertFalse(result)
|
|
117
|
+
|
|
118
|
+
@patch.object(KrknOpenshift, "_get_clusterversion_string")
|
|
119
|
+
def test_is_openshift_false_none(self, mock_get_clusterversion_string):
|
|
120
|
+
"""Test is_openshift returns False when version is None."""
|
|
121
|
+
mock_get_clusterversion_string.return_value = None
|
|
122
|
+
|
|
123
|
+
result = self.ocp.is_openshift()
|
|
124
|
+
|
|
125
|
+
self.assertFalse(result)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TestGetClusterType(unittest.TestCase):
|
|
129
|
+
"""Test get_cluster_type method with PropertyMock."""
|
|
130
|
+
|
|
131
|
+
def setUp(self):
|
|
132
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
133
|
+
self.ocp = KrknOpenshift()
|
|
134
|
+
|
|
135
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
136
|
+
def test_get_cluster_type_rosa(self, mock_api_client_prop):
|
|
137
|
+
"""Test getting ROSA cluster type from resource tags."""
|
|
138
|
+
mock_api_client = Mock()
|
|
139
|
+
|
|
140
|
+
mock_response = (
|
|
141
|
+
str(
|
|
142
|
+
{
|
|
143
|
+
"status": {
|
|
144
|
+
"platform": "AWS",
|
|
145
|
+
"platformStatus": {
|
|
146
|
+
"aws": {
|
|
147
|
+
"region": "us-west-2",
|
|
148
|
+
"resourceTags": [
|
|
149
|
+
{"key": "prowci", "value": "ci-rosa-123"},
|
|
150
|
+
{
|
|
151
|
+
"key": "red-hat-clustertype",
|
|
152
|
+
"value": "rosa",
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
mock_api_client.call_api.return_value = mock_response
|
|
163
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
164
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
165
|
+
|
|
166
|
+
result = self.ocp.get_cluster_type()
|
|
167
|
+
|
|
168
|
+
self.assertEqual(result, "rosa")
|
|
169
|
+
|
|
170
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
171
|
+
def test_get_cluster_type_self_managed(self, mock_api_client_prop):
|
|
172
|
+
"""Test getting self-managed cluster type (no resource tags)."""
|
|
173
|
+
mock_api_client = Mock()
|
|
174
|
+
|
|
175
|
+
mock_response = (
|
|
176
|
+
str(
|
|
177
|
+
{
|
|
178
|
+
"status": {
|
|
179
|
+
"platform": "AWS",
|
|
180
|
+
"platformStatus": {"aws": {"region": "us-west-2"}},
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
mock_api_client.call_api.return_value = mock_response
|
|
187
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
188
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
189
|
+
|
|
190
|
+
result = self.ocp.get_cluster_type()
|
|
191
|
+
|
|
192
|
+
self.assertEqual(result, "self-managed")
|
|
193
|
+
|
|
194
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
195
|
+
def test_get_cluster_type_exception(self, mock_api_client_prop):
|
|
196
|
+
"""Test exception handling returns self-managed."""
|
|
197
|
+
mock_api_client = Mock()
|
|
198
|
+
mock_api_client.call_api.side_effect = Exception("API error")
|
|
199
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
200
|
+
|
|
201
|
+
result = self.ocp.get_cluster_type()
|
|
202
|
+
|
|
203
|
+
self.assertEqual(result, "self-managed")
|
|
204
|
+
|
|
205
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
206
|
+
def test_get_cluster_type_no_api_client(self, mock_api_client_prop):
|
|
207
|
+
"""Test when api_client is None."""
|
|
208
|
+
mock_api_client_prop.return_value = None
|
|
209
|
+
|
|
210
|
+
result = self.ocp.get_cluster_type()
|
|
211
|
+
|
|
212
|
+
self.assertIsNone(result)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class TestGetCloudInfrastructure(unittest.TestCase):
|
|
216
|
+
"""Test get_cloud_infrastructure method."""
|
|
217
|
+
|
|
218
|
+
def setUp(self):
|
|
219
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
220
|
+
self.ocp = KrknOpenshift()
|
|
221
|
+
|
|
222
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
223
|
+
def test_get_cloud_infrastructure_aws(self, mock_api_client_prop):
|
|
224
|
+
"""Test getting AWS infrastructure."""
|
|
225
|
+
mock_api_client = Mock()
|
|
226
|
+
|
|
227
|
+
mock_response = (
|
|
228
|
+
str(
|
|
229
|
+
{
|
|
230
|
+
"status": {
|
|
231
|
+
"platform": "AWS",
|
|
232
|
+
"platformStatus": {"aws": {"region": "us-west-2"}},
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
mock_api_client.call_api.return_value = mock_response
|
|
239
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
240
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
241
|
+
|
|
242
|
+
result = self.ocp.get_cloud_infrastructure()
|
|
243
|
+
|
|
244
|
+
self.assertEqual(result, "AWS")
|
|
245
|
+
|
|
246
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
247
|
+
def test_get_cloud_infrastructure_exception(self, mock_api_client_prop):
|
|
248
|
+
"""Test exception handling returns Unknown."""
|
|
249
|
+
mock_api_client = Mock()
|
|
250
|
+
mock_api_client.call_api.side_effect = Exception("API error")
|
|
251
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
252
|
+
|
|
253
|
+
result = self.ocp.get_cloud_infrastructure()
|
|
254
|
+
|
|
255
|
+
self.assertEqual(result, "Unknown")
|
|
256
|
+
|
|
257
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
258
|
+
def test_get_cloud_infrastructure_no_api_client(
|
|
259
|
+
self, mock_api_client_prop
|
|
260
|
+
):
|
|
261
|
+
"""Test when api_client is None."""
|
|
262
|
+
mock_api_client_prop.return_value = None
|
|
263
|
+
|
|
264
|
+
result = self.ocp.get_cloud_infrastructure()
|
|
265
|
+
|
|
266
|
+
self.assertIsNone(result)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class TestGetClusterNetworkPlugins(unittest.TestCase):
|
|
270
|
+
"""Test get_cluster_network_plugins method."""
|
|
271
|
+
|
|
272
|
+
def setUp(self):
|
|
273
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
274
|
+
self.ocp = KrknOpenshift()
|
|
275
|
+
|
|
276
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
277
|
+
def test_get_cluster_network_plugins_ovn(self, mock_api_client_prop):
|
|
278
|
+
"""Test getting OVNKubernetes network plugin."""
|
|
279
|
+
mock_api_client = Mock()
|
|
280
|
+
|
|
281
|
+
mock_response = (
|
|
282
|
+
str(
|
|
283
|
+
{
|
|
284
|
+
"items": [
|
|
285
|
+
{
|
|
286
|
+
"metadata": {"name": "cluster"},
|
|
287
|
+
"status": {"networkType": "OVNKubernetes"},
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
mock_api_client.call_api.return_value = mock_response
|
|
295
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
296
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
297
|
+
|
|
298
|
+
result = self.ocp.get_cluster_network_plugins()
|
|
299
|
+
|
|
300
|
+
self.assertEqual(result, ["OVNKubernetes"])
|
|
301
|
+
|
|
302
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
303
|
+
def test_get_cluster_network_plugins_exception(self, mock_api_client_prop):
|
|
304
|
+
"""Test exception handling returns Unknown."""
|
|
305
|
+
mock_api_client = Mock()
|
|
306
|
+
mock_api_client.call_api.side_effect = Exception("API error")
|
|
307
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
308
|
+
|
|
309
|
+
result = self.ocp.get_cluster_network_plugins()
|
|
310
|
+
|
|
311
|
+
self.assertEqual(result, ["Unknown"])
|
|
312
|
+
|
|
313
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
314
|
+
def test_get_cluster_network_plugins_no_api_client(
|
|
315
|
+
self, mock_api_client_prop
|
|
316
|
+
):
|
|
317
|
+
"""Test when api_client is None."""
|
|
318
|
+
mock_api_client_prop.return_value = None
|
|
319
|
+
|
|
320
|
+
result = self.ocp.get_cluster_network_plugins()
|
|
321
|
+
|
|
322
|
+
self.assertEqual(result, [])
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class TestGetPrometheusApiConnectionData(unittest.TestCase):
|
|
326
|
+
"""Test get_prometheus_api_connection_data method."""
|
|
327
|
+
|
|
328
|
+
def setUp(self):
|
|
329
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
330
|
+
self.ocp = KrknOpenshift()
|
|
331
|
+
|
|
332
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
333
|
+
@patch.object(KrknOpenshift, "create_token_for_sa")
|
|
334
|
+
def test_get_prometheus_api_connection_data_success(
|
|
335
|
+
self, mock_create_token, mock_api_client_prop
|
|
336
|
+
):
|
|
337
|
+
"""Test successful retrieval of Prometheus connection data."""
|
|
338
|
+
mock_create_token.return_value = "test-token-12345"
|
|
339
|
+
|
|
340
|
+
mock_api_client = Mock()
|
|
341
|
+
host = "prometheus-k8s-openshift-monitoring.apps.cluster.com"
|
|
342
|
+
mock_response = (
|
|
343
|
+
str(
|
|
344
|
+
{
|
|
345
|
+
"items": [
|
|
346
|
+
{
|
|
347
|
+
"metadata": {"name": "prometheus-k8s"},
|
|
348
|
+
"spec": {"host": host},
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
mock_api_client.call_api.return_value = mock_response
|
|
356
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
357
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
358
|
+
|
|
359
|
+
result = self.ocp.get_prometheus_api_connection_data()
|
|
360
|
+
|
|
361
|
+
self.assertIsNotNone(result)
|
|
362
|
+
self.assertEqual(result.token, "test-token-12345")
|
|
363
|
+
self.assertEqual(
|
|
364
|
+
result.endpoint,
|
|
365
|
+
"https://prometheus-k8s-openshift-monitoring.apps.cluster.com",
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
@patch.object(KrknOpenshift, "create_token_for_sa")
|
|
369
|
+
def test_get_prometheus_api_connection_data_no_token(
|
|
370
|
+
self, mock_create_token
|
|
371
|
+
):
|
|
372
|
+
"""Test when token creation fails."""
|
|
373
|
+
mock_create_token.return_value = None
|
|
374
|
+
|
|
375
|
+
result = self.ocp.get_prometheus_api_connection_data()
|
|
376
|
+
|
|
377
|
+
self.assertIsNone(result)
|
|
378
|
+
|
|
379
|
+
@patch.object(KrknOpenshift, "api_client", new_callable=PropertyMock)
|
|
380
|
+
@patch.object(KrknOpenshift, "create_token_for_sa")
|
|
381
|
+
def test_get_prometheus_api_connection_data_route_not_found(
|
|
382
|
+
self, mock_create_token, mock_api_client_prop
|
|
383
|
+
):
|
|
384
|
+
"""Test when prometheus route is not found."""
|
|
385
|
+
mock_create_token.return_value = "test-token-12345"
|
|
386
|
+
|
|
387
|
+
mock_api_client = Mock()
|
|
388
|
+
mock_response = (str({"items": []}),)
|
|
389
|
+
mock_api_client.call_api.return_value = mock_response
|
|
390
|
+
mock_api_client.select_header_accept.return_value = "application/json"
|
|
391
|
+
mock_api_client_prop.return_value = mock_api_client
|
|
392
|
+
|
|
393
|
+
result = self.ocp.get_prometheus_api_connection_data()
|
|
394
|
+
|
|
395
|
+
self.assertIsNone(result)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
class TestCollectFilterArchiveOcpLogs(unittest.TestCase):
|
|
399
|
+
"""Test collect_filter_archive_ocp_logs method."""
|
|
400
|
+
|
|
401
|
+
def setUp(self):
|
|
402
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
403
|
+
self.ocp = KrknOpenshift()
|
|
404
|
+
self.safe_logger = Mock(spec=SafeLogger)
|
|
405
|
+
|
|
406
|
+
@patch("shutil.which")
|
|
407
|
+
def test_collect_filter_archive_ocp_logs_oc_not_found(self, mock_which):
|
|
408
|
+
"""Test when oc command is not found."""
|
|
409
|
+
mock_which.return_value = None
|
|
410
|
+
|
|
411
|
+
result = self.ocp.collect_filter_archive_ocp_logs(
|
|
412
|
+
"/tmp/src",
|
|
413
|
+
"/tmp/dst",
|
|
414
|
+
"/tmp/kubeconfig",
|
|
415
|
+
1234567890,
|
|
416
|
+
1234567900,
|
|
417
|
+
[r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z).+"],
|
|
418
|
+
3,
|
|
419
|
+
self.safe_logger,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
self.assertIsNone(result)
|
|
423
|
+
self.safe_logger.error.assert_called()
|
|
424
|
+
|
|
425
|
+
@patch("os.path.exists")
|
|
426
|
+
@patch("shutil.which")
|
|
427
|
+
def test_collect_filter_archive_ocp_logs_invalid_kubeconfig(
|
|
428
|
+
self, mock_which, mock_exists
|
|
429
|
+
):
|
|
430
|
+
"""Test with invalid kubeconfig path."""
|
|
431
|
+
mock_which.return_value = "/usr/bin/oc"
|
|
432
|
+
|
|
433
|
+
def exists_side_effect(path):
|
|
434
|
+
if "kubeconfig" in path:
|
|
435
|
+
return False
|
|
436
|
+
return True
|
|
437
|
+
|
|
438
|
+
mock_exists.side_effect = exists_side_effect
|
|
439
|
+
|
|
440
|
+
with self.assertRaises(Exception) as context:
|
|
441
|
+
self.ocp.collect_filter_archive_ocp_logs(
|
|
442
|
+
"/tmp/src",
|
|
443
|
+
"/tmp/dst",
|
|
444
|
+
"/tmp/kubeconfig",
|
|
445
|
+
1234567890,
|
|
446
|
+
1234567900,
|
|
447
|
+
[r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z).+"],
|
|
448
|
+
3,
|
|
449
|
+
self.safe_logger,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
self.assertIn("kubeconfig path", str(context.exception))
|
|
453
|
+
|
|
454
|
+
@patch("os.path.expanduser")
|
|
455
|
+
@patch("os.path.exists")
|
|
456
|
+
@patch("shutil.which")
|
|
457
|
+
def test_collect_filter_archive_ocp_logs_expands_tilde(
|
|
458
|
+
self, mock_which, mock_exists, mock_expanduser
|
|
459
|
+
):
|
|
460
|
+
"""Test tilde expansion in paths."""
|
|
461
|
+
mock_which.return_value = "/usr/bin/oc"
|
|
462
|
+
mock_exists.return_value = False
|
|
463
|
+
|
|
464
|
+
def expanduser_side_effect(path):
|
|
465
|
+
return path.replace("~", "/home/user")
|
|
466
|
+
|
|
467
|
+
mock_expanduser.side_effect = expanduser_side_effect
|
|
468
|
+
|
|
469
|
+
with self.assertRaises(Exception):
|
|
470
|
+
self.ocp.collect_filter_archive_ocp_logs(
|
|
471
|
+
"~/src",
|
|
472
|
+
"~/dst",
|
|
473
|
+
"~/kubeconfig",
|
|
474
|
+
1234567890,
|
|
475
|
+
1234567900,
|
|
476
|
+
[r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z).+"],
|
|
477
|
+
3,
|
|
478
|
+
self.safe_logger,
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
# Should have expanded paths
|
|
482
|
+
self.assertTrue(mock_expanduser.called)
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class TestFilterMustGatherOcpLogFolder(unittest.TestCase):
|
|
486
|
+
"""Test filter_must_gather_ocp_log_folder method."""
|
|
487
|
+
|
|
488
|
+
def setUp(self):
|
|
489
|
+
with patch("krkn_lib.k8s.krkn_kubernetes.config"):
|
|
490
|
+
self.ocp = KrknOpenshift()
|
|
491
|
+
|
|
492
|
+
def test_filter_must_gather_ocp_log_folder_dst_not_exists(self):
|
|
493
|
+
"""Test when destination directory doesn't exist."""
|
|
494
|
+
with self.assertRaises(Exception) as context:
|
|
495
|
+
self.ocp.filter_must_gather_ocp_log_folder(
|
|
496
|
+
"src/testdata/must-gather",
|
|
497
|
+
"/nonexistent/dir",
|
|
498
|
+
1234567890,
|
|
499
|
+
1234567900,
|
|
500
|
+
"*.log",
|
|
501
|
+
3,
|
|
502
|
+
[r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z).+"],
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
self.assertIn(
|
|
506
|
+
"Log destination dir do not exist", str(context.exception)
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
# ==============================================================================
|
|
511
|
+
# INTEGRATION TESTS (Require actual testdata or kind cluster connections)
|
|
512
|
+
# ==============================================================================
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
class KrknOpenshiftIntegrationTest(BaseTest):
|
|
516
|
+
"""Integration tests requiring actual cluster connections."""
|
|
7
517
|
|
|
8
|
-
class KrknOpenshiftTest(BaseTest):
|
|
9
518
|
def test_get_cluster_version_string(self):
|
|
10
|
-
|
|
519
|
+
"""Test cluster version string retrieval on real cluster."""
|
|
11
520
|
result = self.lib_ocp.get_clusterversion_string()
|
|
12
521
|
self.assertIsNotNone(result)
|
|
13
522
|
|
|
14
523
|
def test_get_cluster_network_plugins(self):
|
|
524
|
+
"""Test network plugin detection on real cluster."""
|
|
15
525
|
resp = self.lib_ocp.get_cluster_network_plugins()
|
|
16
526
|
self.assertTrue(len(resp) > 0)
|
|
17
527
|
self.assertEqual(resp[0], "Unknown")
|
|
18
528
|
|
|
19
529
|
def test_get_cluster_type(self):
|
|
530
|
+
"""Test cluster type detection on real cluster."""
|
|
20
531
|
resp = self.lib_ocp.get_cluster_type()
|
|
21
532
|
self.assertTrue(resp)
|
|
22
533
|
self.assertEqual(resp, "self-managed")
|
|
23
534
|
|
|
24
535
|
def test_get_cloud_infrastructure(self):
|
|
536
|
+
"""Test cloud infrastructure detection on real cluster."""
|
|
25
537
|
resp = self.lib_ocp.get_cloud_infrastructure()
|
|
26
538
|
self.assertTrue(resp)
|
|
27
539
|
self.assertEqual(resp, "Unknown")
|
|
28
540
|
|
|
541
|
+
def test_is_openshift(self):
|
|
542
|
+
"""Test OpenShift detection on real cluster."""
|
|
543
|
+
self.assertFalse(self.lib_ocp.is_openshift())
|
|
544
|
+
|
|
29
545
|
def test_filter_must_gather_ocp_log_folder(self):
|
|
30
|
-
|
|
31
|
-
#
|
|
546
|
+
"""Test log filtering with actual testdata files."""
|
|
547
|
+
# 1694473200 = 12 Sep 2023 01:00 AM GMT+2
|
|
548
|
+
# 1694476200 = 12 Sep 2023 01:50 AM GMT+2
|
|
32
549
|
filter_patterns = [
|
|
33
550
|
# Sep 9 11:20:36.123425532
|
|
34
551
|
r"(\w{3}\s\d{1,2}\s\d{2}:\d{2}:\d{2}\.\d+).+",
|
|
@@ -39,60 +556,62 @@ class KrknOpenshiftTest(BaseTest):
|
|
|
39
556
|
]
|
|
40
557
|
dst_dir = f"/tmp/filtered_logs.{datetime.now().timestamp()}"
|
|
41
558
|
os.mkdir(dst_dir)
|
|
42
|
-
self.lib_ocp.filter_must_gather_ocp_log_folder(
|
|
43
|
-
"src/testdata/must-gather",
|
|
44
|
-
dst_dir,
|
|
45
|
-
1694473200,
|
|
46
|
-
1694476200,
|
|
47
|
-
"*.log",
|
|
48
|
-
3,
|
|
49
|
-
filter_patterns,
|
|
50
|
-
)
|
|
51
559
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
560
|
+
try:
|
|
561
|
+
self.lib_ocp.filter_must_gather_ocp_log_folder(
|
|
562
|
+
"src/testdata/must-gather",
|
|
563
|
+
dst_dir,
|
|
564
|
+
1694473200,
|
|
565
|
+
1694476200,
|
|
566
|
+
"*.log",
|
|
567
|
+
3,
|
|
568
|
+
filter_patterns,
|
|
569
|
+
)
|
|
59
570
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
571
|
+
test_file_1 = os.path.join(
|
|
572
|
+
dst_dir,
|
|
573
|
+
"namespaces.openshift-monitoring.pods."
|
|
574
|
+
"openshift-state-metrics-"
|
|
575
|
+
"78df59b4d5-mjvhd.openshift-state-metrics."
|
|
576
|
+
"openshift-state-metrics.logs.current.log",
|
|
577
|
+
)
|
|
67
578
|
|
|
68
|
-
|
|
69
|
-
|
|
579
|
+
test_file_2 = os.path.join(
|
|
580
|
+
dst_dir,
|
|
581
|
+
"namespaces.openshift-monitoring.pods.prometheus-"
|
|
582
|
+
"k8s-0.prometheus.prometheus.logs.current.log",
|
|
583
|
+
)
|
|
70
584
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
test_file_1_lines += 1
|
|
585
|
+
self.assertTrue(os.path.exists(test_file_1))
|
|
586
|
+
self.assertTrue(os.path.exists(test_file_2))
|
|
74
587
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
test_file_2_lines += 1
|
|
588
|
+
test_file_1_lines = 0
|
|
589
|
+
test_file_2_lines = 0
|
|
78
590
|
|
|
79
|
-
|
|
80
|
-
|
|
591
|
+
with open(test_file_1) as file:
|
|
592
|
+
for _ in file:
|
|
593
|
+
test_file_1_lines += 1
|
|
81
594
|
|
|
82
|
-
|
|
83
|
-
|
|
595
|
+
with open(test_file_2) as file:
|
|
596
|
+
for _ in file:
|
|
597
|
+
test_file_2_lines += 1
|
|
84
598
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
599
|
+
self.assertEqual(test_file_1_lines, 7)
|
|
600
|
+
self.assertEqual(test_file_2_lines, 4)
|
|
601
|
+
finally:
|
|
602
|
+
# Cleanup temporary directory
|
|
603
|
+
if os.path.exists(dst_dir):
|
|
604
|
+
import shutil
|
|
605
|
+
|
|
606
|
+
shutil.rmtree(dst_dir)
|
|
89
607
|
|
|
90
608
|
def _test_collect_filter_archive_ocp_logs(self):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# we don't have an OCP Integration env yet. #
|
|
94
|
-
##################################################
|
|
609
|
+
"""
|
|
610
|
+
Test full log collection, filtering, and archiving.
|
|
95
611
|
|
|
612
|
+
Note: This test is incomplete and inactive because
|
|
613
|
+
we don't have an OCP integration env yet.
|
|
614
|
+
"""
|
|
96
615
|
base_dir = os.path.join(
|
|
97
616
|
"/tmp", f"log-filter-test.{datetime.now().timestamp()}"
|
|
98
617
|
)
|
|
@@ -114,10 +633,14 @@ class KrknOpenshiftTest(BaseTest):
|
|
|
114
633
|
self.lib_ocp.collect_filter_archive_ocp_logs(
|
|
115
634
|
work_dir,
|
|
116
635
|
dst_dir,
|
|
117
|
-
"/
|
|
636
|
+
"/path/to/kubeconfig", # Update with actual path
|
|
118
637
|
start,
|
|
119
638
|
end,
|
|
120
639
|
filter_patterns,
|
|
121
640
|
5,
|
|
122
641
|
SafeLogger(),
|
|
123
642
|
)
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
if __name__ == "__main__":
|
|
646
|
+
unittest.main()
|