qontract-reconcile 0.10.2.dev20__py3-none-any.whl → 0.10.2.dev22__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.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/RECORD +7 -7
- reconcile/utils/dynatrace/client.py +31 -0
- tools/cli_commands/erv2.py +35 -0
- tools/qontract_cli.py +41 -0
- {qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev22
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
{qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/RECORD
RENAMED
@@ -657,7 +657,7 @@ reconcile/utils/clusterhealth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
657
657
|
reconcile/utils/clusterhealth/providerbase.py,sha256=DXomGYogckBLqWtXn0PXU0hWYxB6K0F7ernldrkHhVY,1140
|
658
658
|
reconcile/utils/clusterhealth/telemeter.py,sha256=PllSLsJXvGNatmTF4mxCNPVbDrpr_MPk0m5pWj-LT6g,1534
|
659
659
|
reconcile/utils/dynatrace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
660
|
-
reconcile/utils/dynatrace/client.py,sha256=
|
660
|
+
reconcile/utils/dynatrace/client.py,sha256=RUk6KH-3CJyfJ1jolrdGQR4Hhz-tIWWJo9dsZ1IgJVw,3736
|
661
661
|
reconcile/utils/glitchtip/__init__.py,sha256=FT6iBhGqoe7KExFdbgL8AYUb64iW_4snF5__Dcl7yt0,258
|
662
662
|
reconcile/utils/glitchtip/client.py,sha256=ovh4tx-ajlihjvcq6nyY4chulbuMJYvzDPv9j9CuAKM,7867
|
663
663
|
reconcile/utils/glitchtip/models.py,sha256=AJuGq4_A6G_T7asBKIw69-fOZLmT8HFrTKBEys7Tp00,6481
|
@@ -739,12 +739,12 @@ tools/app_interface_metrics_exporter.py,sha256=f1qwTmQfEcs98uBVRyBa0k7GQXdiSwd7w
|
|
739
739
|
tools/app_interface_reporter.py,sha256=gR2EgHmgSIxzK5xxDW1SduFU6OkPaf2LlAQjhV3NYIg,17623
|
740
740
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
741
741
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
742
|
-
tools/qontract_cli.py,sha256=
|
742
|
+
tools/qontract_cli.py,sha256=T637u3EVpodta2SSIjMa-3doLqXci1AEDt3Bspng4mE,145561
|
743
743
|
tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaBNFA,5062
|
744
744
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
745
745
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
746
746
|
tools/cli_commands/container_images_report.py,sha256=8fG9XU-eEhJ7hKCdQzBcdPpvIJR-8WGkHOgFEulpfYQ,5213
|
747
|
-
tools/cli_commands/erv2.py,sha256=
|
747
|
+
tools/cli_commands/erv2.py,sha256=1eilft_xwfGDQAMuOitKCzZw21Abmh0aDdCTafT1unw,23380
|
748
748
|
tools/cli_commands/gpg_encrypt.py,sha256=NhzwN49UN7P5_FJgTUN5A4BIwNbFokIE4lwDax2iP5k,4891
|
749
749
|
tools/cli_commands/systems_and_tools.py,sha256=EMHOF1AtUDaoSk0bbjl6oUKYAz4rTZjIBaF-6E6GspM,16816
|
750
750
|
tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -766,7 +766,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
766
766
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
767
767
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
768
768
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
769
|
-
qontract_reconcile-0.10.2.
|
770
|
-
qontract_reconcile-0.10.2.
|
771
|
-
qontract_reconcile-0.10.2.
|
772
|
-
qontract_reconcile-0.10.2.
|
769
|
+
qontract_reconcile-0.10.2.dev22.dist-info/METADATA,sha256=1szHp6oUOSn63z-WQ3M1bafK9dvg3AKmmfpNIyBboyY,24665
|
770
|
+
qontract_reconcile-0.10.2.dev22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
771
|
+
qontract_reconcile-0.10.2.dev22.dist-info/entry_points.txt,sha256=JniHZPadNOILPyfSl0LF2YSp3Db7K2_W2CN7i9f3Gos,540
|
772
|
+
qontract_reconcile-0.10.2.dev22.dist-info/RECORD,,
|
@@ -1,6 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from collections.abc import Iterable
|
4
|
+
from datetime import datetime
|
5
|
+
from unittest.mock import patch
|
4
6
|
|
5
7
|
from dynatrace import Dynatrace
|
6
8
|
from dynatrace.environment_v2.tokens_api import ApiTokenUpdate
|
@@ -33,11 +35,32 @@ class DynatraceAPIToken(BaseModel):
|
|
33
35
|
scopes: list[str]
|
34
36
|
|
35
37
|
|
38
|
+
# TODO: Remove once APPSRE-11428 is resolved #######
|
39
|
+
ISO_8601 = "%Y-%m-%dT%H:%M:%S.%fZ"
|
40
|
+
FIXED_ISO_8601 = "%Y-%m-%dT%H:%M:%SZ"
|
41
|
+
|
42
|
+
|
43
|
+
def custom_iso8601_to_datetime(timestamp: str | None) -> datetime | None:
|
44
|
+
if isinstance(timestamp, str):
|
45
|
+
try:
|
46
|
+
return datetime.strptime(timestamp, ISO_8601)
|
47
|
+
except ValueError:
|
48
|
+
return datetime.strptime(timestamp, FIXED_ISO_8601)
|
49
|
+
return timestamp
|
50
|
+
|
51
|
+
|
52
|
+
################################################
|
53
|
+
|
54
|
+
|
36
55
|
class DynatraceClient:
|
37
56
|
def __init__(self, environment_url: str, api: Dynatrace) -> None:
|
38
57
|
self._environment_url = environment_url
|
39
58
|
self._api = api
|
40
59
|
|
60
|
+
@patch(
|
61
|
+
"dynatrace.environment_v2.tokens_api.iso8601_to_datetime",
|
62
|
+
custom_iso8601_to_datetime,
|
63
|
+
)
|
41
64
|
def create_api_token(
|
42
65
|
self, name: str, scopes: Iterable[str]
|
43
66
|
) -> DynatraceAPITokenCreated:
|
@@ -49,6 +72,10 @@ class DynatraceClient:
|
|
49
72
|
) from e
|
50
73
|
return DynatraceAPITokenCreated(token=token.token, id=token.id)
|
51
74
|
|
75
|
+
@patch(
|
76
|
+
"dynatrace.environment_v2.tokens_api.iso8601_to_datetime",
|
77
|
+
custom_iso8601_to_datetime,
|
78
|
+
)
|
52
79
|
def get_token_ids_map_for_name_prefix(self, prefix: str) -> dict[str, str]:
|
53
80
|
try:
|
54
81
|
dt_tokens = self._api.tokens.list()
|
@@ -60,6 +87,10 @@ class DynatraceClient:
|
|
60
87
|
token.id: token.name for token in dt_tokens if token.name.startswith(prefix)
|
61
88
|
}
|
62
89
|
|
90
|
+
@patch(
|
91
|
+
"dynatrace.environment_v2.tokens_api.iso8601_to_datetime",
|
92
|
+
custom_iso8601_to_datetime,
|
93
|
+
)
|
63
94
|
def get_token_by_id(self, token_id: str) -> DynatraceAPIToken:
|
64
95
|
try:
|
65
96
|
token = self._api.tokens.get(token_id=token_id)
|
tools/cli_commands/erv2.py
CHANGED
@@ -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
|
{qontract_reconcile-0.10.2.dev20.dist-info → qontract_reconcile-0.10.2.dev22.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|