qontract-reconcile 0.10.1rc1201__py3-none-any.whl → 0.10.2.dev1__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.
Files changed (140) hide show
  1. qontract_reconcile-0.10.2.dev1.dist-info/METADATA +500 -0
  2. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/RECORD +14 -132
  3. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.1rc1201.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/entry_points.txt +1 -0
  5. reconcile/aws_account_manager/README.md +5 -0
  6. reconcile/change_owners/README.md +34 -0
  7. reconcile/external_resources/manager.py +12 -1
  8. reconcile/external_resources/model.py +11 -0
  9. reconcile/glitchtip/README.md +150 -0
  10. reconcile/gql_definitions/introspection.json +51176 -0
  11. reconcile/run_integration.py +293 -0
  12. reconcile/utils/binary.py +2 -2
  13. reconcile/utils/mr/README.md +198 -0
  14. reconcile/utils/oc_map.py +2 -2
  15. tools/qontract_cli.py +0 -0
  16. qontract_reconcile-0.10.1rc1201.dist-info/METADATA +0 -64
  17. qontract_reconcile-0.10.1rc1201.dist-info/top_level.txt +0 -3
  18. reconcile/test/__init__.py +0 -0
  19. reconcile/test/conftest.py +0 -157
  20. reconcile/test/fixtures.py +0 -24
  21. reconcile/test/saas_auto_promotions_manager/__init__.py +0 -0
  22. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -170
  23. reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py +0 -0
  24. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py +0 -0
  25. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -115
  26. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -19
  27. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py +0 -66
  28. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -86
  29. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +0 -352
  30. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +0 -494
  31. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py +0 -0
  32. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -25
  33. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -37
  34. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -81
  35. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -61
  36. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py +0 -74
  37. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -52
  38. reconcile/test/saas_auto_promotions_manager/utils/__init__.py +0 -0
  39. reconcile/test/test_acs_notifiers.py +0 -393
  40. reconcile/test/test_acs_policies.py +0 -497
  41. reconcile/test/test_acs_rbac.py +0 -865
  42. reconcile/test/test_aggregated_list.py +0 -237
  43. reconcile/test/test_amtool.py +0 -37
  44. reconcile/test/test_aws_ami_cleanup.py +0 -230
  45. reconcile/test/test_aws_ami_share.py +0 -68
  46. reconcile/test/test_aws_cloudwatch_log_retention.py +0 -434
  47. reconcile/test/test_aws_iam_keys.py +0 -70
  48. reconcile/test/test_aws_iam_password_reset.py +0 -35
  49. reconcile/test/test_aws_support_cases_sos.py +0 -23
  50. reconcile/test/test_checkpoint.py +0 -178
  51. reconcile/test/test_cli.py +0 -41
  52. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  53. reconcile/test/test_dashdotdb_dora.py +0 -245
  54. reconcile/test/test_database_access_manager.py +0 -660
  55. reconcile/test/test_deadmanssnitch.py +0 -290
  56. reconcile/test/test_gabi_authorized_users.py +0 -72
  57. reconcile/test/test_gcr_mirror.py +0 -14
  58. reconcile/test/test_github_org.py +0 -156
  59. reconcile/test/test_github_repo_invites.py +0 -119
  60. reconcile/test/test_gitlab_housekeeping.py +0 -333
  61. reconcile/test/test_gitlab_labeler.py +0 -126
  62. reconcile/test/test_gitlab_members.py +0 -219
  63. reconcile/test/test_gitlab_permissions.py +0 -164
  64. reconcile/test/test_instrumented_wrappers.py +0 -18
  65. reconcile/test/test_integrations_manager.py +0 -1252
  66. reconcile/test/test_jenkins_worker_fleets.py +0 -57
  67. reconcile/test/test_jira_permissions_validator.py +0 -519
  68. reconcile/test/test_jump_host.py +0 -114
  69. reconcile/test/test_ldap_users.py +0 -125
  70. reconcile/test/test_make.py +0 -28
  71. reconcile/test/test_ocm_additional_routers.py +0 -133
  72. reconcile/test/test_ocm_clusters.py +0 -798
  73. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -87
  74. reconcile/test/test_ocm_machine_pools.py +0 -1103
  75. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  76. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -125
  77. reconcile/test/test_openshift_base.py +0 -1269
  78. reconcile/test/test_openshift_cluster_bots.py +0 -240
  79. reconcile/test/test_openshift_namespace_labels.py +0 -344
  80. reconcile/test/test_openshift_namespaces.py +0 -256
  81. reconcile/test/test_openshift_resource.py +0 -443
  82. reconcile/test/test_openshift_resources_base.py +0 -478
  83. reconcile/test/test_openshift_saas_deploy.py +0 -188
  84. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -308
  85. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +0 -65
  86. reconcile/test/test_openshift_serviceaccount_tokens.py +0 -282
  87. reconcile/test/test_openshift_tekton_resources.py +0 -265
  88. reconcile/test/test_openshift_upgrade_watcher.py +0 -223
  89. reconcile/test/test_prometheus_rules_tester.py +0 -151
  90. reconcile/test/test_quay_membership.py +0 -86
  91. reconcile/test/test_quay_mirror.py +0 -172
  92. reconcile/test/test_quay_mirror_org.py +0 -82
  93. reconcile/test/test_quay_repos.py +0 -59
  94. reconcile/test/test_queries.py +0 -53
  95. reconcile/test/test_repo_owners.py +0 -47
  96. reconcile/test/test_requests_sender.py +0 -139
  97. reconcile/test/test_saasherder.py +0 -1611
  98. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -125
  99. reconcile/test/test_secret_reader.py +0 -153
  100. reconcile/test/test_slack_base.py +0 -183
  101. reconcile/test/test_slack_usergroups.py +0 -785
  102. reconcile/test/test_sql_query.py +0 -316
  103. reconcile/test/test_status_board.py +0 -258
  104. reconcile/test/test_terraform_aws_route53.py +0 -29
  105. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  106. reconcile/test/test_terraform_cloudflare_resources.py +0 -408
  107. reconcile/test/test_terraform_cloudflare_users.py +0 -747
  108. reconcile/test/test_terraform_repo.py +0 -440
  109. reconcile/test/test_terraform_resources.py +0 -519
  110. reconcile/test/test_terraform_tgw_attachments.py +0 -1295
  111. reconcile/test/test_terraform_users.py +0 -152
  112. reconcile/test/test_terraform_vpc_peerings.py +0 -576
  113. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1434
  114. reconcile/test/test_three_way_diff_strategy.py +0 -131
  115. reconcile/test/test_utils_jinja2.py +0 -130
  116. reconcile/test/test_vault_replication.py +0 -534
  117. reconcile/test/test_vault_utils.py +0 -47
  118. reconcile/test/test_version_bump.py +0 -18
  119. reconcile/test/test_vpc_peerings_validator.py +0 -194
  120. reconcile/test/test_wrong_region.py +0 -78
  121. release/__init__.py +0 -0
  122. release/test_version.py +0 -50
  123. release/version.py +0 -104
  124. tools/cli_commands/test/__init__.py +0 -0
  125. tools/cli_commands/test/conftest.py +0 -332
  126. tools/cli_commands/test/test_aws_cost_report.py +0 -258
  127. tools/cli_commands/test/test_cost_management_api.py +0 -326
  128. tools/cli_commands/test/test_gpg_encrypt.py +0 -235
  129. tools/cli_commands/test/test_openshift_cost_optimization_report.py +0 -255
  130. tools/cli_commands/test/test_openshift_cost_report.py +0 -295
  131. tools/cli_commands/test/test_util.py +0 -70
  132. tools/test/__init__.py +0 -0
  133. tools/test/conftest.py +0 -77
  134. tools/test/test_app_interface_metrics_exporter.py +0 -48
  135. tools/test/test_erv2.py +0 -80
  136. tools/test/test_get_container_images.py +0 -230
  137. tools/test/test_qontract_cli.py +0 -197
  138. tools/test/test_saas_promotion_state.py +0 -187
  139. tools/test/test_sd_app_sre_alert_report.py +0 -74
  140. tools/test/test_sre_checkpoints.py +0 -79
@@ -1,265 +0,0 @@
1
- # Setting ignore[misc] for setters on TstData:
2
- # see https://github.com/python/mypy/issues/9160
3
- # Made this a complete ignore because there are even more errors here that need
4
- # to be addressed, but it was blocking other changes.
5
- # type: ignore
6
-
7
- from copy import deepcopy
8
- from typing import Any
9
- from unittest.mock import (
10
- create_autospec,
11
- patch,
12
- )
13
-
14
- import pytest
15
-
16
- from reconcile import openshift_tekton_resources as otr
17
- from reconcile.queries import PIPELINES_PROVIDERS_QUERY
18
- from reconcile.utils import gql
19
-
20
- from .fixtures import Fixtures
21
-
22
- MODULE = "reconcile.openshift_tekton_resources"
23
-
24
-
25
- class TstUnsupportedGqlQueryError(Exception):
26
- pass
27
-
28
-
29
- class TstData:
30
- """Class to add data to tests in setUp. It will be used by mocks"""
31
-
32
- def __init__(self):
33
- self._providers = []
34
- self._saas_files = []
35
-
36
- @property
37
- def providers(self) -> list[dict[str, Any]]:
38
- return self._providers
39
-
40
- @property
41
- def saas_files(self) -> list[dict[str, Any]]:
42
- return self._saas_files
43
-
44
- @providers.setter
45
- def providers(self, providers: list[dict[str, Any]]) -> None:
46
- if not isinstance(providers, list):
47
- raise TypeError(f"Expecting list, have {type(providers)}")
48
- self._providers = providers
49
-
50
- @saas_files.setter
51
- def saas_files(self, saas_files: list[dict[str, Any]]) -> None:
52
- if not isinstance(saas_files, list):
53
- raise TypeError(f"Expecting list, have {type(saas_files)}")
54
- self._saas_files = saas_files
55
-
56
-
57
- # This was originally written in unittest, hence the use of xunit-style
58
- # setup/teardown methods instead of pytest fixtures.
59
- class TestOpenshiftTektonResources:
60
- @staticmethod
61
- def _test_deploy_resources_in_task(
62
- desired_resources, task_name, deploy_resources
63
- ) -> None:
64
- """Helper method to test if deploy resources have been properly set"""
65
- for dr in desired_resources:
66
- if dr["name"] == task_name:
67
- task = dr["value"].body
68
- for step in task["spec"]["steps"]:
69
- if step["name"] == otr.DEFAULT_DEPLOY_RESOURCES_STEP_NAME:
70
- assert step["computeResources"] == deploy_resources
71
- break
72
-
73
- def mock_gql_get_resource(self, path: str) -> dict[str, str]:
74
- """Mock for GqlApi.get_resources using fixtures"""
75
- content = self.fxt.get(path)
76
- return {
77
- "path": path,
78
- "content": content,
79
- "sha256sum": "",
80
- } # we do not need it for these tests
81
-
82
- def mock_gql_query(self, query: str) -> dict[str, Any]:
83
- """Mock for GqlApi.query using test_data set in setUp"""
84
- if query == otr.SAAS_FILES_QUERY:
85
- return {"saas_files": self.test_data.saas_files}
86
- if query == PIPELINES_PROVIDERS_QUERY:
87
- return {"pipelines_providers": self.test_data.providers}
88
- raise TstUnsupportedGqlQueryError("Unsupported query")
89
-
90
- def setup_method(self) -> None:
91
- self.test_data = TstData()
92
-
93
- self.fxt = Fixtures("openshift_tekton_resources")
94
-
95
- # Common fixtures
96
- self.saas1 = self.fxt.get_json("saas1.json")
97
- self.saas2 = self.fxt.get_json("saas2.json")
98
- self.saas2_wr = self.fxt.get_json("saas2-with-resources.json")
99
- self.provider1 = self.fxt.get_json("provider1.json")
100
- self.provider2_wr = self.fxt.get_json("provider2-with-resources.json")
101
-
102
- # Patcher for GqlApi methods
103
- self.gql_patcher = patch.object(gql, "get_api", autospec=True)
104
- self.gql = self.gql_patcher.start()
105
- gqlapi_mock = create_autospec(gql.GqlApi)
106
- self.gql.return_value = gqlapi_mock
107
- gqlapi_mock.query.side_effect = self.mock_gql_query
108
- gqlapi_mock.get_resource.side_effect = self.mock_gql_get_resource
109
-
110
- def teardown_method(self) -> None:
111
- """cleanup patches created in self.setUp"""
112
- self.gql_patcher.stop()
113
-
114
- def test_get_one_saas_file(self) -> None:
115
- self.test_data.saas_files = [self.saas1, self.saas2]
116
- saas_files = otr.fetch_saas_files(self.saas1["name"])
117
- assert saas_files == [self.saas1]
118
-
119
- def test_fetch_tkn_providers(self) -> None:
120
- self.test_data.saas_files = [self.saas1, self.saas2]
121
- self.test_data.providers = [self.provider1, self.provider2_wr]
122
-
123
- tkn_providers = otr.fetch_tkn_providers(None)
124
- keys_expected = {self.provider1["name"], self.provider2_wr["name"]}
125
- assert tkn_providers.keys() == keys_expected
126
-
127
- def test_duplicate_providers(self) -> None:
128
- self.test_data.saas_files = [self.saas1]
129
- provider1_duplicate = deepcopy(self.provider1)
130
- self.test_data.providers = [self.provider1, provider1_duplicate]
131
- msg = r"There are duplicates in tekton providers names: provider1"
132
- with pytest.raises(otr.OpenshiftTektonResourcesBadConfigError, match=msg):
133
- otr.fetch_tkn_providers(None)
134
-
135
- def test_fetch_desired_resources(self) -> None:
136
- self.test_data.saas_files = [self.saas1, self.saas2, self.saas2_wr]
137
- self.test_data.providers = [self.provider1, self.provider2_wr]
138
-
139
- desired_resources = otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
140
-
141
- # we have one task per namespace and a pipeline + task per saas file
142
- assert len(desired_resources) == 8
143
-
144
- def test_fetch_desired_resources_names(self) -> None:
145
- self.test_data.saas_files = [self.saas1]
146
- self.test_data.providers = [self.provider1]
147
- desired_resources = otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
148
-
149
- expected_task_names = {
150
- "o-push-gateway-openshift-saas-deploy-task-status-metric",
151
- "o-openshift-saas-deploy-saas1",
152
- }
153
- expected_pipeline_name = "o-saas-deploy-saas1"
154
-
155
- task_names = set()
156
- for dr in desired_resources:
157
- body = dr["value"].body
158
- if body["kind"] == "Task":
159
- task_names.add(body["metadata"]["name"])
160
- else:
161
- pipeline_name = body["metadata"]["name"]
162
-
163
- assert task_names == expected_task_names
164
- assert pipeline_name == expected_pipeline_name
165
-
166
- def test_set_deploy_resources_default(self) -> None:
167
- self.test_data.saas_files = [self.saas1]
168
- self.test_data.providers = [self.provider1]
169
- desired_resources = otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
170
-
171
- # we need to locate the onePerSaasFile task in the desired resources
172
- # we could be very strict and find the onePerSaasFile task in
173
- # self.provider1 or just use the actual structure of the fixtures
174
- task_name = otr.build_one_per_saas_file_tkn_task_name(
175
- template_name=self.provider1["taskTemplates"][0]["name"],
176
- saas_file_name=self.saas1["name"],
177
- )
178
- self._test_deploy_resources_in_task(
179
- desired_resources, task_name, otr.DEFAULT_DEPLOY_RESOURCES
180
- )
181
-
182
- def test_set_deploy_resources_from_provider(self) -> None:
183
- self.test_data.saas_files = [self.saas2]
184
- self.test_data.providers = [self.provider2_wr]
185
- desired_resources = otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
186
-
187
- task_name = otr.build_one_per_saas_file_tkn_task_name(
188
- template_name=self.provider2_wr["taskTemplates"][0]["name"],
189
- saas_file_name=self.saas2["name"],
190
- )
191
- self._test_deploy_resources_in_task(
192
- desired_resources, task_name, self.provider2_wr["deployResources"]
193
- )
194
-
195
- def test_set_deploy_resources_from_saas_file(self) -> None:
196
- self.test_data.saas_files = [self.saas2_wr]
197
- self.test_data.providers = [self.provider2_wr]
198
- desired_resources = otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
199
-
200
- task_name = otr.build_one_per_saas_file_tkn_task_name(
201
- template_name=self.provider2_wr["taskTemplates"][0]["name"],
202
- saas_file_name=self.saas2["name"],
203
- )
204
- self._test_deploy_resources_in_task(
205
- desired_resources, task_name, self.saas2_wr["deployResources"]
206
- )
207
-
208
- def test_task_templates_name_duplicates(self) -> None:
209
- self.provider4_wtd = self.fxt.get_json("provider4-with-task-duplicates.json")
210
- self.saas4 = self.fxt.get_json("saas4.json")
211
- self.test_data.saas_files = [self.saas4]
212
- self.test_data.providers = [self.provider4_wtd]
213
-
214
- msg = (
215
- r"There are duplicates in task templates names in tekton "
216
- r"provider provider4-with-task-duplicates"
217
- )
218
- with pytest.raises(otr.OpenshiftTektonResourcesBadConfigError, match=msg):
219
- otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
220
-
221
- def test_task_templates_unknown_task(self) -> None:
222
- self.provider5_wut = self.fxt.get_json("provider5-with-unknown-task.json")
223
- self.saas5 = self.fxt.get_json("saas5.json")
224
- self.test_data.saas_files = [self.saas5]
225
- self.test_data.providers = [self.provider5_wut]
226
-
227
- msg = r"Unknown task this-is-an-unknown-task in pipeline template saas-deploy"
228
- with pytest.raises(otr.OpenshiftTektonResourcesBadConfigError, match=msg):
229
- otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
230
-
231
- @patch(f"{MODULE}.DEFAULT_DEPLOY_RESOURCES_STEP_NAME", "unknown-step")
232
- def test_task_templates_unknown_deploy_resources_step(self) -> None:
233
- self.test_data.saas_files = [self.saas1]
234
- self.test_data.providers = [self.provider1]
235
- msg = (
236
- r"Cannot find a step named unknown-step to set resources in "
237
- r"task template openshift-saas-deploy"
238
- )
239
- with pytest.raises(otr.OpenshiftTektonResourcesBadConfigError, match=msg):
240
- otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
241
-
242
- @patch(f"{MODULE}.RESOURCE_MAX_LENGTH", 10)
243
- def test_task_templates_resource_too_long(self) -> None:
244
- self.test_data.saas_files = [self.saas1]
245
- self.test_data.providers = [self.provider1]
246
- msg = (
247
- r"Resource name o-openshift-saas-deploy-saas1 is longer than 10 characters"
248
- )
249
- with pytest.raises(otr.OpenshiftTektonResourcesNameTooLongError, match=msg):
250
- otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
251
-
252
- # This test describes a situation that should not take place in current app-interface since
253
- # pipeline names are limited to 15 characters. But just in case, the code protects us from
254
- # this situation to happen, hence the test.
255
- def test_pipeline_templates_resource_too_long(self) -> None:
256
- self.provider6_tlpn = self.fxt.get_json("provider6-too-long-pipeline-name.yaml")
257
- self.saas6_39cn = self.fxt.get_json("saas6-39-chars-name.yaml")
258
- self.test_data.saas_files = [self.saas6_39cn]
259
- self.test_data.providers = [self.provider6_tlpn]
260
- msg = (
261
- r"Pipeline name o-saas-deploy-too-long-name-this-is-a-saas-file-with-a-39-char-name "
262
- r"is longer than 56 characters"
263
- )
264
- with pytest.raises(otr.OpenshiftTektonResourcesNameTooLongError, match=msg):
265
- otr.fetch_desired_resources(otr.fetch_tkn_providers(None))
@@ -1,223 +0,0 @@
1
- from datetime import (
2
- datetime,
3
- timedelta,
4
- )
5
-
6
- import pytest
7
-
8
- from reconcile import openshift_upgrade_watcher as ouw
9
- from reconcile.gql_definitions.common.clusters import ClusterV1
10
- from reconcile.test.fixtures import Fixtures
11
- from reconcile.utils.models import data_default_none
12
-
13
- fxt = Fixtures("openshift_upgrade_watcher")
14
-
15
-
16
- def load_cluster(path: str) -> ClusterV1:
17
- content = fxt.get_anymarkup(path)
18
- return ClusterV1(**data_default_none(ClusterV1, content))
19
-
20
-
21
- @pytest.fixture
22
- def state(mocker):
23
- return mocker.patch("reconcile.utils.state.State", autospec=True).return_value
24
-
25
-
26
- @pytest.fixture
27
- def slack(mocker):
28
- return mocker.patch(
29
- "reconcile.utils.slack_api.SlackApi", autospec=True
30
- ).return_value
31
-
32
-
33
- cluster_name = "cluster1"
34
- upgrade_at = datetime(2020, 6, 1, 0, 0, 0)
35
- old_version = "4.5.1"
36
- upgrade_version = "4.5.2"
37
-
38
-
39
- @pytest.fixture
40
- def ouw_oc_map(mocker):
41
- map = mocker.patch("reconcile.utils.oc_map.OCMap", autospec=True).return_value
42
- map.clusters.return_value = [cluster_name]
43
- oc = mocker.patch("reconcile.utils.oc.OCNative", autospec=True)
44
- oc.get.return_value = {"items": []}
45
- map.get.return_value = oc
46
- return map
47
-
48
-
49
- @pytest.fixture
50
- def ouw_ocm_map(mocker):
51
- return mocker.patch("reconcile.utils.ocm.OCMMap", autospec=True)
52
-
53
-
54
- @pytest.fixture
55
- def upgrade_config():
56
- return {
57
- "items": [
58
- {
59
- "spec": {
60
- "upgradeAt": upgrade_at.strftime("%Y-%m-%dT%H:%M:%SZ"),
61
- "desired": {"version": upgrade_version},
62
- }
63
- }
64
- ]
65
- }
66
-
67
-
68
- @pytest.fixture
69
- def dt(mocker):
70
- return mocker.patch(
71
- "reconcile.openshift_upgrade_watcher.datetime",
72
- mocker.Mock(datetime, wraps=datetime),
73
- )
74
-
75
-
76
- def test_new_upgrade_pending(
77
- mocker, state, slack, ouw_oc_map, ouw_ocm_map, upgrade_config, dt
78
- ):
79
- """There is an UpgradeConfig on the cluster but its upgradeAt is in the future"""
80
- dt.utcnow.return_value = upgrade_at - timedelta(hours=1)
81
- gso = mocker.patch(
82
- "reconcile.openshift_upgrade_watcher._get_start_osd", autospec=True
83
- )
84
- gso.return_value = upgrade_at.strftime("%Y-%m-%dT%H:%M:%SZ"), upgrade_version
85
- ouw.notify_upgrades_start(
86
- ocm_map=ouw_ocm_map,
87
- oc_map=ouw_oc_map,
88
- clusters=[load_cluster("cluster1.yml")],
89
- state=state,
90
- slack=slack,
91
- )
92
- assert slack.chat_post_message.call_count == 0
93
- assert state.add.call_count == 0
94
-
95
-
96
- def test_new_upgrade_notify(
97
- mocker, state, slack, ouw_oc_map, ouw_ocm_map, upgrade_config, dt
98
- ):
99
- """There is an UpgradeConfig on the cluster, its upgradeAt is in the past,
100
- and we did not already notify"""
101
- dt.utcnow.return_value = upgrade_at + timedelta(hours=1)
102
- gso = mocker.patch(
103
- "reconcile.openshift_upgrade_watcher._get_start_osd", autospec=True
104
- )
105
- gso.return_value = upgrade_at.strftime("%Y-%m-%dT%H:%M:%SZ"), upgrade_version
106
- state.exists.return_value = False
107
- ouw.notify_upgrades_start(
108
- ocm_map=ouw_ocm_map,
109
- oc_map=ouw_oc_map,
110
- clusters=[load_cluster("cluster1.yml")],
111
- state=state,
112
- slack=slack,
113
- )
114
- assert slack.chat_post_message.call_count == 1
115
- assert state.add.call_count == 1
116
-
117
-
118
- def test_new_upgrade_already_notified(
119
- mocker, state, slack, ouw_oc_map, ouw_ocm_map, upgrade_config, dt
120
- ):
121
- """There is an UpgradeConfig on the cluster, its upgradeAt is in the past,
122
- and we already notified"""
123
- state.exists.return_value = True
124
- state.get.return_value = None
125
- dt.utcnow.return_value = upgrade_at + timedelta(hours=1)
126
- gso = mocker.patch(
127
- "reconcile.openshift_upgrade_watcher._get_start_osd", autospec=True
128
- )
129
- gso.return_value = upgrade_at.strftime("%Y-%m-%dT%H:%M:%SZ"), upgrade_version
130
- ouw.notify_upgrades_start(
131
- ocm_map=ouw_ocm_map,
132
- oc_map=ouw_oc_map,
133
- clusters=[load_cluster("cluster1.yml")],
134
- state=state,
135
- slack=slack,
136
- )
137
- assert slack.chat_post_message.call_count == 0
138
- assert state.add.call_count == 0
139
-
140
-
141
- @pytest.fixture
142
- def clusters():
143
- cluster = load_cluster("cluster1.yml")
144
- cluster.name = cluster_name
145
- if not cluster.spec:
146
- raise RuntimeError("This test requires a cluster_spec. Check your fixture.")
147
- cluster.spec.version = upgrade_version
148
- return [cluster]
149
-
150
-
151
- def test_new_version_no_op(mocker, state, slack, clusters):
152
- """We already notified for this cluster & version"""
153
- state.exists.return_value = True
154
- state.get.return_value = upgrade_version # same version, already notified
155
- ouw.notify_cluster_new_version(clusters, state=state, slack=slack)
156
- assert slack.chat_post_message.call_count == 0
157
- assert state.add.call_count == 0
158
-
159
-
160
- def test_new_version_no_state(mocker, state, slack, clusters):
161
- """We never notified for this cluster"""
162
- state.exists.return_value = False # never notified for this cluster
163
- state.get.return_value = None
164
- ouw.notify_cluster_new_version(clusters, state=state, slack=slack)
165
- assert slack.chat_post_message.call_count == 1
166
- assert state.add.call_count == 1
167
-
168
-
169
- def test_new_version_notify(mocker, state, slack, clusters):
170
- """We already notified for this cluster, but on an old version"""
171
- state.exists.return_value = True
172
- state.get.return_value = old_version # different version
173
- ouw.notify_cluster_new_version(clusters, state=state, slack=slack)
174
- assert slack.chat_post_message.call_count == 1
175
- assert state.add.call_count == 1
176
-
177
-
178
- def test__get_start_hypershift_started(mocker):
179
- get_control_plane_upgrade_policies_mock = mocker.patch.object(
180
- ouw, "get_control_plane_upgrade_policies", autospec=True
181
- )
182
- get_control_plane_upgrade_policies_mock.return_value = [
183
- {
184
- "next_run": upgrade_at,
185
- "version": upgrade_version,
186
- "state": "started",
187
- }
188
- ]
189
- ocm_api_mock = mocker.patch(
190
- "reconcile.utils.ocm_base_client.OCMBaseClient", autospec=True
191
- )
192
- next_run, version = ouw._get_start_hypershift(ocm_api_mock, "cluster-id")
193
- assert next_run == upgrade_at
194
- assert version == upgrade_version
195
-
196
-
197
- def test__get_start_hypershift_noop(mocker):
198
- get_control_plane_upgrade_policies_mock = mocker.patch.object(
199
- ouw, "get_control_plane_upgrade_policies", autospec=True
200
- )
201
- get_control_plane_upgrade_policies_mock.return_value = []
202
- ocm_api_mock = mocker.patch(
203
- "reconcile.utils.ocm_base_client.OCMBaseClient", autospec=True
204
- )
205
- next_run, version = ouw._get_start_hypershift(ocm_api_mock, "cluster-id")
206
- assert not next_run
207
- assert not version
208
-
209
-
210
- def test__get_start_osd_no_op(ouw_oc_map):
211
- """There is no UpgradeConfig on the cluster"""
212
- next_run, version = ouw._get_start_osd(ouw_oc_map, cluster_name)
213
- assert not next_run
214
- assert not version
215
-
216
-
217
- def test__get_start_osd_started(ouw_oc_map, upgrade_config):
218
- """There is no UpgradeConfig on the cluster"""
219
- oc = ouw_oc_map.get.return_value
220
- oc.get.return_value = upgrade_config
221
- next_run, version = ouw._get_start_osd(ouw_oc_map, cluster_name)
222
- assert next_run == "2020-06-01T00:00:00Z"
223
- assert version == "4.5.2"
@@ -1,151 +0,0 @@
1
- from typing import Any
2
- from unittest.mock import (
3
- create_autospec,
4
- patch,
5
- )
6
-
7
- import pytest
8
-
9
- from reconcile.gql_definitions.common.app_interface_vault_settings import (
10
- AppInterfaceSettingsV1,
11
- )
12
- from reconcile.openshift_resources_base import NAMESPACES_QUERY
13
- from reconcile.prometheus_rules_tester.integration import Test as PTest
14
- from reconcile.prometheus_rules_tester.integration import (
15
- check_rules_and_tests,
16
- run,
17
- )
18
- from reconcile.status import ExitCodes
19
- from reconcile.utils import gql
20
-
21
- from .fixtures import Fixtures
22
-
23
- THREAD_POOL_SIZE = 2
24
-
25
-
26
- class TstUnsupportedGqlQueryError(Exception):
27
- pass
28
-
29
-
30
- class TestPrometheusRulesTester:
31
- def mock_gql_get_resource(self, path: str) -> dict[str, str]:
32
- """Mock for GqlApi.get_resources using fixtures. Namespace fixtures have paths
33
- that refer to files in fixture dir so that this methos loads them."""
34
- content = self.fxt.get(path)
35
- return {
36
- "path": path,
37
- "content": content,
38
- "sha256sum": "",
39
- }
40
-
41
- def mock_gql_query(self, query: str) -> dict[str, Any]:
42
- """Mock for GqlApi.query using test_data set in setup_method."""
43
- if query == NAMESPACES_QUERY:
44
- return {"namespaces": self.ns_data}
45
-
46
- raise TstUnsupportedGqlQueryError("Unsupported query")
47
-
48
- def setup_method(self) -> None:
49
- self.ns_data: dict[str, Any] = {}
50
-
51
- self.fxt = Fixtures("prometheus_rules_tester")
52
- self.alerting_services = {"yak-shaver"}
53
- self.vault_settings = AppInterfaceSettingsV1(vault=False)
54
-
55
- # Patcher for GqlApi methods
56
- self.gql_patcher = patch.object(gql, "get_api", autospec=True)
57
- self.gql = self.gql_patcher.start()
58
- gqlapi_mock = create_autospec(gql.GqlApi)
59
- self.gql.return_value = gqlapi_mock
60
- gqlapi_mock.query.side_effect = self.mock_gql_query
61
- gqlapi_mock.get_resource.side_effect = self.mock_gql_get_resource
62
-
63
- def teardown_method(self) -> None:
64
- """cleanup patches created in setup_method"""
65
- self.gql_patcher.stop()
66
-
67
- def run_check(self, cluster_name=None) -> list[PTest]:
68
- return check_rules_and_tests(
69
- vault_settings=self.vault_settings,
70
- alerting_services=self.alerting_services,
71
- thread_pool_size=THREAD_POOL_SIZE,
72
- cluster_names=cluster_name,
73
- )
74
-
75
- def test_ok_non_templated(self) -> None:
76
- self.ns_data = self.fxt.get_anymarkup("ns-ok-non-templated.yaml")
77
- assert self.run_check() == []
78
-
79
- def test_ok_templated(self) -> None:
80
- self.ns_data = self.fxt.get_anymarkup("ns-ok-templated.yaml")
81
- assert self.run_check() == []
82
-
83
- # Bad rule syntax should me caught by schema, but since we check it, we test it."
84
- def test_bad_rule(self) -> None:
85
- self.ns_data = self.fxt.get_anymarkup("ns-bad-rule.yaml")
86
- failed = self.run_check()
87
- assert len(failed) == 1
88
- assert "Error running promtool command" in str(failed[0].result)
89
-
90
- def test_bad_alerting_service(self) -> None:
91
- self.ns_data = self.fxt.get_anymarkup("ns-ok-templated.yaml")
92
- self.alerting_services = {"not-a-yak-shaver"}
93
- failed = self.run_check()
94
- assert len(failed) == 1
95
- assert "services are missing from alertingServices" in str(failed[0].result)
96
-
97
- @patch("reconcile.prometheus_rules_tester.integration.MAX_CONFIGMAP_SIZE", 1)
98
- def test_rule_too_long(self) -> None:
99
- self.ns_data = self.fxt.get_anymarkup("ns-ok-non-templated.yaml")
100
- failed = self.run_check()
101
- assert len(failed) == 1
102
- assert "Rules spec is larger than 1 bytes" in str(failed[0].result)
103
-
104
- def test_bad_test(self) -> None:
105
- self.ns_data = self.fxt.get_anymarkup("ns-bad-test.yaml")
106
- failed = self.run_check()
107
- assert len(failed) == 1
108
- assert "Error running promtool command" in str(failed[0].result)
109
-
110
- # Tests regarding filtering by cluster name.
111
- def test_2_ns_bad_alerting_service_unfiltered(self) -> None:
112
- self.ns_data = self.fxt.get_anymarkup("2-ns-ok-non-templated.yaml")
113
- self.alerting_services = {"not-a-yak-shaver"}
114
- assert len(self.run_check()) == 2
115
-
116
- def test_2_ns_bad_alerting_service_filtered(self) -> None:
117
- self.ns_data = self.fxt.get_anymarkup("2-ns-ok-non-templated.yaml")
118
- self.alerting_services = {"not-a-yak-shaver"}
119
-
120
- failed = self.run_check(cluster_name="appint-ex-01")
121
- assert len(failed) == 1
122
-
123
- failed = self.run_check(cluster_name="appint-ex-02")
124
- assert len(failed) == 1
125
-
126
- failed = self.run_check(cluster_name="no-such-cluster")
127
- assert len(failed) == 0
128
-
129
- @patch("reconcile.prometheus_rules_tester.integration.get_alerting_services")
130
- @patch(
131
- "reconcile.prometheus_rules_tester.integration.get_app_interface_vault_settings"
132
- )
133
- def test_run_logs_error(
134
- self, mocker_vault_settings, mocker_alerting_services, caplog
135
- ) -> None:
136
- self.ns_data = self.fxt.get_anymarkup("ns-bad-test.yaml")
137
- mocker_alerting_services.return_value = {"yak-shaver"}
138
- mocker_vault_settings.return_value = AppInterfaceSettingsV1(vault=False)
139
- cluster_name = ("appint-ex-01",)
140
-
141
- with pytest.raises(SystemExit) as exc:
142
- run(False, THREAD_POOL_SIZE, cluster_names=cluster_name)
143
-
144
- assert exc.value.code == ExitCodes.ERROR
145
-
146
- error_msg = (
147
- "Error checking rule bad-test.prometheusrules.yaml "
148
- "from namespace openshift-customer-monitoring in "
149
- f"cluster {cluster_name[0]}: Error running promtool command"
150
- )
151
- assert error_msg in caplog.text