Repository: cobbler/cobbler

Issue:
Log when a config object is ignored because a dependency is missing
Currentlya Distro object will not show up when the kernel is missing, which will result in the profile not showing up, because the distro is missing etc.
This is in principle okay, but as a user, one doesn't even get a warning in the log, which is bad. It doesn't seem to hard to just log when silently discarding an object, making it simpler to debug why stuff doesn't show up in the web interface.



Discussion:
note to self: collection_manager needs to be fixed

iirc a missing kernel in distro object will interrupt cobblerd start (distro.set_kernel() throws an exception with "kernel not found: <kernel_name>" msg and this exception msg ends up being show to user). A similar exception is thrown in tftpgen.py and logged to cobbler sync log. Therefore, missing kernel is never silently ignored and this bug does not exist anymore.

Maybe we want to improve code to support cobblerd start even if there are distros with missing kernel/initrd? As a Cobbler admin, this feature does not matter much to me, as adding a distro with a missing kernel/distro is forbidden and this could only happen if someone deletes those files or unmounts a NFS share I'm accessing, in which case the problem should be fixed asap. I see no advantage in supporting cobblerd start on this situation.


Resolving patch:
diff --git a/cobbler/cobbler_collections/collection.py b/cobbler/cobbler_collections/collection.py
--- a/cobbler/cobbler_collections/collection.py
+++ b/cobbler/cobbler_collections/collection.py
@@ -203,8 +203,13 @@ def from_list(self, _list: list):
         if _list is None:
             return
         for item_dict in _list:
-            item = self.factory_produce(self.api, item_dict)
-            self.add(item)
+            try:
+                item = self.factory_produce(self.api, item_dict)
+                self.add(item)
+            except Exception as exc:
+                self.logger.error(
+                    f"Error while loading a collection: {exc}. Skipping this collection!"
+                )
 
     def copy(self, ref, newname):
         """
diff --git a/cobbler/modules/serializers/file.py b/cobbler/modules/serializers/file.py
--- a/cobbler/modules/serializers/file.py
+++ b/cobbler/modules/serializers/file.py
@@ -11,12 +11,15 @@
 import os
 import glob
 import json
+import logging
 
 import cobbler.api as capi
 from cobbler import settings
 from cobbler.cexceptions import CX
 from cobbler.modules.serializers import StorageBase
 
+logger = logging.getLogger()
+
 
 def register() -> str:
     """
@@ -110,10 +113,15 @@ def deserialize(self, collection, topological: bool = True):
         datastruct = self.deserialize_raw(collection.collection_types())
         if topological and isinstance(datastruct, list):
             datastruct.sort(key=lambda x: x.get("depth", 1))
-        if isinstance(datastruct, dict):
-            collection.from_dict(datastruct)
-        elif isinstance(datastruct, list):
-            collection.from_list(datastruct)
+        try:
+            if isinstance(datastruct, dict):
+                collection.from_dict(datastruct)
+            elif isinstance(datastruct, list):
+                collection.from_list(datastruct)
+        except Exception as exc:
+            logger.error(
+                f"Error while loading a collection: {exc}. Skipping this collection!"
+            )
 
 
 def storage_factory(api):
diff --git a/cobbler/utils/__init__.py b/cobbler/utils/__init__.py
--- a/cobbler/utils/__init__.py
+++ b/cobbler/utils/__init__.py
@@ -480,9 +480,10 @@ def blender(api_handle, remove_dicts: bool, root_obj):
         for key in child_names:
             child = api_handle.find_items("", name=key, return_list=False)
             if child is None:
-                raise ValueError(
-                    f'Child with the name "{key}" of parent object "{root_obj.name}" did not exist!'
+                logger.error(
+                    f'Child with the name "{key}" did not exist! This child is referenced in consolidated object "{root_obj.name}".'
                 )
+                continue
             results["children"][key] = child.to_dict()
 
     # sanitize output for koan and kernel option lines, etc


Test patch: