Skip to content

Commit 2b4b263

Browse files
authored
Strip /v3 suffix from app cred auth url and improve error handling (#116)
1 parent 426acad commit 2b4b263

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

capi_janitor/openstack/openstack.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import contextlib
3+
import re
34
import urllib.parse
45

56
import httpx
@@ -14,6 +15,13 @@ class UnsupportedAuthenticationError(Exception):
1415
def __init__(self, auth_type):
1516
super().__init__(f"unsupported authentication type: {auth_type}")
1617

18+
class AuthenticationError(Exception):
19+
"""
20+
Raised when an unknown authentication error is encountered.
21+
"""
22+
def __init__(self, user):
23+
super().__init__(f"failed to authenticate as user: {user}")
24+
1725

1826
class Auth(httpx.Auth):
1927
"""
@@ -55,7 +63,7 @@ def _build_token_request(self):
5563
},
5664
}
5765
)
58-
66+
5967
def _handle_token_response(self, response):
6068
response.raise_for_status()
6169
self._token = response.headers["X-Subject-Token"]
@@ -91,7 +99,7 @@ def _extract_list(self, response):
9199
# Some resources support a /detail endpoint
92100
# In this case, we just want to use the name up to the slash
93101
return response.json()[self._plural_name]
94-
102+
95103
def _extract_next_page(self, response):
96104
next_url = next(
97105
(
@@ -131,7 +139,7 @@ def __init__(self, /, base_url, prefix = None, **kwargs):
131139
def __aenter__(self):
132140
# Prevent individual clients from being used in a context manager
133141
raise RuntimeError("clients must be used via a cloud object")
134-
142+
135143
def resource(self, name, prefix = None, plural_name = None, singular_name = None):
136144
# If an additional prefix is given, combine it with the existing prefix
137145
if prefix:
@@ -199,7 +207,7 @@ def apis(self):
199207
The APIs supported by the cloud.
200208
"""
201209
return list(self._endpoints.keys())
202-
210+
203211
def api_client(self, name, prefix = None):
204212
"""
205213
Returns a client for the named API.
@@ -218,8 +226,9 @@ def from_clouds(cls, clouds, cloud, cacert):
218226
config = clouds["clouds"][cloud]
219227
if config["auth_type"] != "v3applicationcredential":
220228
raise UnsupportedAuthenticationError(config["auth_type"])
229+
auth_url = re.sub("/v3/?$", "", config["auth"]["auth_url"])
221230
auth = Auth(
222-
config["auth"]["auth_url"],
231+
auth_url,
223232
config["auth"]["application_credential_id"],
224233
config["auth"]["application_credential_secret"]
225234
)

capi_janitor/openstack/operator.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,15 @@ async def purge_openstack_resources(
152152
"""
153153
# Use the credential to delete external resources as required
154154
async with openstack.Cloud.from_clouds(clouds, cloud_name, cacert) as cloud:
155-
# If the session is not authenticated, there is nothing we can do
156155
if not cloud.is_authenticated:
157-
logger.warn("application credential has been deleted")
156+
if include_appcred:
157+
# If the session is not authenticated then we've already
158+
# cleaned up and deleted the app cred.
159+
logger.warn("application credential has been deleted")
160+
else:
161+
# Raise an error and skip removing the finalizer to block cluster
162+
# deletion to avoid leaking resources.
163+
raise openstack.AuthenticationError(cloud.current_user_id)
158164
return
159165

160166
# Release any floating IPs associated with loadbalancer services for the cluster
@@ -301,7 +307,7 @@ async def wrapper(**kwargs):
301307
if exc.status_code != 404:
302308
raise
303309
return wrapper
304-
310+
305311

306312
@kopf.on.event(CAPO_API_GROUP, "openstackclusters")
307313
@retry_event
@@ -326,7 +332,7 @@ async def on_openstackcluster_event(name, namespace, meta, spec, logger, **kwarg
326332
)
327333
logger.info("added janitor finalizer to cluster")
328334
return
329-
335+
330336
# NOTE: If we get to here, the cluster is deleting
331337

332338
# If our finalizer is not present, we don't do anything

0 commit comments

Comments
 (0)