Skip to content

Commit 6bd3147

Browse files
author
Alan Christie
committed
fix: Work-around the 409 conflict errors
1 parent f22b76f commit 6bd3147

File tree

1 file changed

+83
-64
lines changed

1 file changed

+83
-64
lines changed

operator/handlers.py

Lines changed: 83 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,55 @@ def create(spec: Dict[str, Any], name: str, namespace: str, **_: Any) -> Dict[st
142142
logging.info("Starting create (name=%s namespace=%s)...", name, namespace)
143143
logging.info("spec=%s (name=%s)", spec, name)
144144

145+
# All Data-Manager provided material
146+
# will be namespaced under the 'imDataManager' property
147+
material: Dict[str, Any] = spec.get("imDataManager", {})
148+
149+
notebook_interface = material.get("notebook", {}).get("interface", "lab")
150+
151+
image = material.get("image", _DEFAULT_IMAGE)
152+
image_parts = image.split(":")
153+
image_tag = "latest" if len(image_parts) == 1 else image_parts[1]
154+
image_pull_policy = (
155+
"Always" if image_tag.lower() in ["latest", "stable"] else "IfNotPresent"
156+
)
157+
158+
service_account = material.get("serviceAccountName", _DEFAULT_SA)
159+
160+
resources = material.get("resources", {})
161+
cpu_limit = resources.get("limits", {}).get("cpu", _DEFAULT_CPU_LIMIT)
162+
cpu_request = resources.get("requests", {}).get("cpu", _DEFAULT_CPU_REQUEST)
163+
memory_limit = resources.get("limits", {}).get("memory", _DEFAULT_MEM_LIMIT)
164+
memory_request = resources.get("requests", {}).get("memory", _DEFAULT_MEM_REQUEST)
165+
166+
# Data Manager API compliance.
167+
#
168+
# The user and group IDs we're asked to run as.
169+
# The files in the container project volume will be owned
170+
# by this user and group. We must run as group 100.
171+
# We use the supplied group ID and pass that into the container
172+
# as the Kubernetes 'File System Group' (fsGroup).
173+
# This should allow us to run and manipulate the files.
174+
sc_run_as_user = material.get("securityContext", {}).get(
175+
"runAsUser", _DEFAULT_USER_ID
176+
)
177+
sc_run_as_group = material.get("securityContext", {}).get(
178+
"runAsGroup", _DEFAULT_GROUP_ID
179+
)
180+
181+
# Project storage
182+
project_claim_name = material.get("project", {}).get("claimName")
183+
project_id = material.get("project", {}).get("id")
184+
185+
ingress_proxy_body_size = material.get(
186+
"ingressProxyBodySize", _DEFAULT_INGRESS_PROXY_BODY_SIZE
187+
)
188+
189+
ingress_class = material.get("ingressClass", _DEFAULT_INGRESS_CLASS)
190+
ingress_domain = material.get("ingressDomain", _DEFAULT_INGRESS_DOMAIN)
191+
ingress_tls_secret = material.get("ingressTlsSecret", _DEFAULT_INGRESS_TLS_SECRET)
192+
ingress_path = f"/{name}"
193+
145194
# ConfigMaps
146195
# ----------
147196

@@ -169,11 +218,43 @@ def create(spec: Dict[str, Any], name: str, namespace: str, **_: Any) -> Dict[st
169218
"data": {"jupyter_notebook_config.json": _NOTEBOOK_CONFIG % config_vars},
170219
}
171220

221+
create_response = {
222+
"notebook": {
223+
"url": f"http://{ingress_domain}{ingress_path}?token={token}",
224+
"token": token,
225+
"interface": notebook_interface,
226+
},
227+
"image": image,
228+
"serviceAccountName": service_account,
229+
"resources": {
230+
"requests": {"memory": memory_request},
231+
"limits": {"memory": memory_limit},
232+
},
233+
"project": {"claimName": project_claim_name, "id": project_id},
234+
}
235+
172236
kopf.adopt(bp_cm_body)
173237
kopf.adopt(startup_cm_body)
174238
kopf.adopt(config_cm_body)
175239
core_api = kubernetes.client.CoreV1Api()
176-
core_api.create_namespaced_config_map(namespace, bp_cm_body)
240+
241+
# We currently see a number of 409 exceptions with the objects we create
242+
# (with the reason 'Conflict'). As each one has a unique name
243+
# we have to assume there is a serious underlying problem
244+
# in kopf of kubernetes. For now, if the first object we create
245+
# already exists let us assume they all do?
246+
#
247+
# Added as a work-wround for sc-
248+
try:
249+
core_api.create_namespaced_config_map(namespace, bp_cm_body)
250+
except kubernetes.client.exceptions.ApiException as ex:
251+
if ex.status != 409 or ex.reason != "Conflict":
252+
raise ex
253+
# Warn, but ignore and return a valid 'create' response now.
254+
logging.warning(
255+
"Got ApiException [409/Conflict] creating BP ConfigMap. Ignoring [#10]"
256+
)
257+
return create_response
177258
core_api.create_namespaced_config_map(namespace, startup_cm_body)
178259
core_api.create_namespaced_config_map(namespace, config_cm_body)
179260

@@ -184,46 +265,6 @@ def create(spec: Dict[str, Any], name: str, namespace: str, **_: Any) -> Dict[st
184265

185266
logging.info("Creating Deployment %s...", name)
186267

187-
# All Data-Manager provided material
188-
# will be namespaced under the 'imDataManager' property
189-
material: Dict[str, Any] = spec.get("imDataManager", {})
190-
191-
notebook_interface = material.get("notebook", {}).get("interface", "lab")
192-
193-
image = material.get("image", _DEFAULT_IMAGE)
194-
image_parts = image.split(":")
195-
image_tag = "latest" if len(image_parts) == 1 else image_parts[1]
196-
image_pull_policy = (
197-
"Always" if image_tag.lower() in ["latest", "stable"] else "IfNotPresent"
198-
)
199-
200-
service_account = material.get("serviceAccountName", _DEFAULT_SA)
201-
202-
resources = material.get("resources", {})
203-
cpu_limit = resources.get("limits", {}).get("cpu", _DEFAULT_CPU_LIMIT)
204-
cpu_request = resources.get("requests", {}).get("cpu", _DEFAULT_CPU_REQUEST)
205-
memory_limit = resources.get("limits", {}).get("memory", _DEFAULT_MEM_LIMIT)
206-
memory_request = resources.get("requests", {}).get("memory", _DEFAULT_MEM_REQUEST)
207-
208-
# Data Manager API compliance.
209-
#
210-
# The user and group IDs we're asked to run as.
211-
# The files in the container project volume will be owned
212-
# by this user and group. We must run as group 100.
213-
# We use the supplied group ID and pass that into the container
214-
# as the Kubernetes 'File System Group' (fsGroup).
215-
# This should allow us to run and manipulate the files.
216-
sc_run_as_user = material.get("securityContext", {}).get(
217-
"runAsUser", _DEFAULT_USER_ID
218-
)
219-
sc_run_as_group = material.get("securityContext", {}).get(
220-
"runAsGroup", _DEFAULT_GROUP_ID
221-
)
222-
223-
# Project storage
224-
project_claim_name = material.get("project", {}).get("claimName")
225-
project_id = material.get("project", {}).get("id")
226-
227268
# Command is simply our custom start script,
228269
# which is mounted at /usr/local/bin
229270
command_items = ["bash", "/usr/local/bin/start.sh"]
@@ -368,15 +409,6 @@ def create(spec: Dict[str, Any], name: str, namespace: str, **_: Any) -> Dict[st
368409

369410
logging.info("Creating Ingress %s...", name)
370411

371-
ingress_proxy_body_size = material.get(
372-
"ingressProxyBodySize", _DEFAULT_INGRESS_PROXY_BODY_SIZE
373-
)
374-
375-
ingress_class = material.get("ingressClass", _DEFAULT_INGRESS_CLASS)
376-
ingress_domain = material.get("ingressDomain", _DEFAULT_INGRESS_DOMAIN)
377-
ingress_tls_secret = material.get("ingressTlsSecret", _DEFAULT_INGRESS_TLS_SECRET)
378-
ingress_path = f"/{name}"
379-
380412
ingress_body: Dict[Any, Any] = {
381413
"kind": "Ingress",
382414
"apiVersion": "networking.k8s.io/v1",
@@ -424,17 +456,4 @@ def create(spec: Dict[str, Any], name: str, namespace: str, **_: Any) -> Dict[st
424456
# Done
425457
# ----
426458

427-
return {
428-
"notebook": {
429-
"url": f"http://{ingress_domain}{ingress_path}?token={token}",
430-
"token": token,
431-
"interface": notebook_interface,
432-
},
433-
"image": image,
434-
"serviceAccountName": service_account,
435-
"resources": {
436-
"requests": {"memory": memory_request},
437-
"limits": {"memory": memory_limit},
438-
},
439-
"project": {"claimName": project_claim_name, "id": project_id},
440-
}
459+
return create_response

0 commit comments

Comments
 (0)