qontract-reconcile 0.10.2.dev60__py3-none-any.whl → 0.10.2.dev61__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.dev60.dist-info → qontract_reconcile-0.10.2.dev61.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev60.dist-info → qontract_reconcile-0.10.2.dev61.dist-info}/RECORD +9 -9
- reconcile/change_owners/change_log_tracking.py +15 -25
- reconcile/utils/output.py +3 -6
- tools/app_interface_reporter.py +44 -70
- tools/cli_commands/gpg_encrypt.py +2 -2
- tools/qontract_cli.py +291 -230
- {qontract_reconcile-0.10.2.dev60.dist-info → qontract_reconcile-0.10.2.dev61.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev60.dist-info → qontract_reconcile-0.10.2.dev61.dist-info}/entry_points.txt +0 -0
tools/qontract_cli.py
CHANGED
@@ -10,6 +10,7 @@ import sys
|
|
10
10
|
import tempfile
|
11
11
|
import textwrap
|
12
12
|
from collections import defaultdict
|
13
|
+
from collections.abc import Callable, Mapping
|
13
14
|
from datetime import (
|
14
15
|
UTC,
|
15
16
|
datetime,
|
@@ -54,7 +55,6 @@ from reconcile.change_owners.bundle import NoOpFileDiffResolver
|
|
54
55
|
from reconcile.change_owners.change_log_tracking import (
|
55
56
|
BUNDLE_DIFFS_OBJ,
|
56
57
|
ChangeLog,
|
57
|
-
ChangeLogItem,
|
58
58
|
)
|
59
59
|
from reconcile.change_owners.change_owners import (
|
60
60
|
fetch_change_type_processors,
|
@@ -81,6 +81,7 @@ from reconcile.gql_definitions.app_sre_tekton_access_revalidation.roles import (
|
|
81
81
|
from reconcile.gql_definitions.common.app_interface_vault_settings import (
|
82
82
|
AppInterfaceSettingsV1,
|
83
83
|
)
|
84
|
+
from reconcile.gql_definitions.common.clusters import ClusterSpecROSAV1
|
84
85
|
from reconcile.gql_definitions.fragments.aus_organization import AUSOCMOrganization
|
85
86
|
from reconcile.gql_definitions.integrations import integrations as integrations_gql
|
86
87
|
from reconcile.gql_definitions.maintenance import maintenances as maintenances_gql
|
@@ -152,6 +153,7 @@ from reconcile.utils.oc_map import (
|
|
152
153
|
init_oc_map_from_clusters,
|
153
154
|
)
|
154
155
|
from reconcile.utils.ocm import OCM_PRODUCT_ROSA, OCMMap
|
156
|
+
from reconcile.utils.ocm.upgrades import get_upgrade_policies
|
155
157
|
from reconcile.utils.ocm_base_client import init_ocm_base_client
|
156
158
|
from reconcile.utils.output import print_output
|
157
159
|
from reconcile.utils.saasherder.models import TargetSpec
|
@@ -190,7 +192,7 @@ else:
|
|
190
192
|
CopySourceTypeDef = object
|
191
193
|
|
192
194
|
|
193
|
-
def output(function):
|
195
|
+
def output(function: Callable) -> Callable:
|
194
196
|
function = click.option(
|
195
197
|
"--output",
|
196
198
|
"-o",
|
@@ -201,14 +203,14 @@ def output(function):
|
|
201
203
|
return function
|
202
204
|
|
203
205
|
|
204
|
-
def sort(function):
|
206
|
+
def sort(function: Callable) -> Callable:
|
205
207
|
function = click.option(
|
206
208
|
"--sort", "-s", help="sort output", default=True, type=bool
|
207
209
|
)(function)
|
208
210
|
return function
|
209
211
|
|
210
212
|
|
211
|
-
def to_string(function):
|
213
|
+
def to_string(function: Callable) -> Callable:
|
212
214
|
function = click.option(
|
213
215
|
"--to-string", help="stringify output", default=False, type=bool
|
214
216
|
)(function)
|
@@ -218,14 +220,14 @@ def to_string(function):
|
|
218
220
|
@click.group()
|
219
221
|
@config_file
|
220
222
|
@click.pass_context
|
221
|
-
def root(ctx, configfile):
|
223
|
+
def root(ctx: click.Context, configfile: str) -> None:
|
222
224
|
ctx.ensure_object(dict)
|
223
225
|
config.init_from_toml(configfile)
|
224
226
|
gql.init_from_config()
|
225
227
|
|
226
228
|
|
227
229
|
@root.result_callback()
|
228
|
-
def exit_cli(ctx, configfile):
|
230
|
+
def exit_cli(ctx: click.Context, configfile: str) -> None:
|
229
231
|
GqlApiSingleton.close()
|
230
232
|
|
231
233
|
|
@@ -234,7 +236,7 @@ def exit_cli(ctx, configfile):
|
|
234
236
|
@sort
|
235
237
|
@to_string
|
236
238
|
@click.pass_context
|
237
|
-
def get(ctx, output, sort, to_string):
|
239
|
+
def get(ctx: click.Context, output: str, sort: bool, to_string: bool) -> None:
|
238
240
|
ctx.obj["options"] = {
|
239
241
|
"output": output,
|
240
242
|
"sort": sort,
|
@@ -245,7 +247,7 @@ def get(ctx, output, sort, to_string):
|
|
245
247
|
@root.group()
|
246
248
|
@output
|
247
249
|
@click.pass_context
|
248
|
-
def describe(ctx, output):
|
250
|
+
def describe(ctx: click.Context, output: str) -> None:
|
249
251
|
ctx.obj["options"] = {
|
250
252
|
"output": output,
|
251
253
|
}
|
@@ -253,7 +255,7 @@ def describe(ctx, output):
|
|
253
255
|
|
254
256
|
@get.command()
|
255
257
|
@click.pass_context
|
256
|
-
def settings(ctx):
|
258
|
+
def settings(ctx: click.Context) -> None:
|
257
259
|
settings = queries.get_app_interface_settings()
|
258
260
|
columns = ["vault", "kubeBinary", "mergeRequestGateway"]
|
259
261
|
print_output(ctx.obj["options"], [settings], columns)
|
@@ -262,7 +264,7 @@ def settings(ctx):
|
|
262
264
|
@get.command()
|
263
265
|
@click.argument("name", default="")
|
264
266
|
@click.pass_context
|
265
|
-
def aws_accounts(ctx, name):
|
267
|
+
def aws_accounts(ctx: click.Context, name: str) -> None:
|
266
268
|
accounts = queries.get_aws_accounts(name=name)
|
267
269
|
if not accounts:
|
268
270
|
print("no aws accounts found")
|
@@ -274,7 +276,7 @@ def aws_accounts(ctx, name):
|
|
274
276
|
@get.command()
|
275
277
|
@click.argument("name", default="")
|
276
278
|
@click.pass_context
|
277
|
-
def clusters(ctx, name):
|
279
|
+
def clusters(ctx: click.Context, name: str) -> None:
|
278
280
|
clusters = queries.get_clusters()
|
279
281
|
if name:
|
280
282
|
clusters = [c for c in clusters if c["name"] == name]
|
@@ -291,7 +293,7 @@ def clusters(ctx, name):
|
|
291
293
|
@get.command()
|
292
294
|
@click.argument("name", default="")
|
293
295
|
@click.pass_context
|
294
|
-
def cluster_upgrades(ctx, name):
|
296
|
+
def cluster_upgrades(ctx: click.Context, name: str) -> None:
|
295
297
|
settings = queries.get_app_interface_settings()
|
296
298
|
|
297
299
|
clusters = queries.get_clusters()
|
@@ -322,12 +324,11 @@ def cluster_upgrades(ctx, name):
|
|
322
324
|
if data.get("upgradePolicy") == "automatic":
|
323
325
|
data["schedule"] = c["upgradePolicy"]["schedule"]
|
324
326
|
ocm = ocm_map.get(c["name"])
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
data["next_run"] = next_run
|
327
|
+
upgrade_policy = get_upgrade_policies(ocm.ocm_api, c["spec"]["id"])
|
328
|
+
if upgrade_policy and len(upgrade_policy) > 0:
|
329
|
+
next_run = upgrade_policy[0].get("next_run")
|
330
|
+
if next_run:
|
331
|
+
data["next_run"] = next_run
|
331
332
|
else:
|
332
333
|
data["upgradePolicy"] = "manual"
|
333
334
|
|
@@ -341,7 +342,7 @@ def cluster_upgrades(ctx, name):
|
|
341
342
|
@get.command()
|
342
343
|
@environ(["APP_INTERFACE_STATE_BUCKET", "APP_INTERFACE_STATE_BUCKET_ACCOUNT"])
|
343
344
|
@click.pass_context
|
344
|
-
def version_history(ctx):
|
345
|
+
def version_history(ctx: click.Context) -> None:
|
345
346
|
import reconcile.aus.ocm_upgrade_scheduler as ous
|
346
347
|
|
347
348
|
clusters = aus_clusters_query(query_func=gql.get_api().query).clusters or []
|
@@ -377,11 +378,11 @@ def version_history(ctx):
|
|
377
378
|
|
378
379
|
def get_upgrade_policies_data(
|
379
380
|
org_upgrade_specs: list[OrganizationUpgradeSpec],
|
380
|
-
md_output,
|
381
|
-
integration,
|
382
|
-
workload=None,
|
383
|
-
show_only_soaking_upgrades=False,
|
384
|
-
by_workload=False,
|
381
|
+
md_output: bool,
|
382
|
+
integration: str,
|
383
|
+
workload: str | None = None,
|
384
|
+
show_only_soaking_upgrades: bool = False,
|
385
|
+
by_workload: bool = False,
|
385
386
|
) -> list:
|
386
387
|
if not org_upgrade_specs:
|
387
388
|
return []
|
@@ -562,12 +563,12 @@ more than 6 hours will be highlighted.
|
|
562
563
|
)
|
563
564
|
@click.pass_context
|
564
565
|
def cluster_upgrade_policies(
|
565
|
-
ctx,
|
566
|
-
cluster=None,
|
567
|
-
workload=None,
|
568
|
-
show_only_soaking_upgrades=False,
|
569
|
-
by_workload=False,
|
570
|
-
):
|
566
|
+
ctx: click.Context,
|
567
|
+
cluster: str | None = None,
|
568
|
+
workload: str | None = None,
|
569
|
+
show_only_soaking_upgrades: bool = False,
|
570
|
+
by_workload: bool = False,
|
571
|
+
) -> None:
|
571
572
|
print(
|
572
573
|
"https://grafana.app-sre.devshift.net/d/ukLXCSwVz/aus-cluster-upgrade-overview"
|
573
574
|
)
|
@@ -582,9 +583,7 @@ def inherit_version_data_text(org: AUSOCMOrganization) -> str:
|
|
582
583
|
|
583
584
|
@get.command()
|
584
585
|
@click.pass_context
|
585
|
-
def ocm_fleet_upgrade_policies(
|
586
|
-
ctx,
|
587
|
-
):
|
586
|
+
def ocm_fleet_upgrade_policies(ctx: click.Context) -> None:
|
588
587
|
from reconcile.aus.ocm_upgrade_scheduler_org import (
|
589
588
|
OCMClusterUpgradeSchedulerOrgIntegration,
|
590
589
|
)
|
@@ -617,7 +616,12 @@ def ocm_fleet_upgrade_policies(
|
|
617
616
|
help="Ignore STS clusters",
|
618
617
|
)
|
619
618
|
@click.pass_context
|
620
|
-
def aus_fleet_upgrade_policies(
|
619
|
+
def aus_fleet_upgrade_policies(
|
620
|
+
ctx: click.Context,
|
621
|
+
ocm_env: str | None,
|
622
|
+
ocm_org_ids: str | None,
|
623
|
+
ignore_sts_clusters: bool,
|
624
|
+
) -> None:
|
621
625
|
from reconcile.aus.advanced_upgrade_service import AdvancedUpgradeServiceIntegration
|
622
626
|
|
623
627
|
parsed_ocm_org_ids = set(ocm_org_ids.split(",")) if ocm_org_ids else None
|
@@ -634,8 +638,8 @@ def aus_fleet_upgrade_policies(ctx, ocm_env, ocm_org_ids, ignore_sts_clusters):
|
|
634
638
|
|
635
639
|
|
636
640
|
def generate_fleet_upgrade_policices_report(
|
637
|
-
ctx, aus_integration: AdvancedUpgradeSchedulerBaseIntegration
|
638
|
-
):
|
641
|
+
ctx: click.Context, aus_integration: AdvancedUpgradeSchedulerBaseIntegration
|
642
|
+
) -> None:
|
639
643
|
md_output = ctx.obj["options"]["output"] == "md"
|
640
644
|
|
641
645
|
org_upgrade_specs: dict[str, OrganizationUpgradeSpec] = {}
|
@@ -953,7 +957,7 @@ def upgrade_cluster_addon(
|
|
953
957
|
)
|
954
958
|
|
955
959
|
|
956
|
-
def has_cluster_account_access(cluster: dict[str, Any]):
|
960
|
+
def has_cluster_account_access(cluster: dict[str, Any]) -> bool:
|
957
961
|
spec = cluster.get("spec") or {}
|
958
962
|
account = spec.get("account")
|
959
963
|
return account or cluster.get("awsInfrastructureManagementAccounts") is not None
|
@@ -962,7 +966,7 @@ def has_cluster_account_access(cluster: dict[str, Any]):
|
|
962
966
|
@get.command()
|
963
967
|
@click.argument("name", default="")
|
964
968
|
@click.pass_context
|
965
|
-
def clusters_network(ctx, name):
|
969
|
+
def clusters_network(ctx: click.Context, name: str) -> None:
|
966
970
|
settings = queries.get_app_interface_settings()
|
967
971
|
clusters = [
|
968
972
|
c
|
@@ -1025,7 +1029,7 @@ def clusters_network(ctx, name):
|
|
1025
1029
|
|
1026
1030
|
@get.command()
|
1027
1031
|
@click.pass_context
|
1028
|
-
def network_reservations(ctx) -> None:
|
1032
|
+
def network_reservations(ctx: click.Context) -> None:
|
1029
1033
|
from reconcile.typed_queries.reserved_networks import get_networks
|
1030
1034
|
|
1031
1035
|
columns = [
|
@@ -1038,11 +1042,10 @@ def network_reservations(ctx) -> None:
|
|
1038
1042
|
]
|
1039
1043
|
network_table = []
|
1040
1044
|
|
1041
|
-
def md_link(url) -> str:
|
1045
|
+
def md_link(url: str) -> str:
|
1042
1046
|
if ctx.obj["options"]["output"] == "md":
|
1043
1047
|
return f"[{url}]({url})"
|
1044
|
-
|
1045
|
-
return url
|
1048
|
+
return url
|
1046
1049
|
|
1047
1050
|
for network in get_networks():
|
1048
1051
|
parentAddress = "none"
|
@@ -1083,7 +1086,7 @@ def network_reservations(ctx) -> None:
|
|
1083
1086
|
default=24,
|
1084
1087
|
)
|
1085
1088
|
@click.pass_context
|
1086
|
-
def cidr_blocks(ctx, for_cluster: int, mask: int) -> None:
|
1089
|
+
def cidr_blocks(ctx: click.Context, for_cluster: int, mask: int) -> None:
|
1087
1090
|
import ipaddress
|
1088
1091
|
|
1089
1092
|
from reconcile.typed_queries.aws_vpcs import get_aws_vpcs
|
@@ -1209,7 +1212,7 @@ def ocm_aws_infrastructure_access_switch_role_links_data() -> list[dict]:
|
|
1209
1212
|
|
1210
1213
|
@get.command()
|
1211
1214
|
@click.pass_context
|
1212
|
-
def ocm_aws_infrastructure_access_switch_role_links_flat(ctx):
|
1215
|
+
def ocm_aws_infrastructure_access_switch_role_links_flat(ctx: click.Context) -> None:
|
1213
1216
|
results = ocm_aws_infrastructure_access_switch_role_links_data()
|
1214
1217
|
columns = ["cluster", "user_arn", "access_level", "switch_role_link"]
|
1215
1218
|
print_output(ctx.obj["options"], results, columns)
|
@@ -1217,11 +1220,11 @@ def ocm_aws_infrastructure_access_switch_role_links_flat(ctx):
|
|
1217
1220
|
|
1218
1221
|
@get.command()
|
1219
1222
|
@click.pass_context
|
1220
|
-
def ocm_aws_infrastructure_access_switch_role_links(ctx):
|
1223
|
+
def ocm_aws_infrastructure_access_switch_role_links(ctx: click.Context) -> None:
|
1221
1224
|
if ctx.obj["options"]["output"] != "md":
|
1222
1225
|
raise Exception(f"Unupported output: {ctx.obj['options']['output']}")
|
1223
1226
|
results = ocm_aws_infrastructure_access_switch_role_links_data()
|
1224
|
-
by_user = {}
|
1227
|
+
by_user: dict = {}
|
1225
1228
|
for r in results:
|
1226
1229
|
by_user.setdefault(r["user"], []).append(r)
|
1227
1230
|
columns = ["cluster", "source_login", "access_level", "switch_role_link"]
|
@@ -1235,7 +1238,7 @@ def ocm_aws_infrastructure_access_switch_role_links(ctx):
|
|
1235
1238
|
|
1236
1239
|
@get.command()
|
1237
1240
|
@click.pass_context
|
1238
|
-
def clusters_aws_account_ids(ctx):
|
1241
|
+
def clusters_aws_account_ids(ctx: click.Context) -> None:
|
1239
1242
|
settings = queries.get_app_interface_settings()
|
1240
1243
|
clusters = [c for c in queries.get_clusters() if c.get("ocm") is not None]
|
1241
1244
|
ocm_map = OCMMap(clusters=clusters, settings=settings)
|
@@ -1265,7 +1268,7 @@ def clusters_aws_account_ids(ctx):
|
|
1265
1268
|
@root.command()
|
1266
1269
|
@click.argument("account_name")
|
1267
1270
|
@click.pass_context
|
1268
|
-
def user_credentials_migrate_output(ctx, account_name) -> None:
|
1271
|
+
def user_credentials_migrate_output(ctx: click.Context, account_name: str) -> None:
|
1269
1272
|
accounts = queries.get_state_aws_accounts()
|
1270
1273
|
state = init_state(integration="account-notifier")
|
1271
1274
|
skip_accounts, appsre_pgp_key, _ = tfu.get_reencrypt_settings()
|
@@ -1307,7 +1310,7 @@ def user_credentials_migrate_output(ctx, account_name) -> None:
|
|
1307
1310
|
|
1308
1311
|
@get.command()
|
1309
1312
|
@click.pass_context
|
1310
|
-
def aws_route53_zones(ctx):
|
1313
|
+
def aws_route53_zones(ctx: click.Context) -> None:
|
1311
1314
|
zones = queries.get_dns_zones()
|
1312
1315
|
|
1313
1316
|
results = []
|
@@ -1330,7 +1333,7 @@ def aws_route53_zones(ctx):
|
|
1330
1333
|
@click.argument("cluster_name")
|
1331
1334
|
@click.option("--cluster-admin/--no-cluster-admin", default=False)
|
1332
1335
|
@click.pass_context
|
1333
|
-
def bot_login(ctx, cluster_name, cluster_admin):
|
1336
|
+
def bot_login(ctx: click.Context, cluster_name: str, cluster_admin: bool) -> None:
|
1334
1337
|
settings = queries.get_app_interface_settings()
|
1335
1338
|
secret_reader = SecretReader(settings=settings)
|
1336
1339
|
clusters = queries.get_clusters()
|
@@ -1353,7 +1356,7 @@ def bot_login(ctx, cluster_name, cluster_admin):
|
|
1353
1356
|
)
|
1354
1357
|
@click.argument("org_name")
|
1355
1358
|
@click.pass_context
|
1356
|
-
def ocm_login(ctx, org_name):
|
1359
|
+
def ocm_login(ctx: click.Context, org_name: str) -> None:
|
1357
1360
|
settings = queries.get_app_interface_settings()
|
1358
1361
|
secret_reader = SecretReader(settings=settings)
|
1359
1362
|
ocms = [
|
@@ -1380,7 +1383,7 @@ def ocm_login(ctx, org_name):
|
|
1380
1383
|
)
|
1381
1384
|
@click.argument("account_name")
|
1382
1385
|
@click.pass_context
|
1383
|
-
def aws_creds(ctx, account_name):
|
1386
|
+
def aws_creds(ctx: click.Context, account_name: str) -> None:
|
1384
1387
|
settings = queries.get_app_interface_settings()
|
1385
1388
|
secret_reader = SecretReader(settings=settings)
|
1386
1389
|
accounts = queries.get_aws_accounts(name=account_name)
|
@@ -1423,8 +1426,14 @@ def aws_creds(ctx, account_name):
|
|
1423
1426
|
)
|
1424
1427
|
@click.pass_context
|
1425
1428
|
def copy_tfstate(
|
1426
|
-
ctx
|
1427
|
-
|
1429
|
+
ctx: click.Context,
|
1430
|
+
source_bucket: str,
|
1431
|
+
source_object_path: str,
|
1432
|
+
account_uid: str,
|
1433
|
+
rename: str | None,
|
1434
|
+
region: str | None,
|
1435
|
+
force: bool,
|
1436
|
+
) -> None:
|
1428
1437
|
settings = queries.get_app_interface_settings()
|
1429
1438
|
secret_reader = SecretReader(settings=settings)
|
1430
1439
|
accounts = queries.get_aws_accounts(uid=account_uid, terraform_state=True)
|
@@ -1445,7 +1454,6 @@ def copy_tfstate(
|
|
1445
1454
|
)
|
1446
1455
|
return
|
1447
1456
|
|
1448
|
-
dest_filename = ""
|
1449
1457
|
if rename:
|
1450
1458
|
dest_filename = rename.removesuffix(".tfstate")
|
1451
1459
|
else:
|
@@ -1506,20 +1514,26 @@ def copy_tfstate(
|
|
1506
1514
|
@get.command(short_help='obtain "rosa create cluster" command by cluster name')
|
1507
1515
|
@click.argument("cluster_name")
|
1508
1516
|
@click.pass_context
|
1509
|
-
def rosa_create_cluster_command(ctx, cluster_name):
|
1517
|
+
def rosa_create_cluster_command(ctx: click.Context, cluster_name: str) -> None:
|
1510
1518
|
clusters = [c for c in get_clusters() if c.name == cluster_name]
|
1511
|
-
|
1512
|
-
cluster = clusters[0]
|
1513
|
-
except IndexError:
|
1519
|
+
if not clusters:
|
1514
1520
|
print(f"{cluster_name} not found.")
|
1515
1521
|
sys.exit(1)
|
1522
|
+
cluster = clusters[0]
|
1516
1523
|
|
1517
|
-
if
|
1524
|
+
if (
|
1525
|
+
not cluster.spec
|
1526
|
+
or cluster.spec.product != OCM_PRODUCT_ROSA
|
1527
|
+
or not isinstance(cluster.spec, ClusterSpecROSAV1)
|
1528
|
+
):
|
1518
1529
|
print("must be a rosa cluster.")
|
1519
1530
|
sys.exit(1)
|
1520
1531
|
|
1521
1532
|
settings = queries.get_app_interface_settings()
|
1522
1533
|
account = cluster.spec.account
|
1534
|
+
if not account:
|
1535
|
+
print("account not found.")
|
1536
|
+
sys.exit(1)
|
1523
1537
|
|
1524
1538
|
if account.billing_account:
|
1525
1539
|
billing_account = account.billing_account.uid
|
@@ -1529,6 +1543,19 @@ def rosa_create_cluster_command(ctx, cluster_name):
|
|
1529
1543
|
) as aws_api:
|
1530
1544
|
billing_account = aws_api.get_organization_billing_account(account.name)
|
1531
1545
|
|
1546
|
+
if not cluster.spec.oidc_endpoint_url:
|
1547
|
+
print("oidc_endpoint_url not set.")
|
1548
|
+
sys.exit(1)
|
1549
|
+
if not cluster.spec.subnet_ids:
|
1550
|
+
print("subnet_ids not set.")
|
1551
|
+
sys.exit(1)
|
1552
|
+
if not cluster.network:
|
1553
|
+
print("network not set.")
|
1554
|
+
sys.exit(1)
|
1555
|
+
if not cluster.machine_pools:
|
1556
|
+
print("machine_pools not set.")
|
1557
|
+
sys.exit(1)
|
1558
|
+
|
1532
1559
|
print(
|
1533
1560
|
" ".join([
|
1534
1561
|
"rosa create cluster",
|
@@ -1582,7 +1609,9 @@ def rosa_create_cluster_command(ctx, cluster_name):
|
|
1582
1609
|
@click.argument("jumphost_hostname", required=False)
|
1583
1610
|
@click.argument("cluster_name", required=False)
|
1584
1611
|
@click.pass_context
|
1585
|
-
def sshuttle_command(
|
1612
|
+
def sshuttle_command(
|
1613
|
+
ctx: click.Context, jumphost_hostname: str | None, cluster_name: str | None
|
1614
|
+
) -> None:
|
1586
1615
|
jumphosts_query_data = queries.get_jumphosts(hostname=jumphost_hostname)
|
1587
1616
|
jumphosts = jumphosts_query_data.jumphosts or []
|
1588
1617
|
for jh in jumphosts:
|
@@ -1604,7 +1633,9 @@ def sshuttle_command(ctx, jumphost_hostname: str | None, cluster_name: str | Non
|
|
1604
1633
|
@click.argument("instance_name")
|
1605
1634
|
@click.argument("job_name")
|
1606
1635
|
@click.pass_context
|
1607
|
-
def jenkins_job_vault_secrets(
|
1636
|
+
def jenkins_job_vault_secrets(
|
1637
|
+
ctx: click.Context, instance_name: str, job_name: str
|
1638
|
+
) -> None:
|
1608
1639
|
secret_reader = SecretReader(queries.get_secret_reader_settings())
|
1609
1640
|
jjb: JJB = init_jjb(secret_reader, instance_name, config_name=None, print_only=True)
|
1610
1641
|
jobs = jjb.get_all_jobs([job_name], instance_name)[instance_name]
|
@@ -1629,7 +1660,7 @@ def jenkins_job_vault_secrets(ctx, instance_name: str, job_name: str) -> None:
|
|
1629
1660
|
@get.command()
|
1630
1661
|
@click.argument("name", default="")
|
1631
1662
|
@click.pass_context
|
1632
|
-
def namespaces(ctx, name):
|
1663
|
+
def namespaces(ctx: click.Context, name: str) -> None:
|
1633
1664
|
namespaces = queries.get_namespaces()
|
1634
1665
|
if name:
|
1635
1666
|
namespaces = [ns for ns in namespaces if ns["name"] == name]
|
@@ -1641,7 +1672,7 @@ def namespaces(ctx, name):
|
|
1641
1672
|
print_output(ctx.obj["options"], namespaces, columns)
|
1642
1673
|
|
1643
1674
|
|
1644
|
-
def add_resource(item, resource, columns):
|
1675
|
+
def add_resource(item: dict, resource: Mapping, columns: list[str]) -> None:
|
1645
1676
|
provider = resource["provider"]
|
1646
1677
|
if provider not in columns:
|
1647
1678
|
columns.append(provider)
|
@@ -1652,11 +1683,11 @@ def add_resource(item, resource, columns):
|
|
1652
1683
|
|
1653
1684
|
@get.command
|
1654
1685
|
@click.pass_context
|
1655
|
-
def cluster_openshift_resources(ctx):
|
1686
|
+
def cluster_openshift_resources(ctx: click.Context) -> None:
|
1656
1687
|
gqlapi = gql.get_api()
|
1657
1688
|
namespaces = gqlapi.query(orb.NAMESPACES_QUERY)["namespaces"]
|
1658
1689
|
columns = ["name", "total"]
|
1659
|
-
results = {}
|
1690
|
+
results: dict = {}
|
1660
1691
|
for ns_info in namespaces:
|
1661
1692
|
cluster_name = ns_info["cluster"]["name"]
|
1662
1693
|
item = {"name": cluster_name, "total": 0}
|
@@ -1677,10 +1708,10 @@ def cluster_openshift_resources(ctx):
|
|
1677
1708
|
|
1678
1709
|
@get.command
|
1679
1710
|
@click.pass_context
|
1680
|
-
def aws_terraform_resources(ctx):
|
1711
|
+
def aws_terraform_resources(ctx: click.Context) -> None:
|
1681
1712
|
namespaces = tfr.get_namespaces()
|
1682
1713
|
columns = ["name", "total"]
|
1683
|
-
results = {}
|
1714
|
+
results: dict = {}
|
1684
1715
|
for ns_info in namespaces:
|
1685
1716
|
specs = (
|
1686
1717
|
get_external_resource_specs(
|
@@ -1732,7 +1763,7 @@ def rds_region(
|
|
1732
1763
|
|
1733
1764
|
@get.command
|
1734
1765
|
@click.pass_context
|
1735
|
-
def rds(ctx):
|
1766
|
+
def rds(ctx: click.Context) -> None:
|
1736
1767
|
namespaces = tfr.get_namespaces()
|
1737
1768
|
accounts = {a["name"]: a for a in queries.get_aws_accounts()}
|
1738
1769
|
results = []
|
@@ -1810,7 +1841,7 @@ You can view the source of this Markdown to extract the JSON data.
|
|
1810
1841
|
|
1811
1842
|
@get.command
|
1812
1843
|
@click.pass_context
|
1813
|
-
def rds_recommendations(ctx):
|
1844
|
+
def rds_recommendations(ctx: click.Context) -> None:
|
1814
1845
|
IGNORED_STATUSES = ("resolved",)
|
1815
1846
|
IGNORED_SEVERITIES = ("informational",)
|
1816
1847
|
|
@@ -1889,7 +1920,7 @@ def rds_recommendations(ctx):
|
|
1889
1920
|
|
1890
1921
|
@get.command()
|
1891
1922
|
@click.pass_context
|
1892
|
-
def products(ctx):
|
1923
|
+
def products(ctx: click.Context) -> None:
|
1893
1924
|
products = queries.get_products()
|
1894
1925
|
columns = ["name", "description"]
|
1895
1926
|
print_output(ctx.obj["options"], products, columns)
|
@@ -1898,7 +1929,7 @@ def products(ctx):
|
|
1898
1929
|
@describe.command()
|
1899
1930
|
@click.argument("name")
|
1900
1931
|
@click.pass_context
|
1901
|
-
def product(ctx, name):
|
1932
|
+
def product(ctx: click.Context, name: str) -> None:
|
1902
1933
|
products = queries.get_products()
|
1903
1934
|
products = [p for p in products if p["name"].lower() == name.lower()]
|
1904
1935
|
if len(products) != 1:
|
@@ -1913,7 +1944,7 @@ def product(ctx, name):
|
|
1913
1944
|
|
1914
1945
|
@get.command()
|
1915
1946
|
@click.pass_context
|
1916
|
-
def environments(ctx):
|
1947
|
+
def environments(ctx: click.Context) -> None:
|
1917
1948
|
environments = queries.get_environments()
|
1918
1949
|
columns = ["name", "description", "product.name"]
|
1919
1950
|
# TODO(mafriedm): fix this
|
@@ -1925,7 +1956,7 @@ def environments(ctx):
|
|
1925
1956
|
@describe.command()
|
1926
1957
|
@click.argument("name")
|
1927
1958
|
@click.pass_context
|
1928
|
-
def environment(ctx, name):
|
1959
|
+
def environment(ctx: click.Context, name: str) -> None:
|
1929
1960
|
environments = queries.get_environments()
|
1930
1961
|
environments = [e for e in environments if e["name"].lower() == name.lower()]
|
1931
1962
|
if len(environments) != 1:
|
@@ -1943,7 +1974,7 @@ def environment(ctx, name):
|
|
1943
1974
|
|
1944
1975
|
@get.command()
|
1945
1976
|
@click.pass_context
|
1946
|
-
def services(ctx):
|
1977
|
+
def services(ctx: click.Context) -> None:
|
1947
1978
|
apps = queries.get_apps()
|
1948
1979
|
columns = ["name", "path", "onboardingStatus"]
|
1949
1980
|
print_output(ctx.obj["options"], apps, columns)
|
@@ -1951,17 +1982,15 @@ def services(ctx):
|
|
1951
1982
|
|
1952
1983
|
@get.command()
|
1953
1984
|
@click.pass_context
|
1954
|
-
def repos(ctx):
|
1985
|
+
def repos(ctx: click.Context) -> None:
|
1955
1986
|
repos = queries.get_repos()
|
1956
|
-
|
1957
|
-
columns = ["url"]
|
1958
|
-
print_output(ctx.obj["options"], repos, columns)
|
1987
|
+
print_output(ctx.obj["options"], [{"url": r} for r in repos], ["url"])
|
1959
1988
|
|
1960
1989
|
|
1961
1990
|
@get.command()
|
1962
1991
|
@click.argument("org_username")
|
1963
1992
|
@click.pass_context
|
1964
|
-
def roles(ctx, org_username):
|
1993
|
+
def roles(ctx: click.Context, org_username: str) -> None:
|
1965
1994
|
users = queries.get_roles()
|
1966
1995
|
users = [u for u in users if u["org_username"] == org_username]
|
1967
1996
|
|
@@ -1972,7 +2001,7 @@ def roles(ctx, org_username):
|
|
1972
2001
|
user = users[0]
|
1973
2002
|
|
1974
2003
|
# type, name, resource, [ref]
|
1975
|
-
roles: dict[
|
2004
|
+
roles: dict[tuple[str, str, str], set[str]] = defaultdict(set)
|
1976
2005
|
|
1977
2006
|
for role in user["roles"]:
|
1978
2007
|
role_name = role["path"]
|
@@ -2026,7 +2055,7 @@ def roles(ctx, org_username):
|
|
2026
2055
|
@get.command()
|
2027
2056
|
@click.argument("org_username", default="")
|
2028
2057
|
@click.pass_context
|
2029
|
-
def users(ctx, org_username):
|
2058
|
+
def users(ctx: click.Context, org_username: str) -> None:
|
2030
2059
|
users = queries.get_users()
|
2031
2060
|
if org_username:
|
2032
2061
|
users = [u for u in users if u["org_username"] == org_username]
|
@@ -2037,7 +2066,7 @@ def users(ctx, org_username):
|
|
2037
2066
|
|
2038
2067
|
@get.command()
|
2039
2068
|
@click.pass_context
|
2040
|
-
def integrations(ctx):
|
2069
|
+
def integrations(ctx: click.Context) -> None:
|
2041
2070
|
environments = queries.get_integrations()
|
2042
2071
|
columns = ["name", "description"]
|
2043
2072
|
print_output(ctx.obj["options"], environments, columns)
|
@@ -2045,7 +2074,7 @@ def integrations(ctx):
|
|
2045
2074
|
|
2046
2075
|
@get.command()
|
2047
2076
|
@click.pass_context
|
2048
|
-
def quay_mirrors(ctx):
|
2077
|
+
def quay_mirrors(ctx: click.Context) -> None:
|
2049
2078
|
apps = queries.get_quay_repos()
|
2050
2079
|
|
2051
2080
|
mirrors = []
|
@@ -2083,7 +2112,9 @@ def quay_mirrors(ctx):
|
|
2083
2112
|
@click.argument("kind")
|
2084
2113
|
@click.argument("name")
|
2085
2114
|
@click.pass_context
|
2086
|
-
def root_owner(
|
2115
|
+
def root_owner(
|
2116
|
+
ctx: click.Context, cluster: str, namespace: str, kind: str, name: str
|
2117
|
+
) -> None:
|
2087
2118
|
settings = queries.get_app_interface_settings()
|
2088
2119
|
clusters = [c for c in queries.get_clusters(minimal=True) if c["name"] == cluster]
|
2089
2120
|
oc_map = OC_Map(
|
@@ -2113,7 +2144,9 @@ def root_owner(ctx, cluster, namespace, kind, name):
|
|
2113
2144
|
@click.argument("aws_account")
|
2114
2145
|
@click.argument("identifier")
|
2115
2146
|
@click.pass_context
|
2116
|
-
def service_owners_for_rds_instance(
|
2147
|
+
def service_owners_for_rds_instance(
|
2148
|
+
ctx: click.Context, aws_account: str, identifier: str
|
2149
|
+
) -> None:
|
2117
2150
|
namespaces = queries.get_namespaces()
|
2118
2151
|
service_owners = []
|
2119
2152
|
for namespace_info in namespaces:
|
@@ -2135,7 +2168,7 @@ def service_owners_for_rds_instance(ctx, aws_account, identifier):
|
|
2135
2168
|
|
2136
2169
|
@get.command()
|
2137
2170
|
@click.pass_context
|
2138
|
-
def sre_checkpoints(ctx):
|
2171
|
+
def sre_checkpoints(ctx: click.Context) -> None:
|
2139
2172
|
apps = queries.get_apps()
|
2140
2173
|
|
2141
2174
|
parent_apps = {app["parentApp"]["path"] for app in apps if app.get("parentApp")}
|
@@ -2159,13 +2192,14 @@ def sre_checkpoints(ctx):
|
|
2159
2192
|
|
2160
2193
|
@get.command()
|
2161
2194
|
@click.pass_context
|
2162
|
-
def app_interface_merge_queue(ctx):
|
2195
|
+
def app_interface_merge_queue(ctx: click.Context) -> None:
|
2163
2196
|
import reconcile.gitlab_housekeeping as glhk
|
2164
2197
|
|
2165
2198
|
settings = queries.get_app_interface_settings()
|
2166
2199
|
instance = queries.get_gitlab_instance()
|
2167
2200
|
gl = GitLabApi(instance, project_url=settings["repoUrl"], settings=settings)
|
2168
|
-
|
2201
|
+
state = init_state(integration=glhk.QONTRACT_INTEGRATION)
|
2202
|
+
merge_requests = glhk.get_merge_requests(True, gl, state=state)
|
2169
2203
|
|
2170
2204
|
columns = [
|
2171
2205
|
"id",
|
@@ -2200,7 +2234,7 @@ def app_interface_merge_queue(ctx):
|
|
2200
2234
|
|
2201
2235
|
@get.command()
|
2202
2236
|
@click.pass_context
|
2203
|
-
def app_interface_review_queue(ctx) -> None:
|
2237
|
+
def app_interface_review_queue(ctx: click.Context) -> None:
|
2204
2238
|
import reconcile.gitlab_housekeeping as glhk
|
2205
2239
|
|
2206
2240
|
settings = queries.get_app_interface_settings()
|
@@ -2217,7 +2251,7 @@ def app_interface_review_queue(ctx) -> None:
|
|
2217
2251
|
"labels",
|
2218
2252
|
]
|
2219
2253
|
|
2220
|
-
def get_mrs(repo, url) -> list[dict[str, str]]:
|
2254
|
+
def get_mrs(repo: str, url: str) -> list[dict[str, str]]:
|
2221
2255
|
gl = GitLabApi(instance, project_url=url, settings=settings)
|
2222
2256
|
merge_requests = gl.get_merge_requests(state=MRState.OPENED)
|
2223
2257
|
try:
|
@@ -2312,7 +2346,7 @@ def app_interface_review_queue(ctx) -> None:
|
|
2312
2346
|
|
2313
2347
|
@get.command()
|
2314
2348
|
@click.pass_context
|
2315
|
-
def app_interface_open_selfserviceable_mr_queue(ctx):
|
2349
|
+
def app_interface_open_selfserviceable_mr_queue(ctx: click.Context) -> None:
|
2316
2350
|
settings = queries.get_app_interface_settings()
|
2317
2351
|
instance = queries.get_gitlab_instance()
|
2318
2352
|
gl = GitLabApi(instance, project_url=settings["repoUrl"], settings=settings)
|
@@ -2375,7 +2409,7 @@ def app_interface_open_selfserviceable_mr_queue(ctx):
|
|
2375
2409
|
|
2376
2410
|
@get.command()
|
2377
2411
|
@click.pass_context
|
2378
|
-
def change_types(ctx) -> None:
|
2412
|
+
def change_types(ctx: click.Context) -> None:
|
2379
2413
|
"""List all change types."""
|
2380
2414
|
change_types = fetch_change_type_processors(gql.get_api(), NoOpFileDiffResolver())
|
2381
2415
|
|
@@ -2400,7 +2434,7 @@ def change_types(ctx) -> None:
|
|
2400
2434
|
|
2401
2435
|
@get.command()
|
2402
2436
|
@click.pass_context
|
2403
|
-
def app_interface_merge_history(ctx):
|
2437
|
+
def app_interface_merge_history(ctx: click.Context) -> None:
|
2404
2438
|
settings = queries.get_app_interface_settings()
|
2405
2439
|
instance = queries.get_gitlab_instance()
|
2406
2440
|
gl = GitLabApi(instance, project_url=settings["repoUrl"], settings=settings)
|
@@ -2437,7 +2471,7 @@ def app_interface_merge_history(ctx):
|
|
2437
2471
|
)
|
2438
2472
|
@use_jump_host()
|
2439
2473
|
@click.pass_context
|
2440
|
-
def selectorsyncset_managed_resources(ctx, use_jump_host):
|
2474
|
+
def selectorsyncset_managed_resources(ctx: click.Context, use_jump_host: bool) -> None:
|
2441
2475
|
vault_settings = get_app_interface_vault_settings()
|
2442
2476
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
2443
2477
|
clusters = get_clusters()
|
@@ -2495,7 +2529,9 @@ def selectorsyncset_managed_resources(ctx, use_jump_host):
|
|
2495
2529
|
)
|
2496
2530
|
@use_jump_host()
|
2497
2531
|
@click.pass_context
|
2498
|
-
def selectorsyncset_managed_hypershift_resources(
|
2532
|
+
def selectorsyncset_managed_hypershift_resources(
|
2533
|
+
ctx: click.Context, use_jump_host: bool
|
2534
|
+
) -> None:
|
2499
2535
|
vault_settings = get_app_interface_vault_settings()
|
2500
2536
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
2501
2537
|
clusters = get_clusters()
|
@@ -2573,7 +2609,12 @@ def selectorsyncset_managed_hypershift_resources(ctx, use_jump_host):
|
|
2573
2609
|
default=os.environ.get("QONTRACT_CLI_EC2_JENKINS_WORKER_AWS_REGION", "us-east-1"),
|
2574
2610
|
)
|
2575
2611
|
@click.pass_context
|
2576
|
-
def ec2_jenkins_workers(
|
2612
|
+
def ec2_jenkins_workers(
|
2613
|
+
ctx: click.Context,
|
2614
|
+
aws_access_key_id: str,
|
2615
|
+
aws_secret_access_key: str,
|
2616
|
+
aws_region: str,
|
2617
|
+
) -> None:
|
2577
2618
|
"""Prints a list of jenkins workers and their status."""
|
2578
2619
|
if not aws_access_key_id or not aws_secret_access_key:
|
2579
2620
|
raise click.ClickException(
|
@@ -2620,9 +2661,9 @@ def ec2_jenkins_workers(ctx, aws_access_key_id, aws_secret_access_key, aws_regio
|
|
2620
2661
|
url = ""
|
2621
2662
|
for t in instance.tags:
|
2622
2663
|
if t.get("Key") == "os":
|
2623
|
-
os = t
|
2664
|
+
os = t["Value"]
|
2624
2665
|
if t.get("Key") == "jenkins_controller":
|
2625
|
-
url = f"https://{t
|
2666
|
+
url = f"https://{t['Value'].replace('-', '.')}.devshift.net/computer/{instance.id}"
|
2626
2667
|
image = ec2.Image(instance.image_id)
|
2627
2668
|
commit_url = ""
|
2628
2669
|
for t in image.tags:
|
@@ -2649,7 +2690,7 @@ def ec2_jenkins_workers(ctx, aws_access_key_id, aws_secret_access_key, aws_regio
|
|
2649
2690
|
@get.command()
|
2650
2691
|
@click.argument("status-board-instance")
|
2651
2692
|
@click.pass_context
|
2652
|
-
def slo_document_services(ctx, status_board_instance):
|
2693
|
+
def slo_document_services(ctx: click.Context, status_board_instance: str) -> None:
|
2653
2694
|
"""Print SLO Documents Services"""
|
2654
2695
|
columns = [
|
2655
2696
|
"slo_doc_name",
|
@@ -2678,7 +2719,7 @@ def slo_document_services(ctx, status_board_instance):
|
|
2678
2719
|
slodocs = []
|
2679
2720
|
for slodoc in get_slo_documents():
|
2680
2721
|
products = [ns.namespace.environment.product.name for ns in slodoc.namespaces]
|
2681
|
-
for slo in slodoc.slos:
|
2722
|
+
for slo in slodoc.slos or []:
|
2682
2723
|
for product in products:
|
2683
2724
|
if slodoc.app.parent_app:
|
2684
2725
|
app = f"{slodoc.app.parent_app.name}-{slodoc.app.name}"
|
@@ -2704,7 +2745,7 @@ def slo_document_services(ctx, status_board_instance):
|
|
2704
2745
|
"target_unit": slo.slo_target_unit,
|
2705
2746
|
"window": slo.slo_parameters.window,
|
2706
2747
|
"statusBoardService": f"{product}/{slodoc.app.name}/{slo.name}",
|
2707
|
-
"statusBoardEnabled": "statusBoard" in slodoc.labels,
|
2748
|
+
"statusBoardEnabled": "statusBoard" in (slodoc.labels or {}),
|
2708
2749
|
}
|
2709
2750
|
slodocs.append(item)
|
2710
2751
|
|
@@ -2714,7 +2755,7 @@ def slo_document_services(ctx, status_board_instance):
|
|
2714
2755
|
@get.command()
|
2715
2756
|
@click.argument("file_path")
|
2716
2757
|
@click.pass_context
|
2717
|
-
def alerts(ctx, file_path):
|
2758
|
+
def alerts(ctx: click.Context, file_path: str) -> None:
|
2718
2759
|
BIG_NUMBER = 10
|
2719
2760
|
|
2720
2761
|
def sort_by_threshold(item: dict[str, str]) -> int:
|
@@ -2788,7 +2829,7 @@ def alerts(ctx, file_path):
|
|
2788
2829
|
@get.command()
|
2789
2830
|
@click.pass_context
|
2790
2831
|
@thread_pool_size(default=5)
|
2791
|
-
def aws_cost_report(ctx, thread_pool_size):
|
2832
|
+
def aws_cost_report(ctx: click.Context, thread_pool_size: int) -> None:
|
2792
2833
|
command = AwsCostReportCommand.create(thread_pool_size=thread_pool_size)
|
2793
2834
|
print(command.execute())
|
2794
2835
|
|
@@ -2796,7 +2837,7 @@ def aws_cost_report(ctx, thread_pool_size):
|
|
2796
2837
|
@get.command()
|
2797
2838
|
@click.pass_context
|
2798
2839
|
@thread_pool_size(default=5)
|
2799
|
-
def openshift_cost_report(ctx, thread_pool_size):
|
2840
|
+
def openshift_cost_report(ctx: click.Context, thread_pool_size: int) -> None:
|
2800
2841
|
command = OpenShiftCostReportCommand.create(thread_pool_size=thread_pool_size)
|
2801
2842
|
print(command.execute())
|
2802
2843
|
|
@@ -2804,7 +2845,9 @@ def openshift_cost_report(ctx, thread_pool_size):
|
|
2804
2845
|
@get.command()
|
2805
2846
|
@click.pass_context
|
2806
2847
|
@thread_pool_size(default=5)
|
2807
|
-
def openshift_cost_optimization_report(
|
2848
|
+
def openshift_cost_optimization_report(
|
2849
|
+
ctx: click.Context, thread_pool_size: int
|
2850
|
+
) -> None:
|
2808
2851
|
command = OpenShiftCostOptimizationReportCommand.create(
|
2809
2852
|
thread_pool_size=thread_pool_size
|
2810
2853
|
)
|
@@ -2813,7 +2856,7 @@ def openshift_cost_optimization_report(ctx, thread_pool_size):
|
|
2813
2856
|
|
2814
2857
|
@get.command()
|
2815
2858
|
@click.pass_context
|
2816
|
-
def osd_component_versions(ctx):
|
2859
|
+
def osd_component_versions(ctx: click.Context) -> None:
|
2817
2860
|
osd_environments = [
|
2818
2861
|
e["name"] for e in queries.get_environments() if e["product"]["name"] == "OSDv4"
|
2819
2862
|
]
|
@@ -2849,7 +2892,7 @@ def osd_component_versions(ctx):
|
|
2849
2892
|
|
2850
2893
|
@get.command()
|
2851
2894
|
@click.pass_context
|
2852
|
-
def maintenances(ctx):
|
2895
|
+
def maintenances(ctx: click.Context) -> None:
|
2853
2896
|
now = datetime.now(UTC)
|
2854
2897
|
maintenances = maintenances_gql.query(gql.get_api().query).maintenances or []
|
2855
2898
|
data = [
|
@@ -2912,7 +2955,7 @@ class MigrationStatusCount:
|
|
2912
2955
|
|
2913
2956
|
@get.command()
|
2914
2957
|
@click.pass_context
|
2915
|
-
def hcp_migration_status(ctx):
|
2958
|
+
def hcp_migration_status(ctx: click.Context) -> None:
|
2916
2959
|
counts: dict[str, MigrationStatusCount] = {}
|
2917
2960
|
total_count = MigrationStatusCount("total")
|
2918
2961
|
saas_files = get_saas_files()
|
@@ -2951,7 +2994,7 @@ def hcp_migration_status(ctx):
|
|
2951
2994
|
|
2952
2995
|
@get.command()
|
2953
2996
|
@click.pass_context
|
2954
|
-
def systems_and_tools(ctx):
|
2997
|
+
def systems_and_tools(ctx: click.Context) -> None:
|
2955
2998
|
print(
|
2956
2999
|
f"This report is obtained from app-interface Graphql endpoint available at: {config.get_config()['graphql']['server']}"
|
2957
3000
|
)
|
@@ -2965,7 +3008,7 @@ def systems_and_tools(ctx):
|
|
2965
3008
|
"--environment_name", default="production", help="environment to get logs from"
|
2966
3009
|
)
|
2967
3010
|
@click.pass_context
|
2968
|
-
def logs(ctx, integration_name: str, environment_name: str):
|
3011
|
+
def logs(ctx: click.Context, integration_name: str, environment_name: str) -> None:
|
2969
3012
|
integrations = [
|
2970
3013
|
i
|
2971
3014
|
for i in integrations_gql.query(query_func=gql.get_api().query).integrations
|
@@ -3004,7 +3047,7 @@ def logs(ctx, integration_name: str, environment_name: str):
|
|
3004
3047
|
|
3005
3048
|
@get.command
|
3006
3049
|
@click.pass_context
|
3007
|
-
def jenkins_jobs(ctx):
|
3050
|
+
def jenkins_jobs(ctx: click.Context) -> None:
|
3008
3051
|
jenkins_configs = queries.get_jenkins_configs()
|
3009
3052
|
|
3010
3053
|
# stats dicts
|
@@ -3074,9 +3117,9 @@ You can view the source of this Markdown to extract the JSON data.
|
|
3074
3117
|
|
3075
3118
|
@get.command
|
3076
3119
|
@click.pass_context
|
3077
|
-
def container_image_details(ctx):
|
3120
|
+
def container_image_details(ctx: click.Context) -> None:
|
3078
3121
|
apps = get_apps_quay_repos_escalation_policies()
|
3079
|
-
data: list[dict[str, str]] = []
|
3122
|
+
data: list[dict[str, str | list[str]]] = []
|
3080
3123
|
for app in apps:
|
3081
3124
|
app_name = f"{app.parent_app.name}/{app.name}" if app.parent_app else app.name
|
3082
3125
|
ep_channels = app.escalation_policy.channels
|
@@ -3088,7 +3131,7 @@ def container_image_details(ctx):
|
|
3088
3131
|
if repo.mirror:
|
3089
3132
|
continue
|
3090
3133
|
repository = f"quay.io/{org_name}/{repo.name}"
|
3091
|
-
item = {
|
3134
|
+
item: dict[str, str | list[str]] = {
|
3092
3135
|
"app": app_name,
|
3093
3136
|
"repository": repository,
|
3094
3137
|
"email": email,
|
@@ -3101,27 +3144,25 @@ def container_image_details(ctx):
|
|
3101
3144
|
|
3102
3145
|
@get.command
|
3103
3146
|
@click.pass_context
|
3104
|
-
def change_log_tracking(ctx):
|
3147
|
+
def change_log_tracking(ctx: click.Context) -> None:
|
3105
3148
|
repo_url = get_app_interface_repo_url()
|
3106
3149
|
change_types = fetch_change_type_processors(gql.get_api(), NoOpFileDiffResolver())
|
3107
3150
|
state = init_state(integration=cl.QONTRACT_INTEGRATION)
|
3108
3151
|
change_log = ChangeLog(**state.get(BUNDLE_DIFFS_OBJ))
|
3109
3152
|
data: list[dict[str, str]] = []
|
3110
|
-
for
|
3111
|
-
change_log_item = ChangeLogItem(**item)
|
3153
|
+
for change_log_item in change_log.items:
|
3112
3154
|
commit = change_log_item.commit
|
3113
3155
|
covered_change_types_descriptions = [
|
3114
3156
|
ct.description
|
3115
3157
|
for ct in change_types
|
3116
3158
|
if ct.name in change_log_item.change_types
|
3117
3159
|
]
|
3118
|
-
|
3160
|
+
data.append({
|
3119
3161
|
"commit": f"[{commit[:7]}]({repo_url}/commit/{commit})",
|
3120
3162
|
"merged_at": change_log_item.merged_at,
|
3121
3163
|
"apps": ", ".join(change_log_item.apps),
|
3122
3164
|
"changes": ", ".join(covered_change_types_descriptions),
|
3123
|
-
}
|
3124
|
-
data.append(item)
|
3165
|
+
})
|
3125
3166
|
|
3126
3167
|
# TODO(mafriedm): Fix this
|
3127
3168
|
ctx.obj["options"]["sort"] = False
|
@@ -3132,7 +3173,7 @@ def change_log_tracking(ctx):
|
|
3132
3173
|
@root.group(name="set")
|
3133
3174
|
@output
|
3134
3175
|
@click.pass_context
|
3135
|
-
def set_command(ctx, output):
|
3176
|
+
def set_command(ctx: click.Context, output: str) -> None:
|
3136
3177
|
ctx.obj["output"] = output
|
3137
3178
|
|
3138
3179
|
|
@@ -3141,7 +3182,9 @@ def set_command(ctx, output):
|
|
3141
3182
|
@click.argument("usergroup")
|
3142
3183
|
@click.argument("username")
|
3143
3184
|
@click.pass_context
|
3144
|
-
def slack_usergroup(
|
3185
|
+
def slack_usergroup(
|
3186
|
+
ctx: click.Context, workspace: str, usergroup: str, username: str
|
3187
|
+
) -> None:
|
3145
3188
|
"""Update users in a slack usergroup.
|
3146
3189
|
Use an org_username as the username.
|
3147
3190
|
To empty a slack usergroup, pass '' (empty string) as the username.
|
@@ -3149,6 +3192,8 @@ def slack_usergroup(ctx, workspace, usergroup, username):
|
|
3149
3192
|
settings = queries.get_app_interface_settings()
|
3150
3193
|
slack = slackapi_from_queries("qontract-cli")
|
3151
3194
|
ugid = slack.get_usergroup_id(usergroup)
|
3195
|
+
if not ugid:
|
3196
|
+
raise click.ClickException(f"Usergroup {usergroup} not found.")
|
3152
3197
|
if username:
|
3153
3198
|
mail_address = settings["smtp"]["mailAddress"]
|
3154
3199
|
users = [slack.get_user_id_by_name(username, mail_address)]
|
@@ -3157,33 +3202,17 @@ def slack_usergroup(ctx, workspace, usergroup, username):
|
|
3157
3202
|
slack.update_usergroup_users(ugid, users)
|
3158
3203
|
|
3159
3204
|
|
3160
|
-
@set_command.command()
|
3161
|
-
@click.argument("org_name")
|
3162
|
-
@click.argument("cluster_name")
|
3163
|
-
@click.pass_context
|
3164
|
-
def cluster_admin(ctx, org_name, cluster_name):
|
3165
|
-
settings = queries.get_app_interface_settings()
|
3166
|
-
ocms = [
|
3167
|
-
o for o in queries.get_openshift_cluster_managers() if o["name"] == org_name
|
3168
|
-
]
|
3169
|
-
ocm_map = OCMMap(ocms=ocms, settings=settings)
|
3170
|
-
ocm = ocm_map[org_name]
|
3171
|
-
enabled = ocm.is_cluster_admin_enabled(cluster_name)
|
3172
|
-
if not enabled:
|
3173
|
-
ocm.enable_cluster_admin(cluster_name)
|
3174
|
-
|
3175
|
-
|
3176
3205
|
@root.group()
|
3177
3206
|
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
3178
3207
|
@click.pass_context
|
3179
|
-
def state(ctx):
|
3208
|
+
def state(ctx: click.Context) -> None:
|
3180
3209
|
pass
|
3181
3210
|
|
3182
3211
|
|
3183
3212
|
@state.command()
|
3184
3213
|
@click.argument("integration", default="")
|
3185
3214
|
@click.pass_context
|
3186
|
-
def ls(ctx, integration):
|
3215
|
+
def ls(ctx: click.Context, integration: str) -> None:
|
3187
3216
|
state = init_state(integration=integration)
|
3188
3217
|
keys = state.ls()
|
3189
3218
|
# if integration in not defined the 2th token will be the integration name
|
@@ -3204,7 +3233,7 @@ def ls(ctx, integration):
|
|
3204
3233
|
@click.argument("integration")
|
3205
3234
|
@click.argument("key")
|
3206
3235
|
@click.pass_context
|
3207
|
-
def state_get(ctx, integration, key):
|
3236
|
+
def state_get(ctx: click.Context, integration: str, key: str) -> None:
|
3208
3237
|
state = init_state(integration=integration)
|
3209
3238
|
value = state.get(key)
|
3210
3239
|
print(value)
|
@@ -3214,7 +3243,7 @@ def state_get(ctx, integration, key):
|
|
3214
3243
|
@click.argument("integration")
|
3215
3244
|
@click.argument("key")
|
3216
3245
|
@click.pass_context
|
3217
|
-
def add(ctx, integration, key):
|
3246
|
+
def add(ctx: click.Context, integration: str, key: str) -> None:
|
3218
3247
|
state = init_state(integration=integration)
|
3219
3248
|
state.add(key)
|
3220
3249
|
|
@@ -3224,7 +3253,7 @@ def add(ctx, integration, key):
|
|
3224
3253
|
@click.argument("key")
|
3225
3254
|
@click.argument("value")
|
3226
3255
|
@click.pass_context
|
3227
|
-
def state_set(ctx, integration, key, value):
|
3256
|
+
def state_set(ctx: click.Context, integration: str, key: str, value: str) -> None:
|
3228
3257
|
state = init_state(integration=integration)
|
3229
3258
|
state.add(key, value=value, force=True)
|
3230
3259
|
|
@@ -3233,7 +3262,7 @@ def state_set(ctx, integration, key, value):
|
|
3233
3262
|
@click.argument("integration")
|
3234
3263
|
@click.argument("key")
|
3235
3264
|
@click.pass_context
|
3236
|
-
def rm(ctx, integration, key):
|
3265
|
+
def rm(ctx: click.Context, integration: str, key: str) -> None:
|
3237
3266
|
state = init_state(integration=integration)
|
3238
3267
|
state.rm(key)
|
3239
3268
|
|
@@ -3241,7 +3270,7 @@ def rm(ctx, integration, key):
|
|
3241
3270
|
@root.group()
|
3242
3271
|
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
3243
3272
|
@click.pass_context
|
3244
|
-
def early_exit_cache(ctx):
|
3273
|
+
def early_exit_cache(ctx: click.Context) -> None:
|
3245
3274
|
pass
|
3246
3275
|
|
3247
3276
|
|
@@ -3277,13 +3306,13 @@ def early_exit_cache(ctx):
|
|
3277
3306
|
)
|
3278
3307
|
@click.pass_context
|
3279
3308
|
def early_exit_cache_head(
|
3280
|
-
ctx,
|
3281
|
-
integration,
|
3282
|
-
integration_version,
|
3283
|
-
dry_run,
|
3284
|
-
cache_source,
|
3285
|
-
shard,
|
3286
|
-
):
|
3309
|
+
ctx: click.Context,
|
3310
|
+
integration: str,
|
3311
|
+
integration_version: str,
|
3312
|
+
dry_run: bool,
|
3313
|
+
cache_source: str,
|
3314
|
+
shard: str,
|
3315
|
+
) -> None:
|
3287
3316
|
with EarlyExitCache.build() as cache:
|
3288
3317
|
cache_key = CacheKey(
|
3289
3318
|
integration=integration,
|
@@ -3329,13 +3358,13 @@ def early_exit_cache_head(
|
|
3329
3358
|
)
|
3330
3359
|
@click.pass_context
|
3331
3360
|
def early_exit_cache_get(
|
3332
|
-
ctx,
|
3333
|
-
integration,
|
3334
|
-
integration_version,
|
3335
|
-
dry_run,
|
3336
|
-
cache_source,
|
3337
|
-
shard,
|
3338
|
-
):
|
3361
|
+
ctx: click.Context,
|
3362
|
+
integration: str,
|
3363
|
+
integration_version: str,
|
3364
|
+
dry_run: bool,
|
3365
|
+
cache_source: str,
|
3366
|
+
shard: str,
|
3367
|
+
) -> None:
|
3339
3368
|
with EarlyExitCache.build() as cache:
|
3340
3369
|
cache_key = CacheKey(
|
3341
3370
|
integration=integration,
|
@@ -3412,18 +3441,18 @@ def early_exit_cache_get(
|
|
3412
3441
|
)
|
3413
3442
|
@click.pass_context
|
3414
3443
|
def early_exit_cache_set(
|
3415
|
-
ctx,
|
3416
|
-
integration,
|
3417
|
-
integration_version,
|
3418
|
-
dry_run,
|
3419
|
-
cache_source,
|
3420
|
-
shard,
|
3421
|
-
payload,
|
3422
|
-
log_output,
|
3423
|
-
applied_count,
|
3424
|
-
ttl,
|
3425
|
-
latest_cache_source_digest,
|
3426
|
-
):
|
3444
|
+
ctx: click.Context,
|
3445
|
+
integration: str,
|
3446
|
+
integration_version: str,
|
3447
|
+
dry_run: bool,
|
3448
|
+
cache_source: str,
|
3449
|
+
shard: str,
|
3450
|
+
payload: str,
|
3451
|
+
log_output: str,
|
3452
|
+
applied_count: int,
|
3453
|
+
ttl: int,
|
3454
|
+
latest_cache_source_digest: str,
|
3455
|
+
) -> None:
|
3427
3456
|
with EarlyExitCache.build() as cache:
|
3428
3457
|
cache_key = CacheKey(
|
3429
3458
|
integration=integration,
|
@@ -3472,13 +3501,13 @@ def early_exit_cache_set(
|
|
3472
3501
|
)
|
3473
3502
|
@click.pass_context
|
3474
3503
|
def early_exit_cache_delete(
|
3475
|
-
ctx,
|
3476
|
-
integration,
|
3477
|
-
integration_version,
|
3478
|
-
dry_run,
|
3479
|
-
cache_source_digest,
|
3480
|
-
shard,
|
3481
|
-
):
|
3504
|
+
ctx: click.Context,
|
3505
|
+
integration: str,
|
3506
|
+
integration_version: str,
|
3507
|
+
dry_run: bool,
|
3508
|
+
cache_source_digest: str,
|
3509
|
+
shard: str,
|
3510
|
+
) -> None:
|
3482
3511
|
with EarlyExitCache.build() as cache:
|
3483
3512
|
cache_key_with_digest = CacheKeyWithDigest(
|
3484
3513
|
integration=integration,
|
@@ -3509,25 +3538,33 @@ def early_exit_cache_delete(
|
|
3509
3538
|
type=click.Choice(["config", "vault"]),
|
3510
3539
|
)
|
3511
3540
|
@click.pass_context
|
3512
|
-
def template(
|
3541
|
+
def template(
|
3542
|
+
ctx: click.Context,
|
3543
|
+
cluster: str,
|
3544
|
+
namespace: str,
|
3545
|
+
kind: str,
|
3546
|
+
name: str,
|
3547
|
+
path: str,
|
3548
|
+
secret_reader: str,
|
3549
|
+
) -> None:
|
3513
3550
|
gqlapi = gql.get_api()
|
3514
3551
|
namespaces = gqlapi.query(orb.NAMESPACES_QUERY)["namespaces"]
|
3515
|
-
|
3552
|
+
namespaces_info = [
|
3516
3553
|
n
|
3517
3554
|
for n in namespaces
|
3518
3555
|
if n["cluster"]["name"] == cluster and n["name"] == namespace
|
3519
3556
|
]
|
3520
|
-
if len(
|
3557
|
+
if len(namespaces_info) != 1:
|
3521
3558
|
print(f"{cluster}/{namespace} error")
|
3522
3559
|
sys.exit(1)
|
3523
3560
|
|
3561
|
+
namespace_info = namespaces_info[0]
|
3524
3562
|
settings = queries.get_app_interface_settings()
|
3525
3563
|
settings["vault"] = secret_reader == "vault"
|
3526
3564
|
|
3527
3565
|
if path and path.startswith("resources"):
|
3528
3566
|
path = path.replace("resources", "", 1)
|
3529
3567
|
|
3530
|
-
[namespace_info] = namespace_info
|
3531
3568
|
ob.aggregate_shared_resources(namespace_info, "openshiftResources")
|
3532
3569
|
openshift_resources = namespace_info.get("openshiftResources")
|
3533
3570
|
for r in openshift_resources:
|
@@ -3568,7 +3605,9 @@ def template(ctx, cluster, namespace, kind, name, path, secret_reader):
|
|
3568
3605
|
type=click.Choice(["config", "vault"]),
|
3569
3606
|
)
|
3570
3607
|
@click.pass_context
|
3571
|
-
def run_prometheus_test(
|
3608
|
+
def run_prometheus_test(
|
3609
|
+
ctx: click.Context, path: str, cluster: str, namespace: str, secret_reader: str
|
3610
|
+
) -> None:
|
3572
3611
|
"""Run prometheus tests for the rule associated with the test in the PATH from given
|
3573
3612
|
CLUSTER/NAMESPACE"""
|
3574
3613
|
|
@@ -3654,17 +3693,17 @@ def run_prometheus_test(ctx, path, cluster, namespace, secret_reader):
|
|
3654
3693
|
)
|
3655
3694
|
@click.pass_context
|
3656
3695
|
def alert_to_receiver(
|
3657
|
-
ctx,
|
3658
|
-
cluster,
|
3659
|
-
namespace,
|
3660
|
-
rules_path,
|
3661
|
-
alert_name,
|
3662
|
-
alertmanager_secret_path,
|
3663
|
-
alertmanager_namespace,
|
3664
|
-
alertmanager_secret_key,
|
3665
|
-
secret_reader,
|
3666
|
-
additional_label,
|
3667
|
-
):
|
3696
|
+
ctx: click.Context,
|
3697
|
+
cluster: str,
|
3698
|
+
namespace: str,
|
3699
|
+
rules_path: str,
|
3700
|
+
alert_name: str,
|
3701
|
+
alertmanager_secret_path: str,
|
3702
|
+
alertmanager_namespace: str,
|
3703
|
+
alertmanager_secret_key: str,
|
3704
|
+
secret_reader: str,
|
3705
|
+
additional_label: list[str],
|
3706
|
+
) -> None:
|
3668
3707
|
additional_labels = {}
|
3669
3708
|
for al in additional_label:
|
3670
3709
|
try:
|
@@ -3756,12 +3795,12 @@ def alert_to_receiver(
|
|
3756
3795
|
print(f"Cannot find alert {alert_name} in rules {rules_path}")
|
3757
3796
|
sys.exit(1)
|
3758
3797
|
|
3759
|
-
for
|
3760
|
-
result = amtool.config_routes_test(am_config,
|
3798
|
+
for label in alert_labels:
|
3799
|
+
result = amtool.config_routes_test(am_config, label)
|
3761
3800
|
if not result:
|
3762
3801
|
print(f"Error running amtool: {result}")
|
3763
3802
|
sys.exit(1)
|
3764
|
-
print("|".join([
|
3803
|
+
print("|".join([label["alertname"], str(result)]))
|
3765
3804
|
|
3766
3805
|
|
3767
3806
|
@root.command()
|
@@ -3769,7 +3808,12 @@ def alert_to_receiver(
|
|
3769
3808
|
@click.option("--saas-file-name", default=None, help="saas-file to act on.")
|
3770
3809
|
@click.option("--env-name", default=None, help="environment to use for parameters.")
|
3771
3810
|
@click.pass_context
|
3772
|
-
def saas_dev(
|
3811
|
+
def saas_dev(
|
3812
|
+
ctx: click.Context,
|
3813
|
+
app_name: str | None = None,
|
3814
|
+
saas_file_name: str | None = None,
|
3815
|
+
env_name: str | None = None,
|
3816
|
+
) -> None:
|
3773
3817
|
if not env_name:
|
3774
3818
|
print("env-name must be defined")
|
3775
3819
|
return
|
@@ -3817,7 +3861,7 @@ def saas_dev(ctx, app_name=None, saas_file_name=None, env_name=None) -> None:
|
|
3817
3861
|
@click.option("--app-name", default=None, help="app to act on.")
|
3818
3862
|
@click.pass_context
|
3819
3863
|
def saas_targets(
|
3820
|
-
ctx, saas_file_name: str | None = None, app_name: str | None = None
|
3864
|
+
ctx: click.Context, saas_file_name: str | None = None, app_name: str | None = None
|
3821
3865
|
) -> None:
|
3822
3866
|
"""Resolve namespaceSelectors and print all resulting targets of a saas file."""
|
3823
3867
|
console = Console()
|
@@ -3881,7 +3925,7 @@ def saas_targets(
|
|
3881
3925
|
default="json",
|
3882
3926
|
type=click.Choice(["json", "yaml"]),
|
3883
3927
|
)
|
3884
|
-
def query(output, query):
|
3928
|
+
def query(output: str, query: str) -> None:
|
3885
3929
|
"""Run a raw GraphQL query"""
|
3886
3930
|
gqlapi = gql.get_api()
|
3887
3931
|
result = gqlapi.query(query)
|
@@ -3895,7 +3939,7 @@ def query(output, query):
|
|
3895
3939
|
@root.command()
|
3896
3940
|
@click.argument("cluster")
|
3897
3941
|
@click.argument("query")
|
3898
|
-
def promquery(cluster, query):
|
3942
|
+
def promquery(cluster: str, query: str) -> None:
|
3899
3943
|
"""Run a PromQL query"""
|
3900
3944
|
config_data = config.get_config()
|
3901
3945
|
auth = {"path": config_data["promql-auth"]["secret_path"], "field": "token"}
|
@@ -3946,8 +3990,13 @@ def promquery(cluster, query):
|
|
3946
3990
|
default=False,
|
3947
3991
|
)
|
3948
3992
|
def sre_checkpoint_metadata(
|
3949
|
-
app_path
|
3950
|
-
|
3993
|
+
app_path: str,
|
3994
|
+
parent_ticket: str,
|
3995
|
+
jiraboard: str,
|
3996
|
+
jiradef: str,
|
3997
|
+
create_parent_ticket: bool,
|
3998
|
+
dry_run: bool,
|
3999
|
+
) -> None:
|
3951
4000
|
"""Check an app path for checkpoint-related metadata."""
|
3952
4001
|
data = queries.get_app_metadata(app_path)
|
3953
4002
|
settings = queries.get_app_interface_settings()
|
@@ -3986,8 +4035,13 @@ def sre_checkpoint_metadata(
|
|
3986
4035
|
required=True,
|
3987
4036
|
)
|
3988
4037
|
def gpg_encrypt(
|
3989
|
-
vault_path
|
3990
|
-
|
4038
|
+
vault_path: str,
|
4039
|
+
vault_secret_version: str,
|
4040
|
+
file_path: str,
|
4041
|
+
openshift_path: str,
|
4042
|
+
output: str,
|
4043
|
+
for_user: str,
|
4044
|
+
) -> None:
|
3991
4045
|
"""
|
3992
4046
|
Encrypt the specified secret (local file, vault or openshift) with a
|
3993
4047
|
given users gpg key. This is intended for easily sharing secrets with
|
@@ -4010,7 +4064,7 @@ def gpg_encrypt(
|
|
4010
4064
|
@click.option("--channel", help="the channel that state is part of")
|
4011
4065
|
@click.option("--sha", help="the commit sha we want state for")
|
4012
4066
|
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
4013
|
-
def get_promotion_state(channel: str, sha: str):
|
4067
|
+
def get_promotion_state(channel: str, sha: str) -> None:
|
4014
4068
|
from tools.saas_promotion_state.saas_promotion_state import (
|
4015
4069
|
SaasPromotionState,
|
4016
4070
|
)
|
@@ -4035,7 +4089,7 @@ def get_promotion_state(channel: str, sha: str):
|
|
4035
4089
|
@click.option("--sha", help="the commit sha we want state for")
|
4036
4090
|
@click.option("--publisher-id", help="the publisher id we want state for")
|
4037
4091
|
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
4038
|
-
def mark_promotion_state_successful(channel: str, sha: str, publisher_id: str):
|
4092
|
+
def mark_promotion_state_successful(channel: str, sha: str, publisher_id: str) -> None:
|
4039
4093
|
from tools.saas_promotion_state.saas_promotion_state import (
|
4040
4094
|
SaasPromotionState,
|
4041
4095
|
)
|
@@ -4059,7 +4113,9 @@ def mark_promotion_state_successful(channel: str, sha: str, publisher_id: str):
|
|
4059
4113
|
help="filesystem path to a local app-interface repo",
|
4060
4114
|
default=os.environ.get("APP_INTERFACE_PATH", None),
|
4061
4115
|
)
|
4062
|
-
def test_change_type(
|
4116
|
+
def test_change_type(
|
4117
|
+
change_type_name: str, role_name: str, app_interface_path: str
|
4118
|
+
) -> None:
|
4063
4119
|
from reconcile.change_owners import tester
|
4064
4120
|
|
4065
4121
|
# tester.test_change_type(change_type_name, datafile_path)
|
@@ -4068,7 +4124,7 @@ def test_change_type(change_type_name: str, role_name: str, app_interface_path:
|
|
4068
4124
|
|
4069
4125
|
@root.group()
|
4070
4126
|
@click.pass_context
|
4071
|
-
def sso_client(ctx):
|
4127
|
+
def sso_client(ctx: click.Context) -> None:
|
4072
4128
|
"""SSO client commands"""
|
4073
4129
|
|
4074
4130
|
|
@@ -4104,7 +4160,7 @@ def sso_client(ctx):
|
|
4104
4160
|
)
|
4105
4161
|
@click.pass_context
|
4106
4162
|
def create(
|
4107
|
-
ctx,
|
4163
|
+
ctx: click.Context,
|
4108
4164
|
client_name: str,
|
4109
4165
|
contact_email: str,
|
4110
4166
|
keycloak_instance_vault_path: str,
|
@@ -4138,7 +4194,7 @@ def create(
|
|
4138
4194
|
@sso_client.command()
|
4139
4195
|
@click.argument("sso-client-vault-secret-path", required=True)
|
4140
4196
|
@click.pass_context
|
4141
|
-
def remove(ctx, sso_client_vault_secret_path: str):
|
4197
|
+
def remove(ctx: click.Context, sso_client_vault_secret_path: str) -> None:
|
4142
4198
|
"""Remove an existing SSO client"""
|
4143
4199
|
vault_settings = get_app_interface_vault_settings()
|
4144
4200
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
@@ -4185,8 +4241,12 @@ def remove(ctx, sso_client_vault_secret_path: str):
|
|
4185
4241
|
)
|
4186
4242
|
@click.pass_context
|
4187
4243
|
def external_resources(
|
4188
|
-
ctx
|
4189
|
-
|
4244
|
+
ctx: click.Context,
|
4245
|
+
provision_provider: str,
|
4246
|
+
provisioner: str,
|
4247
|
+
provider: str,
|
4248
|
+
identifier: str,
|
4249
|
+
) -> None:
|
4190
4250
|
"""External resources commands"""
|
4191
4251
|
ctx.obj["provision_provider"] = provision_provider
|
4192
4252
|
ctx.obj["provisioner"] = provisioner
|
@@ -4198,7 +4258,7 @@ def external_resources(
|
|
4198
4258
|
|
4199
4259
|
@external_resources.command()
|
4200
4260
|
@click.pass_context
|
4201
|
-
def get_input(ctx):
|
4261
|
+
def get_input(ctx: click.Context) -> None:
|
4202
4262
|
"""Gets the input data for an external resource asset. Input data is what is used
|
4203
4263
|
in the Reconciliation Job to manage the resource."""
|
4204
4264
|
erv2cli = Erv2Cli(
|
@@ -4213,7 +4273,7 @@ def get_input(ctx):
|
|
4213
4273
|
|
4214
4274
|
@external_resources.command()
|
4215
4275
|
@click.pass_context
|
4216
|
-
def request_reconciliation(ctx):
|
4276
|
+
def request_reconciliation(ctx: click.Context) -> None:
|
4217
4277
|
"""Marks a resource as it needs to get reconciled. The itegration will reconcile the resource at
|
4218
4278
|
its next iteration."""
|
4219
4279
|
erv2cli = Erv2Cli(
|
@@ -4240,7 +4300,7 @@ def request_reconciliation(ctx):
|
|
4240
4300
|
default=False,
|
4241
4301
|
)
|
4242
4302
|
@click.pass_context
|
4243
|
-
def migrate(ctx, dry_run: bool, skip_build: bool) -> None:
|
4303
|
+
def migrate(ctx: click.Context, dry_run: bool, skip_build: bool) -> None:
|
4244
4304
|
"""Migrate an existing external resource managed by terraform-resources to ERv2.
|
4245
4305
|
|
4246
4306
|
|
@@ -4346,7 +4406,7 @@ def migrate(ctx, dry_run: bool, skip_build: bool) -> None:
|
|
4346
4406
|
@external_resources.command()
|
4347
4407
|
@binary(["docker"])
|
4348
4408
|
@click.pass_context
|
4349
|
-
def debug_shell(ctx) -> None:
|
4409
|
+
def debug_shell(ctx: click.Context) -> None:
|
4350
4410
|
"""Enter an ERv2 debug shell to manually migrate resources."""
|
4351
4411
|
# use a temporary directory in $HOME. The MacOS colima default configuration allows docker mounts from $HOME.
|
4352
4412
|
with tempfile.TemporaryDirectory(dir=Path.home(), prefix="erv2-debug.") as _tempdir:
|
@@ -4385,7 +4445,7 @@ def debug_shell(ctx) -> None:
|
|
4385
4445
|
prompt=True,
|
4386
4446
|
)
|
4387
4447
|
@click.pass_context
|
4388
|
-
def force_unlock(ctx, lock_id: str) -> None:
|
4448
|
+
def force_unlock(ctx: click.Context, lock_id: str) -> None:
|
4389
4449
|
"""Manually unlock the ERv2 terraform state."""
|
4390
4450
|
# use a temporary directory in $HOME. The MacOS colima default configuration allows docker mounts from $HOME.
|
4391
4451
|
with tempfile.TemporaryDirectory(
|
@@ -4426,14 +4486,14 @@ def force_unlock(ctx, lock_id: str) -> None:
|
|
4426
4486
|
@click.option("--include-pattern", help="Only include images that match this pattern")
|
4427
4487
|
@click.pass_context
|
4428
4488
|
def container_images(
|
4429
|
-
ctx,
|
4430
|
-
cluster_name,
|
4431
|
-
namespace_name,
|
4432
|
-
thread_pool_size,
|
4433
|
-
use_jump_host,
|
4434
|
-
exclude_pattern,
|
4435
|
-
include_pattern,
|
4436
|
-
):
|
4489
|
+
ctx: click.Context,
|
4490
|
+
cluster_name: str,
|
4491
|
+
namespace_name: str,
|
4492
|
+
thread_pool_size: int,
|
4493
|
+
use_jump_host: bool,
|
4494
|
+
exclude_pattern: str,
|
4495
|
+
include_pattern: str,
|
4496
|
+
) -> None:
|
4437
4497
|
from tools.cli_commands.container_images_report import get_all_pods_images
|
4438
4498
|
|
4439
4499
|
results = get_all_pods_images(
|
@@ -4480,7 +4540,7 @@ You can view the source of this Markdown to extract the JSON data.
|
|
4480
4540
|
@get.command(help="Get all app tekton pipelines providers roles and users")
|
4481
4541
|
@click.argument("app-name")
|
4482
4542
|
@click.pass_context
|
4483
|
-
def tekton_roles_and_users(ctx, app_name):
|
4543
|
+
def tekton_roles_and_users(ctx: click.Context, app_name: str) -> None:
|
4484
4544
|
pp_namespaces = {
|
4485
4545
|
p.namespace.path
|
4486
4546
|
for p in get_tekton_pipeline_providers()
|
@@ -4507,6 +4567,7 @@ def tekton_roles_and_users(ctx, app_name):
|
|
4507
4567
|
if not seen:
|
4508
4568
|
seen = True
|
4509
4569
|
|
4570
|
+
users: str | list[str]
|
4510
4571
|
if ctx.obj["options"]["output"] == "table":
|
4511
4572
|
users = ", ".join([u.org_username for u in r.users])
|
4512
4573
|
else:
|
@@ -4526,7 +4587,7 @@ def tekton_roles_and_users(ctx, app_name):
|
|
4526
4587
|
)
|
4527
4588
|
@click.argument("aws-account")
|
4528
4589
|
@click.pass_context
|
4529
|
-
def log_group_usage(ctx, aws_account):
|
4590
|
+
def log_group_usage(ctx: click.Context, aws_account: str) -> None:
|
4530
4591
|
accounts = queries.get_aws_accounts(name=aws_account)
|
4531
4592
|
if not accounts:
|
4532
4593
|
print("no aws account found with that name")
|
@@ -4536,7 +4597,7 @@ def log_group_usage(ctx, aws_account):
|
|
4536
4597
|
settings = queries.get_app_interface_settings()
|
4537
4598
|
secret_reader = SecretReader(settings=settings)
|
4538
4599
|
columns = ["log_group", "stored_bytes", "retention_days"]
|
4539
|
-
results = []
|
4600
|
+
results: list[dict[str, str | int]] = []
|
4540
4601
|
|
4541
4602
|
with AWSApi(1, [account], settings, secret_reader) as aws:
|
4542
4603
|
session = aws.get_session(account["name"])
|