qontract-reconcile 0.10.1rc460__py3-none-any.whl → 0.10.1rc462__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.1rc460.dist-info → qontract_reconcile-0.10.1rc462.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc460.dist-info → qontract_reconcile-0.10.1rc462.dist-info}/RECORD +88 -88
- reconcile/aus/base.py +3 -3
- reconcile/aws_iam_keys.py +1 -1
- reconcile/aws_support_cases_sos.py +1 -1
- reconcile/change_owners/change_owners.py +2 -3
- reconcile/change_owners/diff.py +1 -1
- reconcile/change_owners/tester.py +3 -3
- reconcile/checkpoint.py +1 -1
- reconcile/cli.py +2 -1
- reconcile/closedbox_endpoint_monitoring_base.py +1 -1
- reconcile/cna/state.py +2 -2
- reconcile/dashdotdb_base.py +3 -3
- reconcile/dynatrace_token_provider.py +7 -8
- reconcile/gcr_mirror.py +2 -2
- reconcile/github_org.py +2 -2
- reconcile/github_owners.py +1 -1
- reconcile/gitlab_housekeeping.py +3 -3
- reconcile/gitlab_labeler.py +4 -5
- reconcile/glitchtip/reconciler.py +3 -3
- reconcile/glitchtip_project_alerts/integration.py +3 -3
- reconcile/gql_definitions/common/clusters.py +0 -2
- reconcile/gql_definitions/common/clusters_minimal.py +0 -2
- reconcile/ocm_clusters.py +9 -9
- reconcile/ocm_github_idp.py +1 -1
- reconcile/ocm_groups.py +1 -1
- reconcile/openshift_base.py +6 -6
- reconcile/openshift_clusterrolebindings.py +1 -1
- reconcile/openshift_groups.py +1 -1
- reconcile/openshift_namespace_labels.py +12 -12
- reconcile/openshift_resources_base.py +3 -3
- reconcile/openshift_rolebindings.py +1 -1
- reconcile/openshift_saas_deploy.py +1 -1
- reconcile/quay_mirror.py +2 -2
- reconcile/queries.py +0 -2
- reconcile/rhidp/common.py +2 -2
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +9 -9
- reconcile/slack_usergroups.py +9 -9
- reconcile/sql_query.py +3 -4
- reconcile/terraform_aws_route53.py +1 -1
- reconcile/terraform_cloudflare_users.py +7 -7
- reconcile/terraform_repo.py +3 -1
- reconcile/terraform_vpc_peerings.py +10 -10
- reconcile/test/fixtures.py +1 -1
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
- reconcile/test/test_jump_host.py +2 -2
- reconcile/test/test_quay_mirror.py +3 -1
- reconcile/test/test_quay_mirror_org.py +3 -1
- reconcile/test/test_terraform_repo.py +2 -2
- reconcile/typed_queries/saas_files.py +5 -5
- reconcile/utils/amtool.py +2 -2
- reconcile/utils/aws_api.py +5 -29
- reconcile/utils/config.py +1 -2
- reconcile/utils/environ.py +1 -1
- reconcile/utils/git.py +7 -3
- reconcile/utils/git_secrets.py +2 -2
- reconcile/utils/helm.py +1 -1
- reconcile/utils/jjb_client.py +7 -7
- reconcile/utils/jump_host.py +2 -2
- reconcile/utils/metrics.py +3 -3
- reconcile/utils/models.py +47 -51
- reconcile/utils/mr/aws_access.py +1 -1
- reconcile/utils/mr/base.py +1 -1
- reconcile/utils/mr/user_maintenance.py +1 -1
- reconcile/utils/oc.py +8 -8
- reconcile/utils/oc_connection_parameters.py +12 -13
- reconcile/utils/ocm/base.py +1 -1
- reconcile/utils/ocm/ocm.py +9 -9
- reconcile/utils/openshift_resource.py +8 -9
- reconcile/utils/parse_dhms_duration.py +1 -1
- reconcile/utils/runtime/sharding.py +1 -1
- reconcile/utils/saasherder/saasherder.py +5 -5
- reconcile/utils/slack_api.py +2 -2
- reconcile/utils/terraform/config_client.py +1 -1
- reconcile/utils/terraform_client.py +5 -5
- reconcile/utils/terrascript/cloudflare_client.py +3 -1
- reconcile/utils/terrascript_aws_client.py +40 -40
- reconcile/utils/three_way_diff_strategy.py +2 -2
- reconcile/utils/unleash.py +1 -1
- reconcile/utils/vault.py +1 -1
- reconcile/vpc_peerings_validator.py +6 -6
- release/version.py +7 -2
- tools/app_interface_reporter.py +3 -3
- tools/cli_commands/gpg_encrypt.py +2 -2
- tools/qontract_cli.py +7 -6
- {qontract_reconcile-0.10.1rc460.dist-info → qontract_reconcile-0.10.1rc462.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc460.dist-info → qontract_reconcile-0.10.1rc462.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc460.dist-info → qontract_reconcile-0.10.1rc462.dist-info}/top_level.txt +0 -0
reconcile/test/fixtures.py
CHANGED
@@ -30,10 +30,10 @@ def file_contents() -> Callable[[str], tuple[str, str]]:
|
|
30
30
|
"files",
|
31
31
|
)
|
32
32
|
|
33
|
-
with open(f"{path}/{case}.yml", "r") as f:
|
33
|
+
with open(f"{path}/{case}.yml", "r", encoding="locale") as f:
|
34
34
|
a = f.read().strip()
|
35
35
|
|
36
|
-
with open(f"{path}/{case}.result.yml", "r") as f:
|
36
|
+
with open(f"{path}/{case}.result.yml", "r", encoding="locale") as f:
|
37
37
|
b = f.read().strip()
|
38
38
|
|
39
39
|
return (a, b)
|
reconcile/test/test_jump_host.py
CHANGED
@@ -55,7 +55,7 @@ def test_base_jumphost(fs: Any, parameters: JumphostParameters, expected_port: i
|
|
55
55
|
jumphost = JumpHostBase(parameters=parameters)
|
56
56
|
assert os.path.exists(jumphost._identity_file)
|
57
57
|
|
58
|
-
with open(jumphost._identity_file, "r") as f:
|
58
|
+
with open(jumphost._identity_file, "r", encoding="locale") as f:
|
59
59
|
assert f.read() == parameters.key
|
60
60
|
|
61
61
|
assert jumphost._port == expected_port
|
@@ -113,5 +113,5 @@ def test_ssh_jumphost(
|
|
113
113
|
if local_port:
|
114
114
|
assert jumphost._local_port == local_port
|
115
115
|
|
116
|
-
with open(known_hosts_file, "r") as f:
|
116
|
+
with open(known_hosts_file, "r", encoding="locale") as f:
|
117
117
|
assert f.read() == EXPECTED_KNOWN_HOSTS_CONTENT
|
@@ -51,7 +51,9 @@ class TestIsCompareTags:
|
|
51
51
|
self.tmp_dir = (
|
52
52
|
tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
|
53
53
|
)
|
54
|
-
with open(
|
54
|
+
with open(
|
55
|
+
os.path.join(self.tmp_dir.name, CONTROL_FILE_NAME), "w", encoding="locale"
|
56
|
+
) as fh:
|
55
57
|
fh.write(str(NOW - 100.0))
|
56
58
|
|
57
59
|
def teardown_method(self):
|
@@ -33,7 +33,9 @@ class TestIsCompareTags:
|
|
33
33
|
self.tmp_dir = (
|
34
34
|
tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
|
35
35
|
)
|
36
|
-
with open(
|
36
|
+
with open(
|
37
|
+
os.path.join(self.tmp_dir.name, CONTROL_FILE_NAME), "w", encoding="locale"
|
38
|
+
) as fh:
|
37
39
|
fh.write(str(NOW - 100.0))
|
38
40
|
|
39
41
|
def teardown_method(self):
|
@@ -339,7 +339,7 @@ def test_output_correct_statefile(
|
|
339
339
|
assert diff
|
340
340
|
integration.print_output(diff, True)
|
341
341
|
|
342
|
-
with open(f"{tmp_path}/tf-repo.yaml", "r") as output:
|
342
|
+
with open(f"{tmp_path}/tf-repo.yaml", "r", encoding="locale") as output:
|
343
343
|
yaml_rep = yaml.safe_load(output)
|
344
344
|
|
345
345
|
assert expected_output == yaml_rep
|
@@ -366,7 +366,7 @@ def test_output_correct_no_statefile(
|
|
366
366
|
assert diff
|
367
367
|
integration.print_output(diff, True)
|
368
368
|
|
369
|
-
with open(f"{tmp_path}/tf-repo.yaml", "r") as output:
|
369
|
+
with open(f"{tmp_path}/tf-repo.yaml", "r", encoding="locale") as output:
|
370
370
|
yaml_rep = yaml.safe_load(output)
|
371
371
|
|
372
372
|
assert expected_output == yaml_rep
|
@@ -95,9 +95,9 @@ class SaasResourceTemplate(ConfiguredBaseModel):
|
|
95
95
|
provider: Optional[str] = Field(..., alias="provider")
|
96
96
|
hash_length: Optional[int] = Field(..., alias="hash_length")
|
97
97
|
parameters: Optional[Json] = Field(..., alias="parameters")
|
98
|
-
secret_parameters: Optional[
|
99
|
-
|
100
|
-
|
98
|
+
secret_parameters: Optional[list[SaasResourceTemplateV2_SaasSecretParametersV1]] = (
|
99
|
+
Field(..., alias="secretParameters")
|
100
|
+
)
|
101
101
|
targets: list[SaasResourceTemplateTarget] = Field(..., alias="targets")
|
102
102
|
|
103
103
|
|
@@ -279,7 +279,7 @@ class SaasFileList:
|
|
279
279
|
if name is None and env_name is None and app_name is None:
|
280
280
|
return self.saas_files
|
281
281
|
|
282
|
-
if name == "" or env_name == "" or app_name == "":
|
282
|
+
if name == "" or env_name == "" or app_name == "": # noqa: PLC1901
|
283
283
|
return []
|
284
284
|
|
285
285
|
filtered: list[SaasFile] = []
|
@@ -308,7 +308,7 @@ class SaasFileList:
|
|
308
308
|
def convert_parameters_to_json_string(root: dict[str, Any]) -> dict[str, Any]:
|
309
309
|
"""Find all parameter occurrences and convert them to a json string."""
|
310
310
|
for key, value in root.items():
|
311
|
-
if key in
|
311
|
+
if key in {"parameters", "labels"}:
|
312
312
|
root[key] = json.dumps(value) if value is not None else None
|
313
313
|
elif isinstance(value, dict):
|
314
314
|
root[key] = convert_parameters_to_json_string(value)
|
reconcile/utils/amtool.py
CHANGED
@@ -25,7 +25,7 @@ class AmtoolResult:
|
|
25
25
|
def check_config(yaml_config: str) -> AmtoolResult:
|
26
26
|
"""Run amtool check rules on the given yaml string"""
|
27
27
|
|
28
|
-
with tempfile.NamedTemporaryFile(mode="w+") as fp:
|
28
|
+
with tempfile.NamedTemporaryFile(mode="w+", encoding="locale") as fp:
|
29
29
|
fp.write(yaml_config)
|
30
30
|
fp.flush()
|
31
31
|
cmd = ["amtool", "check-config", fp.name]
|
@@ -36,7 +36,7 @@ def check_config(yaml_config: str) -> AmtoolResult:
|
|
36
36
|
|
37
37
|
def config_routes_test(yaml_config: str, labels: Mapping[str, str]) -> AmtoolResult:
|
38
38
|
labels_lst = [f"{key}={value}" for key, value in labels.items()]
|
39
|
-
with tempfile.NamedTemporaryFile(mode="w+") as fp:
|
39
|
+
with tempfile.NamedTemporaryFile(mode="w+", encoding="locale") as fp:
|
40
40
|
fp.write(yaml_config)
|
41
41
|
fp.flush()
|
42
42
|
cmd = ["amtool", "config", "routes", "test", "--config.file", fp.name]
|
reconcile/utils/aws_api.py
CHANGED
@@ -58,37 +58,13 @@ if TYPE_CHECKING:
|
|
58
58
|
ResourceRecordTypeDef,
|
59
59
|
)
|
60
60
|
else:
|
61
|
-
EC2Client = (
|
62
|
-
EC2ServiceResource
|
63
|
-
) = (
|
64
|
-
RouteTableTypeDef
|
65
|
-
) = (
|
66
|
-
SubnetTypeDef
|
67
|
-
) = (
|
61
|
+
EC2Client = EC2ServiceResource = RouteTableTypeDef = SubnetTypeDef = (
|
68
62
|
TransitGatewayTypeDef
|
69
|
-
) = (
|
70
|
-
TransitGatewayVpcAttachmentTypeDef
|
71
|
-
) = (
|
72
|
-
VpcTypeDef
|
73
|
-
) = (
|
74
|
-
IAMClient
|
75
|
-
) = (
|
63
|
+
) = TransitGatewayVpcAttachmentTypeDef = VpcTypeDef = IAMClient = (
|
76
64
|
AccessKeyMetadataTypeDef
|
77
|
-
) = (
|
78
|
-
ImageTypeDef
|
79
|
-
) = (
|
80
|
-
TagTypeDef
|
81
|
-
) = (
|
82
|
-
LaunchPermissionModificationsTypeDef
|
83
|
-
) = (
|
65
|
+
) = ImageTypeDef = TagTypeDef = LaunchPermissionModificationsTypeDef = (
|
84
66
|
FilterTypeDef
|
85
|
-
) = (
|
86
|
-
Route53Client
|
87
|
-
) = (
|
88
|
-
ResourceRecordSetTypeDef
|
89
|
-
) = (
|
90
|
-
ResourceRecordTypeDef
|
91
|
-
) = (
|
67
|
+
) = Route53Client = ResourceRecordSetTypeDef = ResourceRecordTypeDef = (
|
92
68
|
HostedZoneTypeDef
|
93
69
|
) = RDSClient = DBInstanceMessageTypeDef = UpgradeTargetTypeDef = object
|
94
70
|
|
@@ -866,7 +842,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
866
842
|
self, account_name: str, assume_role: str, assume_region: str, client_type="ec2"
|
867
843
|
) -> EC2Client:
|
868
844
|
session = self.get_session(account_name)
|
869
|
-
if assume_role
|
845
|
+
if not assume_role:
|
870
846
|
return self.get_session_client(
|
871
847
|
session, client_type, region_name=assume_region
|
872
848
|
)
|
reconcile/utils/config.py
CHANGED
reconcile/utils/environ.py
CHANGED
@@ -11,7 +11,7 @@ def environ(variables=None):
|
|
11
11
|
@wraps(f)
|
12
12
|
def f_environ(*args, **kwargs):
|
13
13
|
for e in variables:
|
14
|
-
if
|
14
|
+
if not os.environ.get(e):
|
15
15
|
raise KeyError("Could not find environment variable: {}".format(e))
|
16
16
|
f(*args, **kwargs)
|
17
17
|
|
reconcile/utils/git.py
CHANGED
@@ -9,7 +9,9 @@ class GitError(Exception):
|
|
9
9
|
def clone(repo_url, wd):
|
10
10
|
# pylint: disable=subprocess-run-check
|
11
11
|
cmd = ["git", "clone", repo_url, wd]
|
12
|
-
result = subprocess.run(
|
12
|
+
result = subprocess.run(
|
13
|
+
cmd, cwd=wd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
14
|
+
)
|
13
15
|
if result.returncode != 0:
|
14
16
|
raise GitError(f"git clone failed: {repo_url}")
|
15
17
|
|
@@ -17,7 +19,9 @@ def clone(repo_url, wd):
|
|
17
19
|
def checkout(commit, wd):
|
18
20
|
# pylint: disable=subprocess-run-check
|
19
21
|
cmd = ["git", "checkout", commit]
|
20
|
-
result = subprocess.run(
|
22
|
+
result = subprocess.run(
|
23
|
+
cmd, cwd=wd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
24
|
+
)
|
21
25
|
if result.returncode != 0:
|
22
26
|
raise GitError(f"git checkout failed: {commit}")
|
23
27
|
|
@@ -28,7 +32,7 @@ def is_file_in_git_repo(file_path):
|
|
28
32
|
# pylint: disable=subprocess-run-check
|
29
33
|
cmd = ["git", "rev-parse", "--is-inside-work-tree"]
|
30
34
|
result = subprocess.run(
|
31
|
-
cmd, cwd=dir_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
35
|
+
cmd, cwd=dir_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
32
36
|
)
|
33
37
|
return result.returncode == 0
|
34
38
|
|
reconcile/utils/git_secrets.py
CHANGED
@@ -38,7 +38,7 @@ def scan_history(repo_url, existing_keys):
|
|
38
38
|
def get_suspected_files(error):
|
39
39
|
suspects = []
|
40
40
|
for e in error.split("\n"):
|
41
|
-
if e
|
41
|
+
if not e:
|
42
42
|
break
|
43
43
|
if e.startswith("warning"):
|
44
44
|
continue
|
@@ -55,7 +55,7 @@ def get_leaked_keys(repo_wd, suspected_files, existing_keys):
|
|
55
55
|
commit, file_relative_path = s[0], s[1]
|
56
56
|
git.checkout(commit, repo_wd)
|
57
57
|
file_path = os.path.join(repo_wd, file_relative_path)
|
58
|
-
with open(file_path, "r") as f:
|
58
|
+
with open(file_path, "r", encoding="locale") as f:
|
59
59
|
content = f.read()
|
60
60
|
leaked_keys = [key for key in existing_keys if key in content]
|
61
61
|
all_leaked_keys.extend(leaked_keys)
|
reconcile/utils/helm.py
CHANGED
@@ -25,7 +25,7 @@ class JSONEncoder(json.JSONEncoder):
|
|
25
25
|
|
26
26
|
def template(values: Mapping[str, Any]) -> Mapping[str, Any]:
|
27
27
|
try:
|
28
|
-
with tempfile.NamedTemporaryFile(mode="w+") as values_file:
|
28
|
+
with tempfile.NamedTemporaryFile(mode="w+", encoding="locale") as values_file:
|
29
29
|
values_file.write(json.dumps(values, cls=JSONEncoder))
|
30
30
|
values_file.flush()
|
31
31
|
cmd = [
|
reconcile/utils/jjb_client.py
CHANGED
@@ -64,7 +64,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
64
64
|
ini = ini.replace('"', "")
|
65
65
|
ini = ini.replace("false", "False")
|
66
66
|
ini_file_path = "{}/{}.ini".format(wd, name)
|
67
|
-
with open(ini_file_path, "w") as f:
|
67
|
+
with open(ini_file_path, "w", encoding="locale") as f:
|
68
68
|
f.write(ini)
|
69
69
|
f.write("\n")
|
70
70
|
working_dirs[name] = wd
|
@@ -81,12 +81,12 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
81
81
|
if c["type"] == "jobs":
|
82
82
|
for item in content:
|
83
83
|
item["project"]["app_name"] = c["app"]["name"]
|
84
|
-
with open(config_file_path, "a") as f:
|
84
|
+
with open(config_file_path, "a", encoding="locale") as f:
|
85
85
|
yaml.dump(content, f)
|
86
86
|
f.write("\n")
|
87
87
|
else:
|
88
88
|
config = c["config_path"]["content"]
|
89
|
-
with open(config_file_path, "a") as f:
|
89
|
+
with open(config_file_path, "a", encoding="locale") as f:
|
90
90
|
f.write(config)
|
91
91
|
f.write("\n")
|
92
92
|
|
@@ -100,7 +100,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
100
100
|
the supplied configs"""
|
101
101
|
for name, wd in self.working_dirs.items():
|
102
102
|
config_path = "{}/config.yaml".format(wd)
|
103
|
-
with open(config_path, "w") as f:
|
103
|
+
with open(config_path, "w", encoding="locale") as f:
|
104
104
|
f.write(configs[name])
|
105
105
|
|
106
106
|
def sort(self, configs):
|
@@ -136,7 +136,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
136
136
|
configs = {}
|
137
137
|
for name, wd in self.working_dirs.items():
|
138
138
|
config_path = "{}/config.yaml".format(wd)
|
139
|
-
with open(config_path, "r") as f:
|
139
|
+
with open(config_path, "r", encoding="locale") as f:
|
140
140
|
configs[name] = f.read()
|
141
141
|
|
142
142
|
return configs
|
@@ -196,7 +196,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
196
196
|
logging.info([action, item_type, instance, item])
|
197
197
|
|
198
198
|
if action == "update":
|
199
|
-
with open(ft) as c, open(f) as d:
|
199
|
+
with open(ft, encoding="locale") as c, open(f, encoding="locale") as d:
|
200
200
|
clines = c.readlines()
|
201
201
|
dlines = d.readlines()
|
202
202
|
|
@@ -247,7 +247,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
247
247
|
|
248
248
|
@staticmethod
|
249
249
|
def get_jjb(args):
|
250
|
-
from jenkins_jobs.cli.entry import JenkinsJobs
|
250
|
+
from jenkins_jobs.cli.entry import JenkinsJobs # noqa: PLC0415
|
251
251
|
|
252
252
|
return JenkinsJobs(args)
|
253
253
|
|
reconcile/utils/jump_host.py
CHANGED
@@ -45,7 +45,7 @@ class JumpHostBase:
|
|
45
45
|
self._identity_dir = tempfile.mkdtemp()
|
46
46
|
|
47
47
|
identity_file = self._identity_dir + "/id"
|
48
|
-
with open(identity_file, "w") as f:
|
48
|
+
with open(identity_file, "w", encoding="locale") as f:
|
49
49
|
f.write(self._identity)
|
50
50
|
os.chmod(identity_file, 0o600)
|
51
51
|
self._identity_file = identity_file
|
@@ -96,7 +96,7 @@ class JumpHostSSH(JumpHostBase):
|
|
96
96
|
|
97
97
|
def _init_known_hosts_file(self) -> None:
|
98
98
|
known_hosts_file = self._identity_dir + "/known_hosts"
|
99
|
-
with open(known_hosts_file, "w") as f:
|
99
|
+
with open(known_hosts_file, "w", encoding="locale") as f:
|
100
100
|
f.write(self._known_hosts)
|
101
101
|
os.chmod(known_hosts_file, 0o600)
|
102
102
|
self.known_hosts_file = known_hosts_file
|
reconcile/utils/metrics.py
CHANGED
@@ -187,9 +187,9 @@ class MetricsContainer:
|
|
187
187
|
self._gauges: dict[Type[GaugeMetric], dict[Sequence[str], float]] = defaultdict(
|
188
188
|
dict
|
189
189
|
)
|
190
|
-
self._counters: dict[
|
191
|
-
|
192
|
-
|
190
|
+
self._counters: dict[Type[CounterMetric], dict[Sequence[str], float]] = (
|
191
|
+
defaultdict(dict)
|
192
|
+
)
|
193
193
|
|
194
194
|
self._scopes: dict[Hashable, MetricsContainer] = {}
|
195
195
|
|
reconcile/utils/models.py
CHANGED
@@ -29,56 +29,52 @@ def data_default_none(
|
|
29
29
|
# Settings defaults
|
30
30
|
if field.allow_none:
|
31
31
|
data[field.alias] = None
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
sub_data.update(d)
|
79
|
-
break
|
80
|
-
except ValidationError:
|
81
|
-
continue
|
32
|
+
elif isinstance(field.type_, type) and issubclass(field.type_, str):
|
33
|
+
data[field.alias] = DEFAULT_STRING
|
34
|
+
elif isinstance(field.type_, type) and issubclass(field.type_, bool):
|
35
|
+
data[field.alias] = False
|
36
|
+
elif isinstance(field.type_, type) and issubclass(field.type_, int):
|
37
|
+
data[field.alias] = DEFAULT_INT
|
38
|
+
elif isinstance(field.type_, type) and issubclass(field.type_, BaseModel):
|
39
|
+
if isinstance(data[field.alias], dict):
|
40
|
+
data[field.alias] = data_default_none(field.type_, data[field.alias])
|
41
|
+
if isinstance(data[field.alias], list):
|
42
|
+
data[field.alias] = [
|
43
|
+
data_default_none(field.type_, item)
|
44
|
+
for item in data[field.alias]
|
45
|
+
if isinstance(item, dict)
|
46
|
+
]
|
47
|
+
elif field.sub_fields:
|
48
|
+
if all(
|
49
|
+
isinstance(sub_field.type_, type)
|
50
|
+
and issubclass(sub_field.type_, BaseModel)
|
51
|
+
for sub_field in field.sub_fields
|
52
|
+
):
|
53
|
+
# Union[ClassA, ClassB] field
|
54
|
+
for sub_field in field.sub_fields:
|
55
|
+
if isinstance(data[field.alias], dict):
|
56
|
+
try:
|
57
|
+
d = dict(data[field.alias])
|
58
|
+
d.update(data_default_none(sub_field.type_, d))
|
59
|
+
# Lets confirm we found a matching union class
|
60
|
+
sub_field.type_(**d)
|
61
|
+
data[field.alias] = d
|
62
|
+
break
|
63
|
+
except ValidationError:
|
64
|
+
continue
|
65
|
+
elif isinstance(data[field.alias], list) and len(field.sub_fields) == 1:
|
66
|
+
# list[Union[ClassA, ClassB]] field
|
67
|
+
for sub_data in data[field.alias]:
|
68
|
+
for sub_field in field.sub_fields[0].sub_fields or []:
|
69
|
+
try:
|
70
|
+
d = dict(sub_data)
|
71
|
+
d.update(data_default_none(sub_field.type_, d))
|
72
|
+
# Lets confirm we found a matching union class
|
73
|
+
sub_field.type_(**d)
|
74
|
+
sub_data.update(d)
|
75
|
+
break
|
76
|
+
except ValidationError:
|
77
|
+
continue
|
82
78
|
|
83
79
|
return data
|
84
80
|
|
@@ -90,7 +86,7 @@ class CSV(list[str]):
|
|
90
86
|
"""
|
91
87
|
|
92
88
|
@classmethod
|
93
|
-
def __get_validators__(cls) -> Generator[Callable, None, None]:
|
89
|
+
def __get_validators__(cls) -> Generator[Callable, None, None]: # noqa: PLW3201
|
94
90
|
yield cls.validate
|
95
91
|
yield cls.length_validator
|
96
92
|
|
reconcile/utils/mr/aws_access.py
CHANGED
@@ -57,7 +57,7 @@ class CreateDeleteAwsAccessKey(MergeRequestBase):
|
|
57
57
|
)
|
58
58
|
|
59
59
|
# add a new email to be picked up by email-sender
|
60
|
-
with open(BODY_TEMPLATE) as file_obj:
|
60
|
+
with open(BODY_TEMPLATE, encoding="locale") as file_obj:
|
61
61
|
body_template = Template(
|
62
62
|
file_obj.read(), keep_trailing_newline=True, trim_blocks=True
|
63
63
|
)
|
reconcile/utils/mr/base.py
CHANGED
@@ -232,7 +232,7 @@ def app_interface_email(
|
|
232
232
|
apps: Optional[list[str]] = None,
|
233
233
|
) -> str:
|
234
234
|
"""Render app-interface-email template."""
|
235
|
-
with open(EMAIL_TEMPLATE) as file_obj:
|
235
|
+
with open(EMAIL_TEMPLATE, encoding="locale") as file_obj:
|
236
236
|
email_template = Template(
|
237
237
|
file_obj.read(), keep_trailing_newline=True, trim_blocks=True
|
238
238
|
)
|
@@ -36,7 +36,7 @@ class CreateDeleteUserAppInterface(MergeRequestBase):
|
|
36
36
|
for path_spec in self.paths:
|
37
37
|
path_type = path_spec["type"]
|
38
38
|
path = path_spec["path"]
|
39
|
-
if path_type in
|
39
|
+
if path_type in {PathTypes.USER, PathTypes.REQUEST, PathTypes.QUERY}:
|
40
40
|
gitlab_cli.delete_file(
|
41
41
|
branch_name=self.branch, file_path=path, commit_message=self.title
|
42
42
|
)
|
reconcile/utils/oc.py
CHANGED
@@ -382,7 +382,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
382
382
|
|
383
383
|
self.is_log_slow_oc_reconcile = os.environ.get(
|
384
384
|
"LOG_SLOW_OC_RECONCILE", ""
|
385
|
-
).lower() in
|
385
|
+
).lower() in {"true", "yes"}
|
386
386
|
|
387
387
|
def _init(
|
388
388
|
self,
|
@@ -454,7 +454,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
454
454
|
|
455
455
|
self.is_log_slow_oc_reconcile = os.environ.get(
|
456
456
|
"LOG_SLOW_OC_RECONCILE", ""
|
457
|
-
).lower() in
|
457
|
+
).lower() in {"true", "yes"}
|
458
458
|
|
459
459
|
def whoami(self):
|
460
460
|
return self._run(["whoami"])
|
@@ -719,7 +719,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
719
719
|
ready_pods = [
|
720
720
|
pod
|
721
721
|
for pod in pods
|
722
|
-
if pod["status"].get("phase") in
|
722
|
+
if pod["status"].get("phase") in {"Running", "Succeeded"}
|
723
723
|
]
|
724
724
|
|
725
725
|
if not ready_pods:
|
@@ -731,7 +731,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
731
731
|
if follow:
|
732
732
|
cmd.append("-f")
|
733
733
|
# pylint: disable=consider-using-with
|
734
|
-
output_file = open(os.path.join(output, name), "w")
|
734
|
+
output_file = open(os.path.join(output, name), "w", encoding="locale")
|
735
735
|
# collect logs to file async
|
736
736
|
Popen(self.oc_base_cmd + cmd, stdout=output_file)
|
737
737
|
|
@@ -983,7 +983,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
983
983
|
kind: str,
|
984
984
|
include_optional: bool = True,
|
985
985
|
) -> dict[str, set[str]]:
|
986
|
-
if kind not in
|
986
|
+
if kind not in {"Secret", "ConfigMap"}:
|
987
987
|
raise KeyError(f"unsupported resource kind: {kind}")
|
988
988
|
optional = "optional"
|
989
989
|
if kind == "Secret":
|
@@ -1117,7 +1117,7 @@ class OCCli: # pylint: disable=too-many-public-methods
|
|
1117
1117
|
find = False
|
1118
1118
|
for gv in self.api_resources[kind]:
|
1119
1119
|
if apigroup_override == gv.group:
|
1120
|
-
if gv.group
|
1120
|
+
if not gv.group:
|
1121
1121
|
group_version = gv.api_version
|
1122
1122
|
else:
|
1123
1123
|
group_version = f"{gv.group}/{gv.api_version}"
|
@@ -1389,7 +1389,7 @@ class OC:
|
|
1389
1389
|
use_native_env = os.environ.get("USE_NATIVE_CLIENT", "")
|
1390
1390
|
use_native = True
|
1391
1391
|
if len(use_native_env) > 0:
|
1392
|
-
use_native = use_native_env.lower() in
|
1392
|
+
use_native = use_native_env.lower() in {"true", "yes"}
|
1393
1393
|
else:
|
1394
1394
|
enable_toggle = "openshift-resources-native-client"
|
1395
1395
|
use_native = get_feature_toggle_state(
|
@@ -1756,7 +1756,7 @@ def validate_labels(labels: dict[str, str]) -> Iterable[str]:
|
|
1756
1756
|
f"Label key prefix is invalid, it needs to match "
|
1757
1757
|
f"'{k_prefix_pattern}'': {prefix}"
|
1758
1758
|
)
|
1759
|
-
if prefix in
|
1759
|
+
if prefix in {"kubernetes.io", "k8s.io"}:
|
1760
1760
|
err.append(f"Label key prefix is reserved: {prefix}")
|
1761
1761
|
|
1762
1762
|
return err
|
@@ -153,20 +153,19 @@ class OCConnectionParameters:
|
|
153
153
|
logging.debug(
|
154
154
|
f"No admin automation token set for cluster '{cluster.name}', but privileged access requested."
|
155
155
|
)
|
156
|
+
elif cluster.automation_token:
|
157
|
+
try:
|
158
|
+
automation_token = OCConnectionParameters._get_automation_token(
|
159
|
+
secret_reader, cluster.automation_token, cluster
|
160
|
+
)
|
161
|
+
except SecretNotFound:
|
162
|
+
logging.error(
|
163
|
+
f"[{cluster.name}] automation token {cluster.automation_token} not found"
|
164
|
+
)
|
156
165
|
else:
|
157
|
-
if
|
158
|
-
|
159
|
-
|
160
|
-
secret_reader, cluster.automation_token, cluster
|
161
|
-
)
|
162
|
-
except SecretNotFound:
|
163
|
-
logging.error(
|
164
|
-
f"[{cluster.name}] automation token {cluster.automation_token} not found"
|
165
|
-
)
|
166
|
-
else:
|
167
|
-
# Note, that currently OCMap uses OCLogMsg if a token is missing, i.e.,
|
168
|
-
# for now this is valid behavior.
|
169
|
-
logging.debug(f"No automation token for cluster '{cluster.name}'.")
|
166
|
+
# Note, that currently OCMap uses OCLogMsg if a token is missing, i.e.,
|
167
|
+
# for now this is valid behavior.
|
168
|
+
logging.debug(f"No automation token for cluster '{cluster.name}'.")
|
170
169
|
|
171
170
|
disabled_integrations = []
|
172
171
|
if cluster.disable:
|
reconcile/utils/ocm/base.py
CHANGED