qontract-reconcile 0.10.2.dev296__py3-none-any.whl → 0.10.2.dev297__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.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/RECORD +9 -9
- reconcile/quay_base.py +19 -5
- reconcile/quay_mirror_org.py +14 -4
- reconcile/quay_repos.py +1 -0
- reconcile/utils/password_validator.py +1 -1
- reconcile/utils/quay_api.py +28 -16
- {qontract_reconcile-0.10.2.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev296.dist-info → qontract_reconcile-0.10.2.dev297.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.dev297
|
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.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/RECORD
RENAMED
@@ -82,12 +82,12 @@ reconcile/openshift_tekton_resources.py,sha256=z9OidaI7Ju2O0O0PfIcdoyH62VA4TxLTD
|
|
82
82
|
reconcile/openshift_upgrade_watcher.py,sha256=dGTQQdCOl95Bz0wOqg6JaMdBSSDgnAveH_hprUafhW0,6624
|
83
83
|
reconcile/openshift_users.py,sha256=h4dH3gTCFFQID76PFuYeMWNzFQ9DgTUtsOcvxfj-3cs,5385
|
84
84
|
reconcile/openshift_vault_secrets.py,sha256=Ax-_EBWWU1VRHYyKaUkGJkIjHGwWM3bZgjXL5CkPW8k,1883
|
85
|
-
reconcile/quay_base.py,sha256=
|
85
|
+
reconcile/quay_base.py,sha256=hfHv8ET6iw0GqPyncYJMRH7YFwJc5E1C9z7zET5MCjo,2327
|
86
86
|
reconcile/quay_membership.py,sha256=No2sgEyTVj-hr5VPLy_xdrYAPvt-xo-CPpOt0X3x_6o,6623
|
87
87
|
reconcile/quay_mirror.py,sha256=pA1_OujRduwQ6dYljoWXU_VJgAwlv7DzThk26ymKmGs,14327
|
88
|
-
reconcile/quay_mirror_org.py,sha256=
|
88
|
+
reconcile/quay_mirror_org.py,sha256=ltPbHuWUI8Wnl8gV4aeYmvoYFA1uXLWqlXqEPpw7Hi0,11065
|
89
89
|
reconcile/quay_permissions.py,sha256=BF539lRxjpgwm88WzazklzgaCF_ipRALwbO2AdpqUqE,4388
|
90
|
-
reconcile/quay_repos.py,sha256=
|
90
|
+
reconcile/quay_repos.py,sha256=fBleLzMtfDmTidpzbrTt8kGCy-Bk3J06EO4hhyghGnQ,7570
|
91
91
|
reconcile/queries.py,sha256=FLUZBtFC2S-e6yjtC1Oq968CJP6t3nc36NPj0wYa0bE,53472
|
92
92
|
reconcile/query_validator.py,sha256=csOSkKxcf6ZlpchJu4ck2jLYKUN6y1l-UmSQUFHgssY,1618
|
93
93
|
reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
|
@@ -637,11 +637,11 @@ reconcile/utils/openssl.py,sha256=QVvhzhpChq_4Daf_5wE1qeZJr4thg3DDjJPn4bOPD4E,36
|
|
637
637
|
reconcile/utils/output.py,sha256=wvsyf8NsFTaFHNkc8to75ta8f474Y4TMO4cHyAHEePk,2209
|
638
638
|
reconcile/utils/pagerduty_api.py,sha256=6Ae-KjcmA6Bf328UhTdQ2VwYjh4uFIW1NdZW6PUgT-c,7607
|
639
639
|
reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv9s8ffbTSY,1840
|
640
|
-
reconcile/utils/password_validator.py,sha256=
|
640
|
+
reconcile/utils/password_validator.py,sha256=knR6jJGc-v44v-hhQFvpYrEubuFfCCc3Qly6n_GJm5I,2191
|
641
641
|
reconcile/utils/prometheus.py,sha256=Ad0rwLbxRuuYjHwkwJloHEdK0bvy42h-p-HIT1DhDhs,3832
|
642
642
|
reconcile/utils/promotion_state.py,sha256=McSgGj3oog83ThJCrMR2v8q6Xb_Pxij-HEe_RbDu8cg,3946
|
643
643
|
reconcile/utils/promtool.py,sha256=YnqwMAzsQVGuBZ1j9zy3UcVPFQVJgBMLzQkxhK_KFkU,3079
|
644
|
-
reconcile/utils/quay_api.py,sha256=
|
644
|
+
reconcile/utils/quay_api.py,sha256=ZWjfjzFnIsbKRDcdAnP9tWQezclf53I7VWZJ0gbF2kE,8260
|
645
645
|
reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
|
646
646
|
reconcile/utils/raw_github_api.py,sha256=2WKtE8ABYYB9UGOAh9N_kLkksBWL3320Z2_scteZddI,2805
|
647
647
|
reconcile/utils/repo_owners.py,sha256=P0QX6F0oB8wYA08yiyzhYUiBtU57iIK_PsxbzKENbKM,6571
|
@@ -796,7 +796,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
796
796
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
|
797
797
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
798
798
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
799
|
-
qontract_reconcile-0.10.2.
|
800
|
-
qontract_reconcile-0.10.2.
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
799
|
+
qontract_reconcile-0.10.2.dev297.dist-info/METADATA,sha256=iGF5qMFr_OjJTe4VrXqoImqpXd6uvpYs0wXPJhdp1q0,24916
|
800
|
+
qontract_reconcile-0.10.2.dev297.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
801
|
+
qontract_reconcile-0.10.2.dev297.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
802
|
+
qontract_reconcile-0.10.2.dev297.dist-info/RECORD,,
|
reconcile/quay_base.py
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
from collections import namedtuple
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any, TypedDict
|
3
3
|
|
4
4
|
from reconcile import queries
|
5
5
|
from reconcile.utils.quay_api import QuayApi
|
6
6
|
from reconcile.utils.secret_reader import SecretReader
|
7
7
|
|
8
8
|
OrgKey = namedtuple("OrgKey", ["instance", "org_name"])
|
9
|
-
|
9
|
+
|
10
|
+
|
11
|
+
class OrgInfo(TypedDict):
|
12
|
+
url: str
|
13
|
+
api: QuayApi
|
14
|
+
push_token: dict[str, str] | None
|
15
|
+
teams: list[str]
|
16
|
+
managedRepos: bool
|
17
|
+
mirror: OrgKey | None
|
18
|
+
mirror_filters: dict[str, Any]
|
19
|
+
|
20
|
+
|
21
|
+
QuayApiStore = dict[OrgKey, OrgInfo]
|
10
22
|
|
11
23
|
|
12
24
|
def get_quay_api_store() -> QuayApiStore:
|
@@ -49,14 +61,16 @@ def get_quay_api_store() -> QuayApiStore:
|
|
49
61
|
else:
|
50
62
|
push_token = None
|
51
63
|
|
52
|
-
|
64
|
+
org_info: OrgInfo = {
|
53
65
|
"url": base_url,
|
54
66
|
"api": QuayApi(token, org_name, base_url=base_url),
|
55
67
|
"push_token": push_token,
|
56
|
-
"teams": org_data.get("managedTeams"),
|
57
|
-
"managedRepos": org_data.get("managedRepos"),
|
68
|
+
"teams": org_data.get("managedTeams") or [],
|
69
|
+
"managedRepos": bool(org_data.get("managedRepos")),
|
58
70
|
"mirror": mirror,
|
59
71
|
"mirror_filters": mirror_filters,
|
60
72
|
}
|
61
73
|
|
74
|
+
store[org_key] = org_info
|
75
|
+
|
62
76
|
return store
|
reconcile/quay_mirror_org.py
CHANGED
@@ -103,11 +103,16 @@ class QuayMirrorOrg:
|
|
103
103
|
|
104
104
|
quay_api = org_info["api"]
|
105
105
|
upstream_org_key = org_info["mirror"]
|
106
|
+
assert upstream_org_key is not None
|
106
107
|
upstream_org = self.quay_api_store[upstream_org_key]
|
107
108
|
upstream_quay_api = upstream_org["api"]
|
108
109
|
|
109
|
-
|
110
|
-
|
110
|
+
push_token = upstream_org["push_token"]
|
111
|
+
|
112
|
+
assert push_token is not None
|
113
|
+
|
114
|
+
username = push_token["user"]
|
115
|
+
token = push_token["token"]
|
111
116
|
|
112
117
|
org_repos = [item["name"] for item in quay_api.list_images()]
|
113
118
|
for repo in upstream_quay_api.list_images():
|
@@ -143,8 +148,11 @@ class QuayMirrorOrg:
|
|
143
148
|
org_name = org_key.org_name
|
144
149
|
|
145
150
|
server_url = org["url"]
|
146
|
-
|
147
|
-
|
151
|
+
push_token = org["push_token"]
|
152
|
+
assert push_token is not None
|
153
|
+
|
154
|
+
username = push_token["user"]
|
155
|
+
password = push_token["token"]
|
148
156
|
|
149
157
|
for item in data:
|
150
158
|
image = Image(
|
@@ -281,6 +289,8 @@ class QuayMirrorOrg:
|
|
281
289
|
"""
|
282
290
|
|
283
291
|
push_token = self.quay_api_store[org_key]["push_token"]
|
292
|
+
assert push_token is not None
|
293
|
+
|
284
294
|
username = push_token["user"]
|
285
295
|
password = push_token["token"]
|
286
296
|
return f"{username}:{password}"
|
reconcile/quay_repos.py
CHANGED
@@ -230,6 +230,7 @@ def run(dry_run: bool) -> None:
|
|
230
230
|
if org_info.get("mirror"):
|
231
231
|
# ensure there are no circular mirror dependencies
|
232
232
|
mirror_org_key = org_info["mirror"]
|
233
|
+
assert mirror_org_key is not None
|
233
234
|
mirror_org = quay_api_store[mirror_org_key]
|
234
235
|
if mirror_org.get("mirror"):
|
235
236
|
logging.error(
|
@@ -29,7 +29,7 @@ class PasswordValidator:
|
|
29
29
|
self._policy_flags = policy_flags
|
30
30
|
self._mininum_length = minimum_length
|
31
31
|
|
32
|
-
def validate(self, password: str):
|
32
|
+
def validate(self, password: str) -> None:
|
33
33
|
errors: list[str] = []
|
34
34
|
|
35
35
|
if len(password) < self._mininum_length:
|
reconcile/utils/quay_api.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
1
3
|
import requests
|
2
4
|
|
3
5
|
|
@@ -8,17 +10,23 @@ class QuayTeamNotFoundError(Exception):
|
|
8
10
|
class QuayApi:
|
9
11
|
LIMIT_FOLLOWS = 15
|
10
12
|
|
11
|
-
def __init__(
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
token: str,
|
16
|
+
organization: str,
|
17
|
+
base_url: str = "quay.io",
|
18
|
+
timeout: int = 60,
|
19
|
+
) -> None:
|
12
20
|
self.token = token
|
13
21
|
self.organization = organization
|
14
22
|
self.auth_header = {"Authorization": "Bearer %s" % (token,)}
|
15
|
-
self.team_members = {}
|
23
|
+
self.team_members: dict[str, Any] = {}
|
16
24
|
self.api_url = f"https://{base_url}/api/v1"
|
17
25
|
|
18
26
|
self._timeout = timeout
|
19
27
|
"""Timeout to use for HTTP calls to Quay (seconds)."""
|
20
28
|
|
21
|
-
def list_team_members(self, team, **kwargs):
|
29
|
+
def list_team_members(self, team: str, **kwargs: Any) -> list[dict]:
|
22
30
|
"""
|
23
31
|
List Quay team members.
|
24
32
|
|
@@ -52,12 +60,12 @@ class QuayApi:
|
|
52
60
|
|
53
61
|
return members_list
|
54
62
|
|
55
|
-
def user_exists(self, user):
|
63
|
+
def user_exists(self, user: str) -> bool:
|
56
64
|
url = f"{self.api_url}/users/{user}"
|
57
65
|
r = requests.get(url, headers=self.auth_header, timeout=self._timeout)
|
58
66
|
return r.ok
|
59
67
|
|
60
|
-
def remove_user_from_team(self, user, team):
|
68
|
+
def remove_user_from_team(self, user: str, team: str) -> bool:
|
61
69
|
"""Deletes an user from a team.
|
62
70
|
|
63
71
|
:raises HTTPError if there are any problems with the request
|
@@ -80,7 +88,7 @@ class QuayApi:
|
|
80
88
|
|
81
89
|
return True
|
82
90
|
|
83
|
-
def add_user_to_team(self, user, team):
|
91
|
+
def add_user_to_team(self, user: str, team: str) -> bool:
|
84
92
|
"""Adds an user to a team.
|
85
93
|
|
86
94
|
:raises HTTPError if there are any errors with the request
|
@@ -93,7 +101,9 @@ class QuayApi:
|
|
93
101
|
r.raise_for_status()
|
94
102
|
return True
|
95
103
|
|
96
|
-
def create_or_update_team(
|
104
|
+
def create_or_update_team(
|
105
|
+
self, team: str, role: str = "member", description: str | None = None
|
106
|
+
) -> None:
|
97
107
|
"""
|
98
108
|
Create or update an Organization team.
|
99
109
|
|
@@ -117,7 +127,9 @@ class QuayApi:
|
|
117
127
|
)
|
118
128
|
r.raise_for_status()
|
119
129
|
|
120
|
-
def list_images(
|
130
|
+
def list_images(
|
131
|
+
self, images: list | None = None, page: str | None = None, count: int = 0
|
132
|
+
) -> list[dict[str, Any]]:
|
121
133
|
"""
|
122
134
|
https://docs.quay.io/api/swagger/#!/repository/listRepos
|
123
135
|
|
@@ -156,7 +168,7 @@ class QuayApi:
|
|
156
168
|
return self.list_images(images, next_page, count + 1)
|
157
169
|
return images
|
158
170
|
|
159
|
-
def repo_create(self, repo_name, description, public):
|
171
|
+
def repo_create(self, repo_name: str, description: str, public: str) -> None:
|
160
172
|
"""Creates a repository called repo_name with the given description
|
161
173
|
and public flag.
|
162
174
|
|
@@ -180,14 +192,14 @@ class QuayApi:
|
|
180
192
|
)
|
181
193
|
r.raise_for_status()
|
182
194
|
|
183
|
-
def repo_delete(self, repo_name):
|
195
|
+
def repo_delete(self, repo_name: str) -> None:
|
184
196
|
url = f"{self.api_url}/repository/{self.organization}/{repo_name}"
|
185
197
|
|
186
198
|
# perform request
|
187
199
|
r = requests.delete(url, headers=self.auth_header, timeout=self._timeout)
|
188
200
|
r.raise_for_status()
|
189
201
|
|
190
|
-
def repo_update_description(self, repo_name, description):
|
202
|
+
def repo_update_description(self, repo_name: str, description: str) -> None:
|
191
203
|
url = f"{self.api_url}/repository/{self.organization}/{repo_name}"
|
192
204
|
|
193
205
|
params = {"description": description}
|
@@ -198,13 +210,13 @@ class QuayApi:
|
|
198
210
|
)
|
199
211
|
r.raise_for_status()
|
200
212
|
|
201
|
-
def repo_make_public(self, repo_name):
|
213
|
+
def repo_make_public(self, repo_name: str) -> None:
|
202
214
|
self._repo_change_visibility(repo_name, "public")
|
203
215
|
|
204
|
-
def repo_make_private(self, repo_name):
|
216
|
+
def repo_make_private(self, repo_name: str) -> None:
|
205
217
|
self._repo_change_visibility(repo_name, "private")
|
206
218
|
|
207
|
-
def _repo_change_visibility(self, repo_name, visibility):
|
219
|
+
def _repo_change_visibility(self, repo_name: str, visibility: str) -> None:
|
208
220
|
url = f"{self.api_url}/repository/{self.organization}/{repo_name}/changevisibility"
|
209
221
|
|
210
222
|
params = {"visibility": visibility}
|
@@ -215,7 +227,7 @@ class QuayApi:
|
|
215
227
|
)
|
216
228
|
r.raise_for_status()
|
217
229
|
|
218
|
-
def get_repo_team_permissions(self, repo_name, team):
|
230
|
+
def get_repo_team_permissions(self, repo_name: str, team: str) -> str | None:
|
219
231
|
url = (
|
220
232
|
f"{self.api_url}/repository/{self.organization}/"
|
221
233
|
+ f"{repo_name}/permissions/team/{team}"
|
@@ -231,7 +243,7 @@ class QuayApi:
|
|
231
243
|
|
232
244
|
return r.json().get("role") or None
|
233
245
|
|
234
|
-
def set_repo_team_permissions(self, repo_name, team, role):
|
246
|
+
def set_repo_team_permissions(self, repo_name: str, team: str, role: str) -> None:
|
235
247
|
url = (
|
236
248
|
f"{self.api_url}/repository/{self.organization}/"
|
237
249
|
+ f"{repo_name}/permissions/team/{team}"
|
{qontract_reconcile-0.10.2.dev296.dist-info → qontract_reconcile-0.10.2.dev297.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|