checkmk-dev-tools 2.1.4__tar.gz → 2.3.0__tar.gz
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.
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/PKG-INFO +2 -2
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/ci_artifacts.py +103 -46
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/version.py +1 -1
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/pyproject.toml +2 -2
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/README.md +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/__init__.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/activity_from_fs.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/binreplace.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/check_rpath.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/cli.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/cpumon.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/decent_output.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/jenkins_utils/__init__.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/job_resource_usage.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/last_access.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/lockable_resources.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/procmon.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/pycinfo.py +0 -0
- {checkmk_dev_tools-2.1.4 → checkmk_dev_tools-2.3.0}/cmk_dev/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: checkmk-dev-tools
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Checkmk DevOps tools
|
|
5
5
|
Author: Frans Fürst
|
|
6
6
|
Author-email: frans.fuerst@checkmk.com
|
|
@@ -14,7 +14,7 @@ Requires-Dist: pydantic (>=2,<3)
|
|
|
14
14
|
Requires-Dist: python-jenkins (>=1.8.3,<1.9.0)
|
|
15
15
|
Requires-Dist: rich
|
|
16
16
|
Requires-Dist: trickkiste (>=0.3.4,<0.4.0)
|
|
17
|
-
Project-URL: Changelog, https://github.com/Checkmk/checkmk-dev-tools/blob/release/2.
|
|
17
|
+
Project-URL: Changelog, https://github.com/Checkmk/checkmk-dev-tools/blob/release/2.3.0/changelog.md
|
|
18
18
|
Project-URL: Repository, https://github.com/Checkmk/checkmk-dev-tools
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
|
|
@@ -24,7 +24,7 @@ from datetime import datetime
|
|
|
24
24
|
from itertools import chain
|
|
25
25
|
from pathlib import Path
|
|
26
26
|
from subprocess import check_output
|
|
27
|
-
from typing import Any, List, Literal, cast
|
|
27
|
+
from typing import Any, List, Literal, TypedDict, cast
|
|
28
28
|
|
|
29
29
|
import requests
|
|
30
30
|
from influxdb_client import InfluxDBClient # type: ignore[attr-defined]
|
|
@@ -56,6 +56,12 @@ from .version import __version__
|
|
|
56
56
|
|
|
57
57
|
PathHashes = Mapping[str, str]
|
|
58
58
|
shared_build_info: asyncio.Queue[str] = asyncio.Queue(maxsize=1)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class FetchResult(TypedDict):
|
|
62
|
+
result: None | JobResult
|
|
63
|
+
artifacts: list[str]
|
|
64
|
+
|
|
59
65
|
MAX_RETRY_ATTEMPTS = 3
|
|
60
66
|
|
|
61
67
|
|
|
@@ -311,7 +317,7 @@ def download_artifacts(
|
|
|
311
317
|
total_download_timeout: int = 240,
|
|
312
318
|
no_remove_others: bool = False,
|
|
313
319
|
no_raise: bool = False,
|
|
314
|
-
) -> tuple[Sequence[str
|
|
320
|
+
) -> tuple[Sequence[str], Sequence[str]]:
|
|
315
321
|
"""Downloads all artifacts listed for given job/build to @out_dir"""
|
|
316
322
|
# pylint: disable=protected-access
|
|
317
323
|
# pylint: disable=too-many-locals
|
|
@@ -733,6 +739,7 @@ async def _fn_request_build(args: Args) -> None:
|
|
|
733
739
|
path_hashes=compose_path_hashes(args.base_dir, args.dependency_paths),
|
|
734
740
|
time_constraints=args.time_constraints,
|
|
735
741
|
next_check_sleep=args.poll_queue_sleep,
|
|
742
|
+
ignore_build_queue=args.ignore_build_queue,
|
|
736
743
|
args=args,
|
|
737
744
|
)
|
|
738
745
|
):
|
|
@@ -901,54 +908,72 @@ def query_matching_builds(
|
|
|
901
908
|
return []
|
|
902
909
|
|
|
903
910
|
|
|
904
|
-
async def
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
911
|
+
async def fetch_artifacts(
|
|
912
|
+
job: str,
|
|
913
|
+
params: None | JobParams = None,
|
|
914
|
+
*,
|
|
915
|
+
out_dir: Path = Path("out"),
|
|
916
|
+
base_dir: Path = Path("."),
|
|
917
|
+
params_no_check: None | JobParams = None,
|
|
918
|
+
dependency_paths: None | Sequence[str] = None,
|
|
919
|
+
time_constraints: None | str = None,
|
|
920
|
+
force_new_build: bool = False,
|
|
921
|
+
omit_new_build: bool = False,
|
|
922
|
+
download: bool = True,
|
|
923
|
+
no_remove_others: bool = False,
|
|
924
|
+
no_raise: bool = False,
|
|
925
|
+
poll_queue_sleep: int = 30,
|
|
926
|
+
poll_sleep: int = 60,
|
|
927
|
+
timeout: int = 120,
|
|
928
|
+
total_download_timeout: int = 240,
|
|
929
|
+
credentials: None | Mapping[str, str] = None,
|
|
930
|
+
credentials_file: str = "~/.config/jenkins_jobs/jenkins_jobs.ini",
|
|
931
|
+
) -> FetchResult:
|
|
932
|
+
"""Find or trigger a matching build, wait for it, download artifacts, return result dict."""
|
|
933
|
+
resolved_out_dir = compose_out_dir(base_dir, out_dir)
|
|
934
|
+
path_hashes = compose_path_hashes(base_dir, dependency_paths or [])
|
|
908
935
|
async with AugmentedJenkinsClient(
|
|
909
|
-
**extract_credentials(
|
|
936
|
+
**extract_credentials(credentials, credentials_file=credentials_file), timeout=timeout
|
|
910
937
|
) as jenkins_client:
|
|
911
|
-
if not (
|
|
912
|
-
raise Fatal(f"{
|
|
913
|
-
# In case we force a new build anyway we don't have to look for an existing one
|
|
938
|
+
if not (job_info := await jenkins_client.job_info(job)).type == "WorkflowJob":
|
|
939
|
+
raise Fatal(f"{job} is not a WorkflowJob")
|
|
914
940
|
matching_build = (
|
|
915
941
|
None
|
|
916
|
-
if
|
|
942
|
+
if force_new_build
|
|
917
943
|
else await identify_matching_build(
|
|
918
|
-
|
|
944
|
+
job_info,
|
|
919
945
|
jenkins_client=jenkins_client,
|
|
920
|
-
params=
|
|
921
|
-
path_hashes=
|
|
922
|
-
time_constraints=
|
|
923
|
-
next_check_sleep=
|
|
924
|
-
args=args,
|
|
946
|
+
params=params,
|
|
947
|
+
path_hashes=path_hashes,
|
|
948
|
+
time_constraints=time_constraints,
|
|
949
|
+
next_check_sleep=poll_queue_sleep,
|
|
925
950
|
)
|
|
926
951
|
)
|
|
927
|
-
if
|
|
928
|
-
raise Fatal(
|
|
929
|
-
|
|
952
|
+
if omit_new_build and not matching_build:
|
|
953
|
+
raise Fatal(
|
|
954
|
+
f"No matching build found for job '{job_info.name}' but new builds are omitted."
|
|
955
|
+
)
|
|
930
956
|
build_candidate = matching_build or await trigger_build(
|
|
931
957
|
jenkins_client=jenkins_client,
|
|
932
|
-
job=
|
|
958
|
+
job=job_info,
|
|
933
959
|
params=compose_build_params(
|
|
934
|
-
params=
|
|
935
|
-
params_no_check=
|
|
936
|
-
path_hashes=
|
|
960
|
+
params=params,
|
|
961
|
+
params_no_check=params_no_check,
|
|
962
|
+
path_hashes=path_hashes,
|
|
937
963
|
),
|
|
938
|
-
next_check_sleep=
|
|
964
|
+
next_check_sleep=poll_queue_sleep,
|
|
939
965
|
)
|
|
940
|
-
|
|
941
966
|
for key, value in build_candidate.__dict__.items():
|
|
942
967
|
log().debug(" %s: %s", key, value)
|
|
943
|
-
|
|
944
968
|
completed_build = await await_build(
|
|
945
|
-
|
|
969
|
+
job_info.path,
|
|
946
970
|
build_candidate.number,
|
|
947
971
|
jenkins_client=jenkins_client,
|
|
948
972
|
check_result=True,
|
|
949
973
|
path_hashes=path_hashes,
|
|
950
|
-
next_check_sleep=
|
|
951
|
-
no_raise=
|
|
974
|
+
next_check_sleep=poll_sleep,
|
|
975
|
+
no_raise=no_raise,
|
|
976
|
+
download=download,
|
|
952
977
|
)
|
|
953
978
|
downloaded_artifacts = (
|
|
954
979
|
list(
|
|
@@ -956,25 +981,44 @@ async def _fn_fetch(args: Args) -> None:
|
|
|
956
981
|
*download_artifacts(
|
|
957
982
|
jenkins_client.client,
|
|
958
983
|
completed_build,
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
984
|
+
resolved_out_dir,
|
|
985
|
+
total_download_timeout,
|
|
986
|
+
no_remove_others,
|
|
987
|
+
no_raise,
|
|
963
988
|
)
|
|
964
989
|
)
|
|
965
990
|
)
|
|
966
|
-
if
|
|
991
|
+
if download
|
|
967
992
|
else []
|
|
968
993
|
)
|
|
994
|
+
return {"result": completed_build.result, "artifacts": downloaded_artifacts}
|
|
969
995
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
996
|
+
|
|
997
|
+
async def _fn_fetch(args: Args) -> None:
|
|
998
|
+
"""Entry point for fetching (request and download combined) artifacts"""
|
|
999
|
+
print(
|
|
1000
|
+
json.dumps(
|
|
1001
|
+
await fetch_artifacts(
|
|
1002
|
+
job=args.job,
|
|
1003
|
+
params=flatten(args.params),
|
|
1004
|
+
out_dir=args.out_dir,
|
|
1005
|
+
base_dir=args.base_dir,
|
|
1006
|
+
params_no_check=flatten(args.params_no_check),
|
|
1007
|
+
dependency_paths=args.dependency_paths,
|
|
1008
|
+
time_constraints=args.time_constraints,
|
|
1009
|
+
force_new_build=args.force_new_build,
|
|
1010
|
+
omit_new_build=args.omit_new_build,
|
|
1011
|
+
download=args.download,
|
|
1012
|
+
no_remove_others=args.no_remove_others,
|
|
1013
|
+
no_raise=args.no_raise,
|
|
1014
|
+
poll_queue_sleep=args.poll_queue_sleep,
|
|
1015
|
+
poll_sleep=args.poll_sleep,
|
|
1016
|
+
timeout=args.timeout,
|
|
1017
|
+
total_download_timeout=args.total_download_timeout,
|
|
1018
|
+
credentials=args.credentials,
|
|
976
1019
|
)
|
|
977
1020
|
)
|
|
1021
|
+
)
|
|
978
1022
|
|
|
979
1023
|
|
|
980
1024
|
async def identify_matching_build(
|
|
@@ -985,6 +1029,7 @@ async def identify_matching_build(
|
|
|
985
1029
|
path_hashes: PathHashes,
|
|
986
1030
|
time_constraints: None | str,
|
|
987
1031
|
next_check_sleep: int = 30,
|
|
1032
|
+
ignore_build_queue: bool = False,
|
|
988
1033
|
args: None | Args = None,
|
|
989
1034
|
) -> None | Build:
|
|
990
1035
|
"""Find an existing build (finished, still running or queued) which matches our
|
|
@@ -1093,13 +1138,16 @@ async def identify_matching_build(
|
|
|
1093
1138
|
f"Got {len(matching_builds)} InfluxDB job history entries of today, generated {len(builds)} builds to check"
|
|
1094
1139
|
)
|
|
1095
1140
|
|
|
1141
|
+
log().info("Check for matching existing builds")
|
|
1096
1142
|
# ugly code duplication incomming, rework this to a dedicated function
|
|
1097
1143
|
for build in list(builds.values()):
|
|
1098
1144
|
if meets_constraints(build, params, time_constraints, path_hashes):
|
|
1099
1145
|
log().info("found matching (may finished) build: %s (%s)", build.number, build.url)
|
|
1100
1146
|
return build
|
|
1147
|
+
log().info("No matching builds found in the InfluxDB")
|
|
1101
1148
|
|
|
1102
|
-
|
|
1149
|
+
log().info("Check for matching queue items via Jenkins API")
|
|
1150
|
+
if not ignore_build_queue:
|
|
1103
1151
|
if matching_item := await find_matching_queue_item(
|
|
1104
1152
|
jenkins_client=jenkins_client,
|
|
1105
1153
|
job=job,
|
|
@@ -1107,33 +1155,40 @@ async def identify_matching_build(
|
|
|
1107
1155
|
path_hashes=path_hashes,
|
|
1108
1156
|
next_check_sleep=next_check_sleep,
|
|
1109
1157
|
):
|
|
1110
|
-
log().
|
|
1158
|
+
log().info("Found matching queued item %s", matching_item)
|
|
1111
1159
|
return await jenkins_client.build_info(job.path, matching_item)
|
|
1160
|
+
log().info("No matching queue items found via Jenkins API")
|
|
1112
1161
|
|
|
1113
1162
|
# exit here with no matching result if
|
|
1114
1163
|
# - the InfluxDB connection was a success
|
|
1115
1164
|
# - and some data was found by the query
|
|
1116
1165
|
# otherwise fall back to the old Jenkins job history crawling
|
|
1117
1166
|
if influx_client.health().status == "pass" and matching_builds:
|
|
1167
|
+
log().info("Return None and schedule a new build")
|
|
1118
1168
|
return None
|
|
1119
1169
|
|
|
1120
|
-
log().
|
|
1170
|
+
log().info("Start finding matching build via Jenkins API")
|
|
1121
1171
|
# fetch a job's build history first
|
|
1122
1172
|
await job.expand(jenkins_client)
|
|
1123
1173
|
|
|
1174
|
+
log().info("Check for matching existing builds")
|
|
1124
1175
|
# Look for finished builds
|
|
1125
1176
|
for build in filter(lambda b: b.completed, job.build_infos.values()):
|
|
1126
1177
|
if meets_constraints(build, params, time_constraints, path_hashes):
|
|
1127
1178
|
log().info("found matching finished build: %s (%s)", build.number, build.url)
|
|
1128
1179
|
return build
|
|
1180
|
+
log().info("No matching builds found via the Jenkins API")
|
|
1129
1181
|
|
|
1182
|
+
log().info("Check for matching non finished builds")
|
|
1130
1183
|
# Look for still unfinished builds
|
|
1131
1184
|
for build in filter(lambda b: not b.completed, job.build_infos.values()):
|
|
1132
1185
|
if meets_constraints(build, params, time_constraints, path_hashes):
|
|
1133
1186
|
log().info("found matching unfinished build: %s (%s)", build.number, build.url)
|
|
1134
1187
|
return build
|
|
1188
|
+
log().info("No matching non finished builds found via the Jenkins API")
|
|
1135
1189
|
|
|
1136
|
-
|
|
1190
|
+
log().info("Check for matching queue items via Jenkins API")
|
|
1191
|
+
if not ignore_build_queue:
|
|
1137
1192
|
if matching_item := await find_matching_queue_item(
|
|
1138
1193
|
jenkins_client=jenkins_client,
|
|
1139
1194
|
job=job,
|
|
@@ -1141,9 +1196,11 @@ async def identify_matching_build(
|
|
|
1141
1196
|
path_hashes=path_hashes,
|
|
1142
1197
|
next_check_sleep=next_check_sleep,
|
|
1143
1198
|
):
|
|
1144
|
-
log().
|
|
1199
|
+
log().info("Found matching queued item %s", matching_item)
|
|
1145
1200
|
return await jenkins_client.build_info(job.path, matching_item)
|
|
1201
|
+
log().info("No matching queue items found via Jenkins API")
|
|
1146
1202
|
|
|
1203
|
+
log().info("Return None and schedule a new build")
|
|
1147
1204
|
return None
|
|
1148
1205
|
|
|
1149
1206
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "checkmk-dev-tools"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.3.0" # will-be-updated-automatically
|
|
4
4
|
description = "Checkmk DevOps tools"
|
|
5
5
|
authors = [
|
|
6
6
|
"Frans Fürst <frans.fuerst@checkmk.com>",
|
|
@@ -14,7 +14,7 @@ exclude = ["cmk_dev/out"]
|
|
|
14
14
|
|
|
15
15
|
[tool.poetry.urls]
|
|
16
16
|
Repository = "https://github.com/Checkmk/checkmk-dev-tools"
|
|
17
|
-
Changelog = "https://github.com/Checkmk/checkmk-dev-tools/blob/release/2.
|
|
17
|
+
Changelog = "https://github.com/Checkmk/checkmk-dev-tools/blob/release/2.3.0/changelog.md"
|
|
18
18
|
|
|
19
19
|
[tool.poetry.scripts]
|
|
20
20
|
activity-from-fs = 'cmk_dev.activity_from_fs:main'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|