qontract-reconcile 0.10.2.dev21__py3-none-any.whl → 0.10.2.dev23__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev21
3
+ Version: 0.10.2.dev23
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
@@ -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=Xyk9VZnf3nQULRE6j3VvNqQXXq8wa0c-HyIfSRgkrlw,107476
13
+ reconcile/cli.py,sha256=jI3MMGWLBXYl-0aYOA4hLEQlBdP9lbb1FyGnqEjt-mM,107621
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=CY7cOj5dzt2se4IOg11VQvGQ-eTvLML5Q42Z9SSgeSk,9463
40
+ reconcile/integrations_manager.py,sha256=wZ5snv0l2KJ2EF7dAece8cDIvRYyGRXcdDcRfBNNfxQ,9573
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=WI39E0fv_J5LyKOuGCl1TB4RIJjR33QGEFX9BlU-Wjk,13044
49
+ reconcile/jira_permissions_validator.py,sha256=Hp9wkBUXafSIGtXozVhYRiIh3lxXyObCnmB77mGA9ZQ,13419
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=mlhbQShB7_Xp3xgrT9dzZZaf155i2fkR79gzUsfEGME,2215125
218
+ reconcile/gql_definitions/introspection.json,sha256=_MsmBFKNpf6uIymRHvkzVyz5ICgVD0aAcDi_7czXfxQ,2221786
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=HosEgRUlAkxLNoj2cnq3mrTdWDn9UvbNmtz6OcweIYk,11668
338
+ reconcile/gql_definitions/integrations/integrations.py,sha256=yPpLVR_tML0QvjvLzGT7_D3SkpA6MaZqn0-45pukWgc,12821
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,6 +373,7 @@ 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
376
377
  reconcile/gql_definitions/sharding/ocm_organization.py,sha256=duBIg3531yJ7fWniuHOG6mASgIiKfFIg6mef_lDzwnE,1871
377
378
  reconcile/gql_definitions/skupper_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
378
379
  reconcile/gql_definitions/skupper_network/site_controller_template.py,sha256=MFJTZAO0wRFlRBU4qfXUeQmCKIP4zkmnnCnrvX67FNY,756
@@ -718,7 +719,7 @@ reconcile/utils/runtime/environment.py,sha256=h-CFKLK1qRl_gfOVIUwjqVNOmukIPzUG7A
718
719
  reconcile/utils/runtime/integration.py,sha256=H3kDfbc4IKrhubSDCWHs0W9oxM7FoCiPaxqA73c9aEs,11101
719
720
  reconcile/utils/runtime/meta.py,sha256=dWdKS9eHVuowFkTK4lgXJ723vS1y9giOMzePUKnHnDI,214
720
721
  reconcile/utils/runtime/runner.py,sha256=I30KRrX1UQbHc_Ir1cIZX3OfNSdoHKdnDSPAEB69Ilk,7944
721
- reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFcnpA_k4,16142
722
+ reconcile/utils/runtime/sharding.py,sha256=y7UZrikyCe-0LmQOCL32fvjqX4NrdZ5rUH9lpvKH5Ks,18517
722
723
  reconcile/utils/saasherder/__init__.py,sha256=3U8plqMAPRE1kjwZ5YnIsYsggTf4_gS7flRUEuXVBAs,343
723
724
  reconcile/utils/saasherder/interfaces.py,sha256=C2wrw34OXypshVocAsPrVZsSHptgw4g9u7Haa2wulZQ,9087
724
725
  reconcile/utils/saasherder/models.py,sha256=z8ln03zi2a8cu716NcNUDHp8Dv1VcVbhqdWVxCl7x9A,10148
@@ -739,12 +740,12 @@ tools/app_interface_metrics_exporter.py,sha256=f1qwTmQfEcs98uBVRyBa0k7GQXdiSwd7w
739
740
  tools/app_interface_reporter.py,sha256=gR2EgHmgSIxzK5xxDW1SduFU6OkPaf2LlAQjhV3NYIg,17623
740
741
  tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
741
742
  tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
742
- tools/qontract_cli.py,sha256=5fpYOGtB7M-VHDAopTdKI0v85Md8YUiKPPNBhKfZgkU,144013
743
+ tools/qontract_cli.py,sha256=T637u3EVpodta2SSIjMa-3doLqXci1AEDt3Bspng4mE,145561
743
744
  tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaBNFA,5062
744
745
  tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
745
746
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
746
747
  tools/cli_commands/container_images_report.py,sha256=8fG9XU-eEhJ7hKCdQzBcdPpvIJR-8WGkHOgFEulpfYQ,5213
747
- tools/cli_commands/erv2.py,sha256=pWjd6yBhzakB1Lz4DUaESTbzEIO9-Njc7p7k_gvZj1U,22040
748
+ tools/cli_commands/erv2.py,sha256=1eilft_xwfGDQAMuOitKCzZw21Abmh0aDdCTafT1unw,23380
748
749
  tools/cli_commands/gpg_encrypt.py,sha256=NhzwN49UN7P5_FJgTUN5A4BIwNbFokIE4lwDax2iP5k,4891
749
750
  tools/cli_commands/systems_and_tools.py,sha256=EMHOF1AtUDaoSk0bbjl6oUKYAz4rTZjIBaF-6E6GspM,16816
750
751
  tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -766,7 +767,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
766
767
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
767
768
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
768
769
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
769
- qontract_reconcile-0.10.2.dev21.dist-info/METADATA,sha256=odjOqT6xlL94VSczTzQ6DNXDbhrppOG_UhaZk9wNnbg,24665
770
- qontract_reconcile-0.10.2.dev21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
771
- qontract_reconcile-0.10.2.dev21.dist-info/entry_points.txt,sha256=JniHZPadNOILPyfSl0LF2YSp3Db7K2_W2CN7i9f3Gos,540
772
- qontract_reconcile-0.10.2.dev21.dist-info/RECORD,,
770
+ qontract_reconcile-0.10.2.dev23.dist-info/METADATA,sha256=C5EWqnp2RymXK2IG0ug0lH9gvhe8-litZ1nqLs_iwgQ,24665
771
+ qontract_reconcile-0.10.2.dev23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
772
+ qontract_reconcile-0.10.2.dev23.dist-info/entry_points.txt,sha256=JniHZPadNOILPyfSl0LF2YSp3Db7K2_W2CN7i9f3Gos,540
773
+ qontract_reconcile-0.10.2.dev23.dist-info/RECORD,,
reconcile/cli.py CHANGED
@@ -1158,12 +1158,14 @@ def jenkins_webhooks_cleaner(ctx):
1158
1158
 
1159
1159
 
1160
1160
  @integration.command(short_help="Validate permissions in Jira.")
1161
+ @click.option("--jira-board-name", help="The Jira board to act on.", default=None)
1161
1162
  @enable_extended_early_exit
1162
1163
  @extended_early_exit_cache_ttl_seconds
1163
1164
  @log_cached_log_output
1164
1165
  @click.pass_context
1165
1166
  def jira_permissions_validator(
1166
1167
  ctx,
1168
+ jira_board_name,
1167
1169
  enable_extended_early_exit,
1168
1170
  extended_early_exit_cache_ttl_seconds,
1169
1171
  log_cached_log_output,
@@ -1173,6 +1175,7 @@ def jira_permissions_validator(
1173
1175
  run_integration(
1174
1176
  reconcile.jira_permissions_validator,
1175
1177
  ctx.obj,
1178
+ jira_board_name=jira_board_name,
1176
1179
  enable_extended_early_exit=enable_extended_early_exit,
1177
1180
  extended_early_exit_cache_ttl_seconds=extended_early_exit_cache_ttl_seconds,
1178
1181
  log_cached_log_output=log_cached_log_output,
@@ -191,6 +191,22 @@ 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
+ }
194
210
  }
195
211
  }
196
212
  }
@@ -342,10 +358,30 @@ class CloudflareDNSZoneShardingV1(IntegrationShardingV1):
342
358
  shard_spec_overrides: Optional[list[CloudflareDNSZoneShardSpecOverrideV1]] = Field(..., alias="shardSpecOverrides")
343
359
 
344
360
 
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
+
345
381
  class IntegrationManagedV1(ConfiguredBaseModel):
346
382
  namespace: NamespaceV1 = Field(..., alias="namespace")
347
383
  spec: IntegrationSpecV1 = Field(..., alias="spec")
348
- sharding: Optional[Union[StaticShardingV1, OpenshiftClusterShardingV1, OCMOrganizationShardingV1, AWSAccountShardingV1, CloudflareDNSZoneShardingV1, IntegrationShardingV1]] = Field(..., alias="sharding")
384
+ sharding: Optional[Union[StaticShardingV1, OpenshiftClusterShardingV1, OCMOrganizationShardingV1, AWSAccountShardingV1, CloudflareDNSZoneShardingV1, JiraBoardShardingV1, IntegrationShardingV1]] = Field(..., alias="sharding")
349
385
 
350
386
 
351
387
  class IntegrationV1(ConfiguredBaseModel):
@@ -29766,6 +29766,11 @@
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
29769
29774
  }
29770
29775
  ]
29771
29776
  },
@@ -45344,6 +45349,42 @@
45344
45349
  },
45345
45350
  "isDeprecated": false,
45346
45351
  "deprecationReason": null
45352
+ },
45353
+ {
45354
+ "name": "managed_by_erv2",
45355
+ "description": null,
45356
+ "args": [],
45357
+ "type": {
45358
+ "kind": "SCALAR",
45359
+ "name": "Boolean",
45360
+ "ofType": null
45361
+ },
45362
+ "isDeprecated": false,
45363
+ "deprecationReason": null
45364
+ },
45365
+ {
45366
+ "name": "delete",
45367
+ "description": null,
45368
+ "args": [],
45369
+ "type": {
45370
+ "kind": "SCALAR",
45371
+ "name": "Boolean",
45372
+ "ofType": null
45373
+ },
45374
+ "isDeprecated": false,
45375
+ "deprecationReason": null
45376
+ },
45377
+ {
45378
+ "name": "module_overrides",
45379
+ "description": null,
45380
+ "args": [],
45381
+ "type": {
45382
+ "kind": "OBJECT",
45383
+ "name": "ExternalResourcesModuleOverrides_v1",
45384
+ "ofType": null
45385
+ },
45386
+ "isDeprecated": false,
45387
+ "deprecationReason": null
45347
45388
  }
45348
45389
  ],
45349
45390
  "inputFields": null,
@@ -49733,6 +49774,122 @@
49733
49774
  "enumValues": null,
49734
49775
  "possibleTypes": null
49735
49776
  },
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
+ },
49736
49893
  {
49737
49894
  "kind": "OBJECT",
49738
49895
  "name": "StaticSubSharding_v1",
@@ -0,0 +1,60 @@
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)
@@ -41,6 +41,7 @@ from reconcile.utils.runtime.sharding import (
41
41
  AWSAccountShardingStrategy,
42
42
  CloudflareDnsZoneShardingStrategy,
43
43
  IntegrationShardManager,
44
+ JiraBoardShardingStrategy,
44
45
  OCMOrganizationShardingStrategy,
45
46
  OpenshiftClusterShardingStrategy,
46
47
  ShardSpec,
@@ -257,6 +258,7 @@ def run(
257
258
  OpenshiftClusterShardingStrategy.IDENTIFIER: OpenshiftClusterShardingStrategy(),
258
259
  CloudflareDnsZoneShardingStrategy.IDENTIFIER: CloudflareDnsZoneShardingStrategy(),
259
260
  OCMOrganizationShardingStrategy.IDENTIFIER: OCMOrganizationShardingStrategy(),
261
+ JiraBoardShardingStrategy.IDENTIFIER: JiraBoardShardingStrategy(),
260
262
  },
261
263
  integration_runtime_meta=integration_runtime_meta,
262
264
  )
@@ -31,7 +31,7 @@ from reconcile.utils.semver_helper import make_semver
31
31
  from reconcile.utils.unleash import get_feature_toggle_state
32
32
 
33
33
  QONTRACT_INTEGRATION = "jira-permissions-validator"
34
- QONTRACT_INTEGRATION_VERSION = make_semver(1, 0, 0)
34
+ QONTRACT_INTEGRATION_VERSION = make_semver(1, 1, 0)
35
35
 
36
36
  NameToIdMap = dict[str, str]
37
37
 
@@ -256,11 +256,14 @@ def validate_boards(
256
256
  return error
257
257
 
258
258
 
259
- def get_jira_boards(query_func: Callable) -> list[JiraBoardV1]:
259
+ def get_jira_boards(
260
+ query_func: Callable, jira_board_name: str | None = None
261
+ ) -> list[JiraBoardV1]:
260
262
  return [
261
263
  board
262
264
  for board in query_jira_boards(query_func=query_func).jira_boards or []
263
265
  if integration_is_enabled(QONTRACT_INTEGRATION, board)
266
+ and (not jira_board_name or board.name.lower() == jira_board_name.lower())
264
267
  ]
265
268
 
266
269
 
@@ -270,12 +273,13 @@ def export_boards(boards: list[JiraBoardV1]) -> list[dict]:
270
273
 
271
274
  def run(
272
275
  dry_run: bool,
276
+ jira_board_name: str | None = None,
273
277
  enable_extended_early_exit: bool = False,
274
278
  extended_early_exit_cache_ttl_seconds: int = 3600,
275
279
  log_cached_log_output: bool = False,
276
280
  ) -> None:
277
281
  gql_api = gql.get_api()
278
- boards = get_jira_boards(query_func=gql_api.query)
282
+ boards = get_jira_boards(query_func=gql_api.query, jira_board_name=jira_board_name)
279
283
  runner_params: RunnerParams = {
280
284
  "boards": boards,
281
285
  "dry_run": dry_run,
@@ -296,7 +300,7 @@ def run(
296
300
  # don't use `dry_run` in the cache key because this is a read-only integration
297
301
  dry_run=False,
298
302
  cache_source=cache_source,
299
- shard="",
303
+ shard=jira_board_name or "",
300
304
  ttl_seconds=extended_early_exit_cache_ttl_seconds,
301
305
  logger=logging.getLogger(),
302
306
  runner=runner,
@@ -332,5 +336,14 @@ def runner(boards: list[JiraBoardV1], dry_run: bool) -> ExtendedEarlyExitRunnerR
332
336
  return ExtendedEarlyExitRunnerResult(payload=export_boards(boards), applied_count=0)
333
337
 
334
338
 
335
- def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
336
- return {"boards": export_boards(get_jira_boards(query_func=gql.get_api().query))}
339
+ def early_exit_desired_state(
340
+ *args: Any, jira_board_name: str | None = None, **kwargs: Any
341
+ ) -> dict[str, Any]:
342
+ return {
343
+ "boards": export_boards(
344
+ get_jira_boards(
345
+ query_func=gql.get_api().query,
346
+ jira_board_name=jira_board_name,
347
+ )
348
+ )
349
+ }
@@ -19,6 +19,8 @@ from reconcile.gql_definitions.integrations.integrations import (
19
19
  IntegrationManagedV1,
20
20
  IntegrationShardingV1,
21
21
  IntegrationSpecV1,
22
+ JiraBoardShardingV1,
23
+ JiraBoardShardSpecOverrideV1,
22
24
  OCMOrganizationShardingV1,
23
25
  OCMOrganizationShardSpecOverrideV1,
24
26
  OpenshiftClusterShardingV1,
@@ -28,6 +30,7 @@ from reconcile.gql_definitions.integrations.integrations import (
28
30
  SubShardingV1,
29
31
  )
30
32
  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
31
34
  from reconcile.gql_definitions.sharding import (
32
35
  ocm_organization as sharding_ocm_organization,
33
36
  )
@@ -434,6 +437,67 @@ class CloudflareDnsZoneShardingStrategy:
434
437
  return shards
435
438
 
436
439
 
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
+
437
501
  @dataclass
438
502
  class IntegrationShardManager:
439
503
  strategies: dict[str, ShardingStrategy]
@@ -255,6 +255,41 @@ class Erv2Cli:
255
255
  print(e.stdout.decode("utf-8"))
256
256
  raise
257
257
 
258
+ def force_unlock(self, credentials: Path, lock_id: str) -> None:
259
+ """Run 'terraform force-unlock' in a CDKTF container."""
260
+ input_file = self.temp / "input.json"
261
+ input_file.write_text(self.input_data)
262
+
263
+ try:
264
+ run(["docker", "pull", self.image], check=True, capture_output=True)
265
+ run(
266
+ [
267
+ "docker",
268
+ "run",
269
+ "--name",
270
+ "erv2-unlock",
271
+ "--rm",
272
+ "--mount",
273
+ f"type=bind,source={input_file!s},target=/inputs/input.json",
274
+ "--mount",
275
+ f"type=bind,source={credentials!s},target=/credentials",
276
+ "-e",
277
+ "AWS_SHARED_CREDENTIALS_FILE=/credentials",
278
+ "--entrypoint",
279
+ "/bin/bash",
280
+ self.image,
281
+ "-c",
282
+ f"cdktf synth && cd cdktf.out/stacks/CDKTF/ && terraform init && terraform force-unlock -force '{lock_id}'",
283
+ ],
284
+ check=True,
285
+ )
286
+ except CalledProcessError as e:
287
+ if e.stderr:
288
+ print(e.stderr.decode("utf-8"))
289
+ if e.stdout:
290
+ print(e.stdout.decode("utf-8"))
291
+ raise
292
+
258
293
 
259
294
  class TfRun(Protocol):
260
295
  def __call__(self, path: Path, cmd: list[str]) -> str: ...
tools/qontract_cli.py CHANGED
@@ -4359,6 +4359,47 @@ def debug_shell(ctx) -> None:
4359
4359
  erv2cli.enter_shell(credentials_file)
4360
4360
 
4361
4361
 
4362
+ @external_resources.command()
4363
+ @binary(["docker"])
4364
+ @click.option(
4365
+ "--lock-id",
4366
+ required=True,
4367
+ help="The terraform lock ID to unlock",
4368
+ prompt=True,
4369
+ )
4370
+ @click.pass_context
4371
+ def force_unlock(ctx, lock_id: str) -> None:
4372
+ """Manually unlock the ERv2 terraform state."""
4373
+ # use a temporary directory in $HOME. The MacOS colima default configuration allows docker mounts from $HOME.
4374
+ with tempfile.TemporaryDirectory(
4375
+ dir=Path.home(), prefix="erv2-unlock."
4376
+ ) as _tempdir:
4377
+ tempdir = Path(_tempdir)
4378
+ with progress_spinner() as progress:
4379
+ with task(progress, "Preparing environment ..."):
4380
+ credentials_file = tempdir / "credentials"
4381
+ credentials_file.write_text(
4382
+ ctx.obj["secret_reader"].read_with_parameters(
4383
+ path=f"app-sre/external-resources/{ctx.obj['provisioner']}",
4384
+ field="credentials",
4385
+ format=None,
4386
+ version=None,
4387
+ )
4388
+ )
4389
+ os.environ["AWS_SHARED_CREDENTIALS_FILE"] = str(credentials_file)
4390
+
4391
+ erv2cli = Erv2Cli(
4392
+ provision_provider=ctx.obj["provision_provider"],
4393
+ provisioner=ctx.obj["provisioner"],
4394
+ provider=ctx.obj["provider"],
4395
+ identifier=ctx.obj["identifier"],
4396
+ secret_reader=ctx.obj["secret_reader"],
4397
+ temp_dir=tempdir,
4398
+ progress_spinner=progress,
4399
+ )
4400
+ erv2cli.force_unlock(credentials_file, lock_id)
4401
+
4402
+
4362
4403
  @get.command(help="Get all container images in app-interface defined namespaces")
4363
4404
  @cluster_name
4364
4405
  @namespace_name