Skip to content

Commit 6128780

Browse files
authored
Merge pull request #116 from pvarki/products_apis_calls
Catch exceptions when calling remote APIs in the background
2 parents f810fd0 + 25f8f06 commit 6128780

File tree

6 files changed

+58
-12
lines changed

6 files changed

+58
-12
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.6.1
2+
current_version = 1.6.2
33
commit = False
44
tag = False
55

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "rasenmaeher_api"
3-
version = "1.6.1"
3+
version = "1.6.2"
44
description = "python-rasenmaeher-api"
55
authors = [
66
"Aciid <703382+Aciid@users.noreply.github.com>",

src/rasenmaeher_api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
""" python-rasenmaeher-api """
2-
__version__ = "1.6.1" # NOTE Use `bump2version --config-file patch` to bump versions correctly
2+
__version__ = "1.6.2" # NOTE Use `bump2version --config-file patch` to bump versions correctly

src/rasenmaeher_api/kchelpers.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from libpvarki.schemas.product import UserCRUDRequest
88
from pydantic import BaseModel, Extra, Field
99
from keycloak.keycloak_admin import KeycloakAdmin
10+
from keycloak.exceptions import KeycloakError
1011

1112

1213
from .rmsettings import RMSettings
@@ -97,6 +98,26 @@ async def check_user_roles(self, user: KCUserData) -> bool:
9798
return True
9899
return False
99100

101+
async def resolve_kc_id(self, email: str) -> Optional[str]:
102+
"""Find user with given email"""
103+
found = await self.kcadmin.a_get_users({"email": email})
104+
if not found:
105+
return None
106+
LOGGER.debug("found: {}".format(found))
107+
if len(found) > 1:
108+
LOGGER.warning("Found more than one result, using the first one")
109+
item = found[0]
110+
if "id" not in item:
111+
LOGGER.error("Found user does not have id")
112+
return None
113+
return str(item["id"])
114+
115+
def user_kc_email(self, user: KCUserData) -> str:
116+
"""Return the unique email for user in KC"""
117+
conf = RMSettings.singleton()
118+
manifest = conf.kraftwerk_manifest_dict
119+
return f"{user.productdata.uuid}@{manifest['dns']}"
120+
100121
async def create_kc_user(self, user: KCUserData) -> Optional[KCUserData]:
101122
"""Create a new user in KC"""
102123
conf = RMSettings.singleton()
@@ -106,9 +127,11 @@ async def create_kc_user(self, user: KCUserData) -> Optional[KCUserData]:
106127
if user.kc_id:
107128
raise ValueError("Cannot specify KC id when creating")
108129
pdata = user.productdata
130+
user_email = self.user_kc_email(user)
131+
109132
send_payload = {
110133
"username": pdata.callsign, # NOTE: KeyCloak now forces this all lowercase
111-
"email": f"{pdata.uuid}@{manifest['dns']}",
134+
"email": user_email,
112135
"firstName": pdata.callsign,
113136
"lastName": manifest["deployment"],
114137
"enabled": True,
@@ -156,28 +179,47 @@ async def update_kc_user(self, user: KCUserData) -> Optional[KCUserData]:
156179
conf = RMSettings.singleton()
157180
if not conf.kc_enabled:
158181
return None
159-
if not user.kc_id:
160-
LOGGER.error("No KC id defined")
161-
return None
162-
await self.check_user_roles(user)
163182
manifest = conf.kraftwerk_manifest_dict
164183
pdata = user.productdata
184+
user_email = self.user_kc_email(user)
185+
186+
if not user.kc_id:
187+
LOGGER.warning("No KC id defined, trying to resolve")
188+
resolved = await self.resolve_kc_id(user_email)
189+
if not resolved:
190+
LOGGER.error("Could not resolve KC id, trying to create the user")
191+
return await self.create_kc_user(user)
192+
user.kc_id = resolved
193+
await self.check_user_roles(user)
165194
send_payload = user.kc_data
166195
send_payload.update(
167196
{
168-
"email": f"{pdata.uuid}@{manifest['dns']}",
197+
"email": user_email,
169198
"firstName": pdata.callsign,
170199
"lastName": manifest["deployment"],
171200
"enabled": True,
172201
}
173202
)
203+
if "attributes" not in send_payload:
204+
send_payload["attributes"] = {
205+
"callsign": pdata.callsign,
206+
}
174207
send_payload["attributes"].update(
175208
{
176209
"certpem": pdata.x509cert,
177210
"altUsernames": [f"{pdata.callsign}_{productname}" for productname in manifest["products"].keys()],
178211
}
179212
)
180-
await self.kcadmin.a_update_user(user.kc_id, send_payload)
213+
for rofieldname in ("createTimestamp", "createdTimestamp", "modifyTimestamp"):
214+
if rofieldname in send_payload:
215+
del send_payload[rofieldname]
216+
if rofieldname in send_payload["attributes"]:
217+
del send_payload["attributes"][rofieldname]
218+
LOGGER.debug("Sending payload: {}".format(send_payload))
219+
try:
220+
await self.kcadmin.a_update_user(user.kc_id, send_payload)
221+
except KeycloakError as exc:
222+
LOGGER.exception("Could not update KC user: {}".format(exc))
181223
return await self._refresh_user(user.kc_id, pdata)
182224

183225
async def delete_kc_user(self, user: KCUserData) -> bool:

src/rasenmaeher_api/prodcutapihelpers.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ async def _method_to_all_products(
8484
async def handle_one(name: str) -> Tuple[str, Optional[pydantic.BaseModel]]:
8585
"""Do one call"""
8686
nonlocal url_suffix, methodname, respose_schema, data
87-
return name, await _method_to_product(name, methodname, url_suffix, data, respose_schema)
87+
try:
88+
return name, await _method_to_product(name, methodname, url_suffix, data, respose_schema)
89+
except Exception as exc: # pylint: disable=W0718
90+
LOGGER.exception(exc)
91+
return name, None
8892

8993
if not collect_responses:
9094
tma = TaskMaster.singleton()

tests/test_rasenmaeher_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
def test_version() -> None:
1717
"""Make sure version matches expected"""
18-
assert __version__ == "1.6.1"
18+
assert __version__ == "1.6.2"
1919

2020

2121
@pytest.mark.asyncio(loop_scope="session")

0 commit comments

Comments
 (0)