qontract-reconcile 0.10.1rc1202__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 (138) hide show
  1. qontract_reconcile-0.10.2.dev1.dist-info/METADATA +500 -0
  2. {qontract_reconcile-0.10.1rc1202.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/RECORD +12 -130
  3. {qontract_reconcile-0.10.1rc1202.dist-info → qontract_reconcile-0.10.2.dev1.dist-info}/WHEEL +1 -2
  4. {qontract_reconcile-0.10.1rc1202.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/glitchtip/README.md +150 -0
  8. reconcile/gql_definitions/introspection.json +51176 -0
  9. reconcile/run_integration.py +293 -0
  10. reconcile/utils/binary.py +2 -2
  11. reconcile/utils/mr/README.md +198 -0
  12. reconcile/utils/oc_map.py +2 -2
  13. tools/qontract_cli.py +0 -0
  14. qontract_reconcile-0.10.1rc1202.dist-info/METADATA +0 -64
  15. qontract_reconcile-0.10.1rc1202.dist-info/top_level.txt +0 -3
  16. reconcile/test/__init__.py +0 -0
  17. reconcile/test/conftest.py +0 -157
  18. reconcile/test/fixtures.py +0 -24
  19. reconcile/test/saas_auto_promotions_manager/__init__.py +0 -0
  20. reconcile/test/saas_auto_promotions_manager/conftest.py +0 -170
  21. reconcile/test/saas_auto_promotions_manager/merge_request_manager/__init__.py +0 -0
  22. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/__init__.py +0 -0
  23. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -115
  24. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -19
  25. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_desired_state.py +0 -66
  26. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -86
  27. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_mr_parser.py +0 -352
  28. reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_reconciler.py +0 -494
  29. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/__init__.py +0 -0
  30. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -25
  31. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -37
  32. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -81
  33. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -61
  34. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_json_path_selector.py +0 -74
  35. reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -52
  36. reconcile/test/saas_auto_promotions_manager/utils/__init__.py +0 -0
  37. reconcile/test/test_acs_notifiers.py +0 -393
  38. reconcile/test/test_acs_policies.py +0 -497
  39. reconcile/test/test_acs_rbac.py +0 -865
  40. reconcile/test/test_aggregated_list.py +0 -237
  41. reconcile/test/test_amtool.py +0 -37
  42. reconcile/test/test_aws_ami_cleanup.py +0 -230
  43. reconcile/test/test_aws_ami_share.py +0 -68
  44. reconcile/test/test_aws_cloudwatch_log_retention.py +0 -434
  45. reconcile/test/test_aws_iam_keys.py +0 -70
  46. reconcile/test/test_aws_iam_password_reset.py +0 -35
  47. reconcile/test/test_aws_support_cases_sos.py +0 -23
  48. reconcile/test/test_checkpoint.py +0 -178
  49. reconcile/test/test_cli.py +0 -41
  50. reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
  51. reconcile/test/test_dashdotdb_dora.py +0 -245
  52. reconcile/test/test_database_access_manager.py +0 -660
  53. reconcile/test/test_deadmanssnitch.py +0 -290
  54. reconcile/test/test_gabi_authorized_users.py +0 -72
  55. reconcile/test/test_gcr_mirror.py +0 -14
  56. reconcile/test/test_github_org.py +0 -156
  57. reconcile/test/test_github_repo_invites.py +0 -119
  58. reconcile/test/test_gitlab_housekeeping.py +0 -333
  59. reconcile/test/test_gitlab_labeler.py +0 -126
  60. reconcile/test/test_gitlab_members.py +0 -219
  61. reconcile/test/test_gitlab_permissions.py +0 -164
  62. reconcile/test/test_instrumented_wrappers.py +0 -18
  63. reconcile/test/test_integrations_manager.py +0 -1252
  64. reconcile/test/test_jenkins_worker_fleets.py +0 -57
  65. reconcile/test/test_jira_permissions_validator.py +0 -519
  66. reconcile/test/test_jump_host.py +0 -114
  67. reconcile/test/test_ldap_users.py +0 -125
  68. reconcile/test/test_make.py +0 -28
  69. reconcile/test/test_ocm_additional_routers.py +0 -133
  70. reconcile/test/test_ocm_clusters.py +0 -798
  71. reconcile/test/test_ocm_clusters_manifest_updates.py +0 -87
  72. reconcile/test/test_ocm_machine_pools.py +0 -1103
  73. reconcile/test/test_ocm_update_recommended_version.py +0 -145
  74. reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -125
  75. reconcile/test/test_openshift_base.py +0 -1269
  76. reconcile/test/test_openshift_cluster_bots.py +0 -240
  77. reconcile/test/test_openshift_namespace_labels.py +0 -344
  78. reconcile/test/test_openshift_namespaces.py +0 -256
  79. reconcile/test/test_openshift_resource.py +0 -443
  80. reconcile/test/test_openshift_resources_base.py +0 -478
  81. reconcile/test/test_openshift_saas_deploy.py +0 -188
  82. reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -308
  83. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +0 -65
  84. reconcile/test/test_openshift_serviceaccount_tokens.py +0 -282
  85. reconcile/test/test_openshift_tekton_resources.py +0 -265
  86. reconcile/test/test_openshift_upgrade_watcher.py +0 -223
  87. reconcile/test/test_prometheus_rules_tester.py +0 -151
  88. reconcile/test/test_quay_membership.py +0 -86
  89. reconcile/test/test_quay_mirror.py +0 -172
  90. reconcile/test/test_quay_mirror_org.py +0 -82
  91. reconcile/test/test_quay_repos.py +0 -59
  92. reconcile/test/test_queries.py +0 -53
  93. reconcile/test/test_repo_owners.py +0 -47
  94. reconcile/test/test_requests_sender.py +0 -139
  95. reconcile/test/test_saasherder.py +0 -1611
  96. reconcile/test/test_saasherder_allowed_secret_paths.py +0 -125
  97. reconcile/test/test_secret_reader.py +0 -153
  98. reconcile/test/test_slack_base.py +0 -183
  99. reconcile/test/test_slack_usergroups.py +0 -785
  100. reconcile/test/test_sql_query.py +0 -316
  101. reconcile/test/test_status_board.py +0 -258
  102. reconcile/test/test_terraform_aws_route53.py +0 -29
  103. reconcile/test/test_terraform_cloudflare_dns.py +0 -117
  104. reconcile/test/test_terraform_cloudflare_resources.py +0 -408
  105. reconcile/test/test_terraform_cloudflare_users.py +0 -747
  106. reconcile/test/test_terraform_repo.py +0 -440
  107. reconcile/test/test_terraform_resources.py +0 -519
  108. reconcile/test/test_terraform_tgw_attachments.py +0 -1295
  109. reconcile/test/test_terraform_users.py +0 -152
  110. reconcile/test/test_terraform_vpc_peerings.py +0 -576
  111. reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1434
  112. reconcile/test/test_three_way_diff_strategy.py +0 -131
  113. reconcile/test/test_utils_jinja2.py +0 -130
  114. reconcile/test/test_vault_replication.py +0 -534
  115. reconcile/test/test_vault_utils.py +0 -47
  116. reconcile/test/test_version_bump.py +0 -18
  117. reconcile/test/test_vpc_peerings_validator.py +0 -194
  118. reconcile/test/test_wrong_region.py +0 -78
  119. release/__init__.py +0 -0
  120. release/test_version.py +0 -50
  121. release/version.py +0 -104
  122. tools/cli_commands/test/__init__.py +0 -0
  123. tools/cli_commands/test/conftest.py +0 -332
  124. tools/cli_commands/test/test_aws_cost_report.py +0 -258
  125. tools/cli_commands/test/test_cost_management_api.py +0 -326
  126. tools/cli_commands/test/test_gpg_encrypt.py +0 -235
  127. tools/cli_commands/test/test_openshift_cost_optimization_report.py +0 -255
  128. tools/cli_commands/test/test_openshift_cost_report.py +0 -295
  129. tools/cli_commands/test/test_util.py +0 -70
  130. tools/test/__init__.py +0 -0
  131. tools/test/conftest.py +0 -77
  132. tools/test/test_app_interface_metrics_exporter.py +0 -48
  133. tools/test/test_erv2.py +0 -80
  134. tools/test/test_get_container_images.py +0 -230
  135. tools/test/test_qontract_cli.py +0 -197
  136. tools/test/test_saas_promotion_state.py +0 -187
  137. tools/test/test_sd_app_sre_alert_report.py +0 -74
  138. 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