diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index e87a972..362661b 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -305,6 +305,31 @@ def validate_api_definition(value): return validate_dict(value, required_fields) +def prune_empty_data(data): + """ + Recursively remove empty values from dictionaries and lists. + Empty values include: None, empty strings, empty lists, empty dicts. + """ + + def is_empty(value): + return value is None or value == "" or value == [] or value == {} + + if isinstance(data, dict): + return { + key: pruned_value + for key, value in data.items() + if not is_empty(pruned_value := prune_empty_data(value)) + } + elif isinstance(data, list): + return [ + pruned_item + for item in data + if not is_empty(pruned_item := prune_empty_data(item)) + ] + else: + return data + + class ServiceDefinition(ServalaModelMixin, models.Model): """ Configuration/service implementation: contains information on which @@ -568,6 +593,16 @@ class ServiceInstance(ServalaModelMixin, models.Model): if key in attrs: delattr(self, key) + @classmethod + def _prepare_spec_data(cls, spec_data): + """ + Prepare spec data by pruning empty values and ensuring required fields. + This method centralizes spec data processing to ensure consistency. + """ + spec_data = spec_data or {} + spec_data = prune_empty_data(spec_data) + return spec_data + @classmethod def create_instance(cls, name, organization, context, created_by, spec_data): # Ensure the namespace exists @@ -587,7 +622,8 @@ class ServiceInstance(ServalaModelMixin, models.Model): ) try: - spec_data = spec_data or {} + spec_data = cls._prepare_spec_data(spec_data) + if "writeConnectionSecretToRef" not in spec_data: spec_data["writeConnectionSecretToRef"] = {} @@ -629,6 +665,7 @@ class ServiceInstance(ServalaModelMixin, models.Model): def update_spec(self, spec_data, updated_by): try: + spec_data = self._prepare_spec_data(spec_data) api_instance = self.context.control_plane.custom_objects_api patch_body = {"spec": spec_data}