qontract-reconcile 0.10.2.dev25__py3-none-any.whl → 0.10.2.dev27__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.
- {qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/RECORD +11 -12
- reconcile/cli.py +6 -1
- reconcile/gql_definitions/integrations/integrations.py +1 -37
- reconcile/gql_definitions/introspection.json +0 -121
- reconcile/integrations_manager.py +0 -2
- reconcile/jira_permissions_validator.py +50 -9
- reconcile/utils/github_api.py +8 -5
- reconcile/utils/runtime/sharding.py +0 -64
- reconcile/gql_definitions/sharding/jira_boards.py +0 -60
- {qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev27
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
{qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/RECORD
RENAMED
@@ -10,7 +10,7 @@ reconcile/aws_iam_password_reset.py,sha256=q96mwr2KeEQ5bpNniGlgIMZTxiuLSodcYfX-t
|
|
10
10
|
reconcile/aws_support_cases_sos.py,sha256=hl_9L53yQYRQxKs3IWrd69Cc60XK067g_bJRM9B0udo,2975
|
11
11
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
|
12
12
|
reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
|
13
|
-
reconcile/cli.py,sha256=
|
13
|
+
reconcile/cli.py,sha256=BCfKBc5BRq-9Y5WYe8sUoz9ufOsB1WwMvylx6mBf6CQ,107806
|
14
14
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=MvGKBqH9PdHWdMjhLuptze-dk0Tifhp3-0SZdI-7Fmo,4862
|
15
15
|
reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
|
16
16
|
reconcile/dashdotdb_base.py,sha256=83ZWIf5JJk3P_D69y2TmXRcQr6ELJGlv10OM0h7fJVs,4767
|
@@ -37,7 +37,7 @@ reconcile/gitlab_mr_sqs_consumer.py,sha256=O46mdziPgGOndbU-0_UJKJVUaiEoVzJPEgKm4
|
|
37
37
|
reconcile/gitlab_owners.py,sha256=Y3i-WqXhszLGqGmddt-tJ3OM2b_cViqDs1Ru1P1aQEM,13405
|
38
38
|
reconcile/gitlab_permissions.py,sha256=gSGH6gAdJbPy5Z0rQGUqiNQSHty_tXQ_3Y4OQP_8nFs,8067
|
39
39
|
reconcile/gitlab_projects.py,sha256=K3tFf_aD1W4Ijp5q-9Qek3kwFGEWPcZ1kd7tzFJ4GyQ,1781
|
40
|
-
reconcile/integrations_manager.py,sha256=
|
40
|
+
reconcile/integrations_manager.py,sha256=CY7cOj5dzt2se4IOg11VQvGQ-eTvLML5Q42Z9SSgeSk,9463
|
41
41
|
reconcile/jenkins_base.py,sha256=0Gocu3fU2YTltaxBlbDQOUvP-7CP2OSQV1ZRwtWeVXw,875
|
42
42
|
reconcile/jenkins_job_builder.py,sha256=2aeOSS5pwKJgF4EzoHBWlOYNbzLj3qYzv6u55Qg6MAg,3466
|
43
43
|
reconcile/jenkins_job_builds_cleaner.py,sha256=0iiX0iJiIIter0g9l0l-C6TUvUdVy8O9zFUh7kaYw5w,3865
|
@@ -46,7 +46,7 @@ reconcile/jenkins_roles.py,sha256=HadmoNhgOoKMFZJmCe_Gdg0_a9k_1MuOXidtr801nUU,45
|
|
46
46
|
reconcile/jenkins_webhooks.py,sha256=dzMT1ywXjeAo5sHj-ittW06Ed3beAUPjnc_oCAtD-Rg,2150
|
47
47
|
reconcile/jenkins_webhooks_cleaner.py,sha256=JsN_NVPfZJwv1JtSzZXDIHUqGiefL-DRffFnDGau9aY,1539
|
48
48
|
reconcile/jenkins_worker_fleets.py,sha256=L2wEXpd4xuEHrXGss4iH788nG8UlLSYduZe1EY2IVw4,5377
|
49
|
-
reconcile/jira_permissions_validator.py,sha256=
|
49
|
+
reconcile/jira_permissions_validator.py,sha256=uuwzizb16jTWGctDB0cG0t9l3trDxZuK2SJA-9w7tfA,14872
|
50
50
|
reconcile/jira_watcher.py,sha256=L_UL2MKm2SoIGNsCLThm28pnqCkoFc154JWsD6bURug,3593
|
51
51
|
reconcile/ldap_users.py,sha256=7hdO5CAPl-VNBvDRmKHg13LoblHXXPt7YEKNGomAoGg,3158
|
52
52
|
reconcile/mr_client_gateway.py,sha256=WhjMd-sIXDFCV8-rt8CEjurJ5OYB1pOD0K3o0tZRXQg,1885
|
@@ -215,7 +215,7 @@ reconcile/glitchtip_project_alerts/integration.py,sha256=BgMx-NyV9mTuv7Sotb2OioC
|
|
215
215
|
reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
216
216
|
reconcile/glitchtip_project_dsn/integration.py,sha256=2iugub-kHYkHNK33n0v9_TeWonuxCPah_VkoTPvaajE,8077
|
217
217
|
reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
218
|
-
reconcile/gql_definitions/introspection.json,sha256=
|
218
|
+
reconcile/gql_definitions/introspection.json,sha256=GoGW7nosXPWvZYQsq6m8nYVIJHIO5hBh9upeFhS_M_k,2216702
|
219
219
|
reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
220
220
|
reconcile/gql_definitions/acs/acs_instances.py,sha256=L91WW9LbhJbBSrECqShQpFtjoBOsmNIYLRpMbx1io5o,2181
|
221
221
|
reconcile/gql_definitions/acs/acs_policies.py,sha256=bN5i4mks10Z23KJSj7jqp966Osq2dps4d-sPH9gjxEA,7008
|
@@ -335,7 +335,7 @@ reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=AojrkCDGbVjY0TOk
|
|
335
335
|
reconcile/gql_definitions/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
336
336
|
reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=Pv6RcuIzpNmGc43eEq64nnKG0Dr7H0wjy5Xg1_oRltM,5197
|
337
337
|
reconcile/gql_definitions/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
338
|
-
reconcile/gql_definitions/integrations/integrations.py,sha256=
|
338
|
+
reconcile/gql_definitions/integrations/integrations.py,sha256=HosEgRUlAkxLNoj2cnq3mrTdWDn9UvbNmtz6OcweIYk,11668
|
339
339
|
reconcile/gql_definitions/jenkins_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
340
340
|
reconcile/gql_definitions/jenkins_configs/jenkins_configs.py,sha256=kr1RwKcSpmpBkotl8rR0cOZ02Co5FAbE1he80CCFbTc,2961
|
341
341
|
reconcile/gql_definitions/jenkins_configs/jenkins_instances.py,sha256=b3gYVzQavxeLe4jSM5ZxrO77Vvs7kOljVOXEkTO943U,2165
|
@@ -373,7 +373,6 @@ reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py,sha2
|
|
373
373
|
reconcile/gql_definitions/service_dependencies/service_dependencies.py,sha256=CpMq9KjhFA61yniLo_11ypVInoeMBXbNmcY7_VAep-0,4700
|
374
374
|
reconcile/gql_definitions/sharding/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
375
375
|
reconcile/gql_definitions/sharding/aws_accounts.py,sha256=CtvVUKlS6PfsbInXuhlNwoV4Zmo4uiOc0mwubED8JwQ,1968
|
376
|
-
reconcile/gql_definitions/sharding/jira_boards.py,sha256=yZGLQEQef919UPpy7PWlfusegYv91pByH5jsumXsYuc,1685
|
377
376
|
reconcile/gql_definitions/sharding/ocm_organization.py,sha256=duBIg3531yJ7fWniuHOG6mASgIiKfFIg6mef_lDzwnE,1871
|
378
377
|
reconcile/gql_definitions/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
379
378
|
reconcile/gql_definitions/skupper_network/site_controller_template.py,sha256=MFJTZAO0wRFlRBU4qfXUeQmCKIP4zkmnnCnrvX67FNY,756
|
@@ -581,7 +580,7 @@ reconcile/utils/external_resource_spec.py,sha256=bhH_xneFwATdFumTPkiQmcVKYI0gcaW
|
|
581
580
|
reconcile/utils/external_resources.py,sha256=YzTb0xAcNdmKO326mGQy7BmST56CZcdru4lX7ai_7kw,7579
|
582
581
|
reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,402
|
583
582
|
reconcile/utils/git.py,sha256=wzVIYAeKlMGW538U1mkJWUI6h_mFRUY4lawh2AR8hw4,2345
|
584
|
-
reconcile/utils/github_api.py,sha256=
|
583
|
+
reconcile/utils/github_api.py,sha256=y3fxty7FKvfhdzfHgGSaIstL6A_Y2loUcMiyIK5TMDg,2750
|
585
584
|
reconcile/utils/gitlab_api.py,sha256=SR0graae7UBZyLLKA7yGsOqKm7dXFe5cexcaa1SokQo,28486
|
586
585
|
reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
|
587
586
|
reconcile/utils/gql.py,sha256=C0thIm_k9MBldfqwHzyqtYZk9sIvMdm9IbbnXLGwjD8,14158
|
@@ -719,7 +718,7 @@ reconcile/utils/runtime/environment.py,sha256=h-CFKLK1qRl_gfOVIUwjqVNOmukIPzUG7A
|
|
719
718
|
reconcile/utils/runtime/integration.py,sha256=H3kDfbc4IKrhubSDCWHs0W9oxM7FoCiPaxqA73c9aEs,11101
|
720
719
|
reconcile/utils/runtime/meta.py,sha256=dWdKS9eHVuowFkTK4lgXJ723vS1y9giOMzePUKnHnDI,214
|
721
720
|
reconcile/utils/runtime/runner.py,sha256=I30KRrX1UQbHc_Ir1cIZX3OfNSdoHKdnDSPAEB69Ilk,7944
|
722
|
-
reconcile/utils/runtime/sharding.py,sha256=
|
721
|
+
reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFcnpA_k4,16142
|
723
722
|
reconcile/utils/saasherder/__init__.py,sha256=3U8plqMAPRE1kjwZ5YnIsYsggTf4_gS7flRUEuXVBAs,343
|
724
723
|
reconcile/utils/saasherder/interfaces.py,sha256=C2wrw34OXypshVocAsPrVZsSHptgw4g9u7Haa2wulZQ,9087
|
725
724
|
reconcile/utils/saasherder/models.py,sha256=z8ln03zi2a8cu716NcNUDHp8Dv1VcVbhqdWVxCl7x9A,10148
|
@@ -767,7 +766,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
767
766
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
768
767
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
769
768
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
770
|
-
qontract_reconcile-0.10.2.
|
771
|
-
qontract_reconcile-0.10.2.
|
772
|
-
qontract_reconcile-0.10.2.
|
773
|
-
qontract_reconcile-0.10.2.
|
769
|
+
qontract_reconcile-0.10.2.dev27.dist-info/METADATA,sha256=Nr3x_-2IN6jO8C6UVvoDJmObBt8_Y6OZ54Ok0UsHikA,24665
|
770
|
+
qontract_reconcile-0.10.2.dev27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
771
|
+
qontract_reconcile-0.10.2.dev27.dist-info/entry_points.txt,sha256=JniHZPadNOILPyfSl0LF2YSp3Db7K2_W2CN7i9f3Gos,540
|
772
|
+
qontract_reconcile-0.10.2.dev27.dist-info/RECORD,,
|
reconcile/cli.py
CHANGED
@@ -1158,7 +1158,10 @@ def jenkins_webhooks_cleaner(ctx):
|
|
1158
1158
|
|
1159
1159
|
|
1160
1160
|
@integration.command(short_help="Validate permissions in Jira.")
|
1161
|
-
@click.option(
|
1161
|
+
@click.option(
|
1162
|
+
"--jira-board-name", help="The Jira board to act on.", default=None, multiple=True
|
1163
|
+
)
|
1164
|
+
@click.option("--board-check-interval", help="Check interval in minutes", default=120)
|
1162
1165
|
@enable_extended_early_exit
|
1163
1166
|
@extended_early_exit_cache_ttl_seconds
|
1164
1167
|
@log_cached_log_output
|
@@ -1166,6 +1169,7 @@ def jenkins_webhooks_cleaner(ctx):
|
|
1166
1169
|
def jira_permissions_validator(
|
1167
1170
|
ctx,
|
1168
1171
|
jira_board_name,
|
1172
|
+
board_check_interval,
|
1169
1173
|
enable_extended_early_exit,
|
1170
1174
|
extended_early_exit_cache_ttl_seconds,
|
1171
1175
|
log_cached_log_output,
|
@@ -1176,6 +1180,7 @@ def jira_permissions_validator(
|
|
1176
1180
|
reconcile.jira_permissions_validator,
|
1177
1181
|
ctx.obj,
|
1178
1182
|
jira_board_name=jira_board_name,
|
1183
|
+
board_check_interval=board_check_interval,
|
1179
1184
|
enable_extended_early_exit=enable_extended_early_exit,
|
1180
1185
|
extended_early_exit_cache_ttl_seconds=extended_early_exit_cache_ttl_seconds,
|
1181
1186
|
log_cached_log_output=log_cached_log_output,
|
@@ -191,22 +191,6 @@ query Integrations {
|
|
191
191
|
}
|
192
192
|
}
|
193
193
|
}
|
194
|
-
|
195
|
-
... on JiraBoardSharding_v1 {
|
196
|
-
shardSpecOverrides {
|
197
|
-
shard {
|
198
|
-
name
|
199
|
-
disable {
|
200
|
-
integrations
|
201
|
-
}
|
202
|
-
}
|
203
|
-
imageRef
|
204
|
-
disabled
|
205
|
-
resources {
|
206
|
-
... DeployResourcesFields
|
207
|
-
}
|
208
|
-
}
|
209
|
-
}
|
210
194
|
}
|
211
195
|
}
|
212
196
|
}
|
@@ -358,30 +342,10 @@ class CloudflareDNSZoneShardingV1(IntegrationShardingV1):
|
|
358
342
|
shard_spec_overrides: Optional[list[CloudflareDNSZoneShardSpecOverrideV1]] = Field(..., alias="shardSpecOverrides")
|
359
343
|
|
360
344
|
|
361
|
-
class DisableJiraBoardAutomationsV1(ConfiguredBaseModel):
|
362
|
-
integrations: Optional[list[str]] = Field(..., alias="integrations")
|
363
|
-
|
364
|
-
|
365
|
-
class JiraBoardV1(ConfiguredBaseModel):
|
366
|
-
name: str = Field(..., alias="name")
|
367
|
-
disable: Optional[DisableJiraBoardAutomationsV1] = Field(..., alias="disable")
|
368
|
-
|
369
|
-
|
370
|
-
class JiraBoardShardSpecOverrideV1(ConfiguredBaseModel):
|
371
|
-
shard: JiraBoardV1 = Field(..., alias="shard")
|
372
|
-
image_ref: Optional[str] = Field(..., alias="imageRef")
|
373
|
-
disabled: Optional[bool] = Field(..., alias="disabled")
|
374
|
-
resources: Optional[DeployResourcesFields] = Field(..., alias="resources")
|
375
|
-
|
376
|
-
|
377
|
-
class JiraBoardShardingV1(IntegrationShardingV1):
|
378
|
-
shard_spec_overrides: Optional[list[JiraBoardShardSpecOverrideV1]] = Field(..., alias="shardSpecOverrides")
|
379
|
-
|
380
|
-
|
381
345
|
class IntegrationManagedV1(ConfiguredBaseModel):
|
382
346
|
namespace: NamespaceV1 = Field(..., alias="namespace")
|
383
347
|
spec: IntegrationSpecV1 = Field(..., alias="spec")
|
384
|
-
sharding: Optional[Union[StaticShardingV1, OpenshiftClusterShardingV1, OCMOrganizationShardingV1, AWSAccountShardingV1, CloudflareDNSZoneShardingV1,
|
348
|
+
sharding: Optional[Union[StaticShardingV1, OpenshiftClusterShardingV1, OCMOrganizationShardingV1, AWSAccountShardingV1, CloudflareDNSZoneShardingV1, IntegrationShardingV1]] = Field(..., alias="sharding")
|
385
349
|
|
386
350
|
|
387
351
|
class IntegrationV1(ConfiguredBaseModel):
|
@@ -29766,11 +29766,6 @@
|
|
29766
29766
|
"kind": "OBJECT",
|
29767
29767
|
"name": "AWSAccountSharding_v1",
|
29768
29768
|
"ofType": null
|
29769
|
-
},
|
29770
|
-
{
|
29771
|
-
"kind": "OBJECT",
|
29772
|
-
"name": "JiraBoardSharding_v1",
|
29773
|
-
"ofType": null
|
29774
29769
|
}
|
29775
29770
|
]
|
29776
29771
|
},
|
@@ -49774,122 +49769,6 @@
|
|
49774
49769
|
"enumValues": null,
|
49775
49770
|
"possibleTypes": null
|
49776
49771
|
},
|
49777
|
-
{
|
49778
|
-
"kind": "OBJECT",
|
49779
|
-
"name": "JiraBoardSharding_v1",
|
49780
|
-
"description": null,
|
49781
|
-
"fields": [
|
49782
|
-
{
|
49783
|
-
"name": "strategy",
|
49784
|
-
"description": null,
|
49785
|
-
"args": [],
|
49786
|
-
"type": {
|
49787
|
-
"kind": "NON_NULL",
|
49788
|
-
"name": null,
|
49789
|
-
"ofType": {
|
49790
|
-
"kind": "SCALAR",
|
49791
|
-
"name": "String",
|
49792
|
-
"ofType": null
|
49793
|
-
}
|
49794
|
-
},
|
49795
|
-
"isDeprecated": false,
|
49796
|
-
"deprecationReason": null
|
49797
|
-
},
|
49798
|
-
{
|
49799
|
-
"name": "shardSpecOverrides",
|
49800
|
-
"description": null,
|
49801
|
-
"args": [],
|
49802
|
-
"type": {
|
49803
|
-
"kind": "LIST",
|
49804
|
-
"name": null,
|
49805
|
-
"ofType": {
|
49806
|
-
"kind": "NON_NULL",
|
49807
|
-
"name": null,
|
49808
|
-
"ofType": {
|
49809
|
-
"kind": "OBJECT",
|
49810
|
-
"name": "JiraBoardShardSpecOverride_v1",
|
49811
|
-
"ofType": null
|
49812
|
-
}
|
49813
|
-
}
|
49814
|
-
},
|
49815
|
-
"isDeprecated": false,
|
49816
|
-
"deprecationReason": null
|
49817
|
-
}
|
49818
|
-
],
|
49819
|
-
"inputFields": null,
|
49820
|
-
"interfaces": [
|
49821
|
-
{
|
49822
|
-
"kind": "INTERFACE",
|
49823
|
-
"name": "IntegrationSharding_v1",
|
49824
|
-
"ofType": null
|
49825
|
-
}
|
49826
|
-
],
|
49827
|
-
"enumValues": null,
|
49828
|
-
"possibleTypes": null
|
49829
|
-
},
|
49830
|
-
{
|
49831
|
-
"kind": "OBJECT",
|
49832
|
-
"name": "JiraBoardShardSpecOverride_v1",
|
49833
|
-
"description": null,
|
49834
|
-
"fields": [
|
49835
|
-
{
|
49836
|
-
"name": "shard",
|
49837
|
-
"description": null,
|
49838
|
-
"args": [],
|
49839
|
-
"type": {
|
49840
|
-
"kind": "NON_NULL",
|
49841
|
-
"name": null,
|
49842
|
-
"ofType": {
|
49843
|
-
"kind": "OBJECT",
|
49844
|
-
"name": "JiraBoard_v1",
|
49845
|
-
"ofType": null
|
49846
|
-
}
|
49847
|
-
},
|
49848
|
-
"isDeprecated": false,
|
49849
|
-
"deprecationReason": null
|
49850
|
-
},
|
49851
|
-
{
|
49852
|
-
"name": "imageRef",
|
49853
|
-
"description": null,
|
49854
|
-
"args": [],
|
49855
|
-
"type": {
|
49856
|
-
"kind": "SCALAR",
|
49857
|
-
"name": "String",
|
49858
|
-
"ofType": null
|
49859
|
-
},
|
49860
|
-
"isDeprecated": false,
|
49861
|
-
"deprecationReason": null
|
49862
|
-
},
|
49863
|
-
{
|
49864
|
-
"name": "resources",
|
49865
|
-
"description": null,
|
49866
|
-
"args": [],
|
49867
|
-
"type": {
|
49868
|
-
"kind": "OBJECT",
|
49869
|
-
"name": "DeployResources_v1",
|
49870
|
-
"ofType": null
|
49871
|
-
},
|
49872
|
-
"isDeprecated": false,
|
49873
|
-
"deprecationReason": null
|
49874
|
-
},
|
49875
|
-
{
|
49876
|
-
"name": "disabled",
|
49877
|
-
"description": null,
|
49878
|
-
"args": [],
|
49879
|
-
"type": {
|
49880
|
-
"kind": "SCALAR",
|
49881
|
-
"name": "Boolean",
|
49882
|
-
"ofType": null
|
49883
|
-
},
|
49884
|
-
"isDeprecated": false,
|
49885
|
-
"deprecationReason": null
|
49886
|
-
}
|
49887
|
-
],
|
49888
|
-
"inputFields": null,
|
49889
|
-
"interfaces": [],
|
49890
|
-
"enumValues": null,
|
49891
|
-
"possibleTypes": null
|
49892
|
-
},
|
49893
49772
|
{
|
49894
49773
|
"kind": "OBJECT",
|
49895
49774
|
"name": "StaticSubSharding_v1",
|
@@ -41,7 +41,6 @@ from reconcile.utils.runtime.sharding import (
|
|
41
41
|
AWSAccountShardingStrategy,
|
42
42
|
CloudflareDnsZoneShardingStrategy,
|
43
43
|
IntegrationShardManager,
|
44
|
-
JiraBoardShardingStrategy,
|
45
44
|
OCMOrganizationShardingStrategy,
|
46
45
|
OpenshiftClusterShardingStrategy,
|
47
46
|
ShardSpec,
|
@@ -258,7 +257,6 @@ def run(
|
|
258
257
|
OpenshiftClusterShardingStrategy.IDENTIFIER: OpenshiftClusterShardingStrategy(),
|
259
258
|
CloudflareDnsZoneShardingStrategy.IDENTIFIER: CloudflareDnsZoneShardingStrategy(),
|
260
259
|
OCMOrganizationShardingStrategy.IDENTIFIER: OCMOrganizationShardingStrategy(),
|
261
|
-
JiraBoardShardingStrategy.IDENTIFIER: JiraBoardShardingStrategy(),
|
262
260
|
},
|
263
261
|
integration_runtime_meta=integration_runtime_meta,
|
264
262
|
)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import sys
|
3
|
+
import time
|
3
4
|
from collections.abc import Callable, Iterable
|
4
5
|
from enum import IntFlag, auto
|
5
6
|
from typing import Any, TypedDict
|
@@ -20,18 +21,21 @@ from reconcile.typed_queries.app_interface_vault_settings import (
|
|
20
21
|
from reconcile.typed_queries.jira_settings import get_jira_settings
|
21
22
|
from reconcile.typed_queries.jiralert_settings import get_jiralert_settings
|
22
23
|
from reconcile.utils import gql, metrics
|
24
|
+
from reconcile.utils.defer import defer
|
23
25
|
from reconcile.utils.disabled_integrations import integration_is_enabled
|
24
26
|
from reconcile.utils.extended_early_exit import (
|
25
27
|
ExtendedEarlyExitRunnerResult,
|
26
28
|
extended_early_exit_run,
|
27
29
|
)
|
28
30
|
from reconcile.utils.jira_client import JiraClient, JiraWatcherSettings
|
31
|
+
from reconcile.utils.runtime.integration import DesiredStateShardConfig
|
29
32
|
from reconcile.utils.secret_reader import SecretReaderBase, create_secret_reader
|
30
33
|
from reconcile.utils.semver_helper import make_semver
|
34
|
+
from reconcile.utils.state import State, init_state
|
31
35
|
from reconcile.utils.unleash import get_feature_toggle_state
|
32
36
|
|
33
37
|
QONTRACT_INTEGRATION = "jira-permissions-validator"
|
34
|
-
QONTRACT_INTEGRATION_VERSION = make_semver(1,
|
38
|
+
QONTRACT_INTEGRATION_VERSION = make_semver(1, 2, 0)
|
35
39
|
|
36
40
|
NameToIdMap = dict[str, str]
|
37
41
|
|
@@ -66,6 +70,7 @@ class ValidationError(IntFlag):
|
|
66
70
|
|
67
71
|
class RunnerParams(TypedDict):
|
68
72
|
boards: list[JiraBoardV1]
|
73
|
+
board_check_interval: int
|
69
74
|
dry_run: bool
|
70
75
|
|
71
76
|
|
@@ -201,12 +206,19 @@ def validate_boards(
|
|
201
206
|
jira_boards: Iterable[JiraBoardV1],
|
202
207
|
default_issue_type: str,
|
203
208
|
default_reopen_state: str,
|
209
|
+
board_check_interval: int,
|
204
210
|
dry_run: bool,
|
211
|
+
state: State,
|
205
212
|
jira_client_class: type[JiraClient] = JiraClient,
|
206
213
|
) -> bool:
|
207
214
|
error = False
|
208
215
|
jira_clients: dict[str, JiraClient] = {}
|
209
216
|
for board in jira_boards:
|
217
|
+
last_successful_run = state.get(board.name, 0)
|
218
|
+
if not dry_run and time.time() <= last_successful_run + board_check_interval:
|
219
|
+
logging.debug(f"[{board.name}] Skipping board")
|
220
|
+
continue
|
221
|
+
|
210
222
|
logging.debug(f"[{board.name}] checking ...")
|
211
223
|
if board.server.server_url not in jira_clients:
|
212
224
|
jira_clients[board.server.server_url] = jira_client_class.create(
|
@@ -230,6 +242,9 @@ def validate_boards(
|
|
230
242
|
case 0:
|
231
243
|
# no errors
|
232
244
|
logging.debug(f"[{board.name}] is valid")
|
245
|
+
if not dry_run:
|
246
|
+
# remember time of the last successful run
|
247
|
+
state[board.name] = time.time()
|
233
248
|
case ValidationError.PERMISSION_ERROR:
|
234
249
|
# we don't have all the permissions, but we can create jira tickets
|
235
250
|
metrics_container.set_gauge(
|
@@ -257,13 +272,17 @@ def validate_boards(
|
|
257
272
|
|
258
273
|
|
259
274
|
def get_jira_boards(
|
260
|
-
query_func: Callable,
|
275
|
+
query_func: Callable,
|
276
|
+
jira_board_names: list[str] | None = None,
|
261
277
|
) -> list[JiraBoardV1]:
|
262
278
|
return [
|
263
279
|
board
|
264
280
|
for board in query_jira_boards(query_func=query_func).jira_boards or []
|
265
281
|
if integration_is_enabled(QONTRACT_INTEGRATION, board)
|
266
|
-
and (
|
282
|
+
and (
|
283
|
+
not jira_board_names
|
284
|
+
or board.name.lower() in [name.lower() for name in jira_board_names]
|
285
|
+
)
|
267
286
|
]
|
268
287
|
|
269
288
|
|
@@ -273,16 +292,18 @@ def export_boards(boards: list[JiraBoardV1]) -> list[dict]:
|
|
273
292
|
|
274
293
|
def run(
|
275
294
|
dry_run: bool,
|
276
|
-
jira_board_name: str | None = None,
|
295
|
+
jira_board_name: list[str] | None = None,
|
296
|
+
board_check_interval: int = 3600,
|
277
297
|
enable_extended_early_exit: bool = False,
|
278
298
|
extended_early_exit_cache_ttl_seconds: int = 3600,
|
279
299
|
log_cached_log_output: bool = False,
|
280
300
|
) -> None:
|
281
301
|
gql_api = gql.get_api()
|
282
|
-
boards = get_jira_boards(query_func=gql_api.query,
|
302
|
+
boards = get_jira_boards(query_func=gql_api.query, jira_board_names=jira_board_name)
|
283
303
|
runner_params: RunnerParams = {
|
284
304
|
"boards": boards,
|
285
305
|
"dry_run": dry_run,
|
306
|
+
"board_check_interval": board_check_interval,
|
286
307
|
}
|
287
308
|
if enable_extended_early_exit and get_feature_toggle_state(
|
288
309
|
"jira-permissions-validator-extended-early-exit",
|
@@ -300,7 +321,7 @@ def run(
|
|
300
321
|
# don't use `dry_run` in the cache key because this is a read-only integration
|
301
322
|
dry_run=False,
|
302
323
|
cache_source=cache_source,
|
303
|
-
shard=jira_board_name
|
324
|
+
shard="_".join(set(jira_board_name)) if jira_board_name else "",
|
304
325
|
ttl_seconds=extended_early_exit_cache_ttl_seconds,
|
305
326
|
logger=logging.getLogger(),
|
306
327
|
runner=runner,
|
@@ -312,12 +333,21 @@ def run(
|
|
312
333
|
runner(**runner_params)
|
313
334
|
|
314
335
|
|
315
|
-
|
336
|
+
@defer
|
337
|
+
def runner(
|
338
|
+
boards: list[JiraBoardV1],
|
339
|
+
dry_run: bool,
|
340
|
+
board_check_interval: int,
|
341
|
+
defer: Callable | None = None,
|
342
|
+
) -> ExtendedEarlyExitRunnerResult:
|
316
343
|
gql_api = gql.get_api()
|
317
344
|
settings = get_jira_settings(gql_api=gql_api)
|
318
345
|
jiralert_settings = get_jiralert_settings(query_func=gql_api.query)
|
319
346
|
vault_settings = get_app_interface_vault_settings()
|
320
347
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
348
|
+
state = init_state(integration=QONTRACT_INTEGRATION, secret_reader=secret_reader)
|
349
|
+
if defer:
|
350
|
+
defer(state.cleanup)
|
321
351
|
|
322
352
|
with metrics.transactional_metrics("jira-boards") as metrics_container:
|
323
353
|
error = validate_boards(
|
@@ -327,7 +357,9 @@ def runner(boards: list[JiraBoardV1], dry_run: bool) -> ExtendedEarlyExitRunnerR
|
|
327
357
|
jira_boards=boards,
|
328
358
|
default_issue_type=jiralert_settings.default_issue_type,
|
329
359
|
default_reopen_state=jiralert_settings.default_reopen_state,
|
360
|
+
board_check_interval=board_check_interval,
|
330
361
|
dry_run=dry_run,
|
362
|
+
state=state,
|
331
363
|
)
|
332
364
|
|
333
365
|
if error:
|
@@ -337,13 +369,22 @@ def runner(boards: list[JiraBoardV1], dry_run: bool) -> ExtendedEarlyExitRunnerR
|
|
337
369
|
|
338
370
|
|
339
371
|
def early_exit_desired_state(
|
340
|
-
*args: Any, jira_board_name: str | None = None, **kwargs: Any
|
372
|
+
*args: Any, jira_board_name: list[str] | None = None, **kwargs: Any
|
341
373
|
) -> dict[str, Any]:
|
342
374
|
return {
|
343
375
|
"boards": export_boards(
|
344
376
|
get_jira_boards(
|
345
377
|
query_func=gql.get_api().query,
|
346
|
-
|
378
|
+
jira_board_names=jira_board_name,
|
347
379
|
)
|
348
380
|
)
|
349
381
|
}
|
382
|
+
|
383
|
+
|
384
|
+
def desired_state_shard_config() -> DesiredStateShardConfig:
|
385
|
+
return DesiredStateShardConfig(
|
386
|
+
shard_arg_name="jira_board_name",
|
387
|
+
shard_path_selectors={"boards[*].name"},
|
388
|
+
shard_arg_is_collection=True,
|
389
|
+
sharded_run_review=lambda proposal: len(proposal.proposed_shards) <= 2,
|
390
|
+
)
|
reconcile/utils/github_api.py
CHANGED
@@ -3,11 +3,7 @@ from pathlib import Path
|
|
3
3
|
from types import TracebackType
|
4
4
|
from urllib.parse import urlparse
|
5
5
|
|
6
|
-
from github import
|
7
|
-
Commit,
|
8
|
-
Github,
|
9
|
-
UnknownObjectException,
|
10
|
-
)
|
6
|
+
from github import Commit, Github, GithubException, UnknownObjectException
|
11
7
|
from sretoolbox.utils import retry
|
12
8
|
|
13
9
|
GH_BASE_URL = os.environ.get("GITHUB_API", "https://api.github.com")
|
@@ -75,6 +71,13 @@ class GithubRepositoryApi:
|
|
75
71
|
# -> for now staying backwards compatible
|
76
72
|
return None
|
77
73
|
return content.decoded_content
|
74
|
+
except GithubException as e:
|
75
|
+
# handling a bug in the upstream GH library
|
76
|
+
# https://github.com/PyGithub/PyGithub/issues/3179
|
77
|
+
if e.status == 404:
|
78
|
+
return None
|
79
|
+
else:
|
80
|
+
raise e
|
78
81
|
except UnknownObjectException:
|
79
82
|
return None
|
80
83
|
|
@@ -19,8 +19,6 @@ from reconcile.gql_definitions.integrations.integrations import (
|
|
19
19
|
IntegrationManagedV1,
|
20
20
|
IntegrationShardingV1,
|
21
21
|
IntegrationSpecV1,
|
22
|
-
JiraBoardShardingV1,
|
23
|
-
JiraBoardShardSpecOverrideV1,
|
24
22
|
OCMOrganizationShardingV1,
|
25
23
|
OCMOrganizationShardSpecOverrideV1,
|
26
24
|
OpenshiftClusterShardingV1,
|
@@ -30,7 +28,6 @@ from reconcile.gql_definitions.integrations.integrations import (
|
|
30
28
|
SubShardingV1,
|
31
29
|
)
|
32
30
|
from reconcile.gql_definitions.sharding import aws_accounts as sharding_aws_accounts
|
33
|
-
from reconcile.gql_definitions.sharding import jira_boards as sharding_jira_boards
|
34
31
|
from reconcile.gql_definitions.sharding import (
|
35
32
|
ocm_organization as sharding_ocm_organization,
|
36
33
|
)
|
@@ -437,67 +434,6 @@ class CloudflareDnsZoneShardingStrategy:
|
|
437
434
|
return shards
|
438
435
|
|
439
436
|
|
440
|
-
class JiraBoardShardingStrategy:
|
441
|
-
IDENTIFIER = "per-jira-board"
|
442
|
-
|
443
|
-
def __init__(
|
444
|
-
self,
|
445
|
-
jira_boards: Iterable[sharding_jira_boards.JiraBoardV1] | None = None,
|
446
|
-
):
|
447
|
-
if not jira_boards:
|
448
|
-
self.jira_boards = (
|
449
|
-
sharding_jira_boards.query(query_func=gql.get_api().query).jira_boards
|
450
|
-
or []
|
451
|
-
)
|
452
|
-
else:
|
453
|
-
self.jira_boards = list(jira_boards)
|
454
|
-
|
455
|
-
def get_shard_spec_overrides(
|
456
|
-
self, sharding: IntegrationShardingV1 | None
|
457
|
-
) -> dict[str, JiraBoardShardSpecOverrideV1]:
|
458
|
-
spos: dict[str, JiraBoardShardSpecOverrideV1] = {}
|
459
|
-
|
460
|
-
if isinstance(sharding, JiraBoardShardingV1) and sharding.shard_spec_overrides:
|
461
|
-
for sp in sharding.shard_spec_overrides or []:
|
462
|
-
spos[sp.shard.name] = sp
|
463
|
-
return spos
|
464
|
-
|
465
|
-
def check_integration_sharding_params(self, meta: IntegrationMeta) -> None:
|
466
|
-
if "--jira-board-name" not in meta.args:
|
467
|
-
raise ValueError(
|
468
|
-
f"the integration {meta.name} does not support the required argument "
|
469
|
-
" --jira-board-name for the 'per-jira-board' sharding strategy."
|
470
|
-
)
|
471
|
-
|
472
|
-
def build_shard_spec(
|
473
|
-
self,
|
474
|
-
jira_board: sharding_jira_boards.JiraBoardV1,
|
475
|
-
integration_spec: IntegrationSpecV1,
|
476
|
-
spo: JiraBoardShardSpecOverrideV1 | None,
|
477
|
-
) -> ShardSpec:
|
478
|
-
return ShardSpec(
|
479
|
-
shard_key=jira_board.name,
|
480
|
-
shard_name_suffix=f"-{jira_board.name.lower()}",
|
481
|
-
extra_args=(integration_spec.extra_args or "")
|
482
|
-
+ f" --jira-board-name {jira_board.name}",
|
483
|
-
shard_spec_overrides=spo,
|
484
|
-
)
|
485
|
-
|
486
|
-
def build_integration_shards(
|
487
|
-
self,
|
488
|
-
integration_meta: IntegrationMeta,
|
489
|
-
integration_managed: IntegrationManagedV1,
|
490
|
-
) -> list[ShardSpec]:
|
491
|
-
self.check_integration_sharding_params(integration_meta)
|
492
|
-
spos = self.get_shard_spec_overrides(integration_managed.sharding)
|
493
|
-
shards = []
|
494
|
-
for board in self.jira_boards:
|
495
|
-
spo = spos.get(board.name)
|
496
|
-
base_shard = self.build_shard_spec(board, integration_managed.spec, spo)
|
497
|
-
shards.append(base_shard)
|
498
|
-
return shards
|
499
|
-
|
500
|
-
|
501
437
|
@dataclass
|
502
438
|
class IntegrationShardManager:
|
503
439
|
strategies: dict[str, ShardingStrategy]
|
@@ -1,60 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
|
3
|
-
"""
|
4
|
-
from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
|
5
|
-
from datetime import datetime # noqa: F401 # pylint: disable=W0611
|
6
|
-
from enum import Enum # noqa: F401 # pylint: disable=W0611
|
7
|
-
from typing import ( # noqa: F401 # pylint: disable=W0611
|
8
|
-
Any,
|
9
|
-
Optional,
|
10
|
-
Union,
|
11
|
-
)
|
12
|
-
|
13
|
-
from pydantic import ( # noqa: F401 # pylint: disable=W0611
|
14
|
-
BaseModel,
|
15
|
-
Extra,
|
16
|
-
Field,
|
17
|
-
Json,
|
18
|
-
)
|
19
|
-
|
20
|
-
|
21
|
-
DEFINITION = """
|
22
|
-
query JiraBoardSharding {
|
23
|
-
jira_boards: jira_boards_v1 {
|
24
|
-
name
|
25
|
-
}
|
26
|
-
}
|
27
|
-
"""
|
28
|
-
|
29
|
-
|
30
|
-
class ConfiguredBaseModel(BaseModel):
|
31
|
-
class Config:
|
32
|
-
smart_union=True
|
33
|
-
extra=Extra.forbid
|
34
|
-
|
35
|
-
|
36
|
-
class JiraBoardV1(ConfiguredBaseModel):
|
37
|
-
name: str = Field(..., alias="name")
|
38
|
-
|
39
|
-
|
40
|
-
class JiraBoardShardingQueryData(ConfiguredBaseModel):
|
41
|
-
jira_boards: Optional[list[JiraBoardV1]] = Field(..., alias="jira_boards")
|
42
|
-
|
43
|
-
|
44
|
-
def query(query_func: Callable, **kwargs: Any) -> JiraBoardShardingQueryData:
|
45
|
-
"""
|
46
|
-
This is a convenience function which queries and parses the data into
|
47
|
-
concrete types. It should be compatible with most GQL clients.
|
48
|
-
You do not have to use it to consume the generated data classes.
|
49
|
-
Alternatively, you can also mime and alternate the behavior
|
50
|
-
of this function in the caller.
|
51
|
-
|
52
|
-
Parameters:
|
53
|
-
query_func (Callable): Function which queries your GQL Server
|
54
|
-
kwargs: optional arguments that will be passed to the query function
|
55
|
-
|
56
|
-
Returns:
|
57
|
-
JiraBoardShardingQueryData: queried data parsed into generated classes
|
58
|
-
"""
|
59
|
-
raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
|
60
|
-
return JiraBoardShardingQueryData(**raw_data)
|
{qontract_reconcile-0.10.2.dev25.dist-info → qontract_reconcile-0.10.2.dev27.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|