11import logging
2+ import uuid
23from typing import Iterator , Optional
34
45from datamasque .client .base import BaseClient
5- from datamasque .client .exceptions import DataMasqueApiError , DataMasqueException
6+ from datamasque .client .exceptions import DataMasqueApiError , DataMasqueArgumentError , DataMasqueException
67from datamasque .client .models .discovery_config import DiscoveryConfig , DiscoveryConfigId , DiscoveryConfigType
78from datamasque .client .models .pagination import Page
89
@@ -75,15 +76,20 @@ def create_discovery_config(self, config: DiscoveryConfig) -> DiscoveryConfig:
7576 Creates a new discovery config on the server.
7677
7778 Sets the config's server-assigned fields
78- (`id`, `is_valid`, `validation_error`, `created`, `modified`) and returns the config.
79+ (`id`, `is_valid`, `validation_error`, `validation_error_details`, `created`, `modified`)
80+ and returns the config.
7981 """
8082
83+ if not config .yaml :
84+ raise DataMasqueArgumentError ("Cannot create a discovery config without YAML content (yaml is empty)" )
85+
8186 data = config .model_dump (exclude_none = True , by_alias = True , mode = "json" )
8287 response = self .make_request ("POST" , "/api/discovery/configs/" , data = data )
8388 created = DiscoveryConfig .model_validate (response .json ())
8489 config .id = created .id
8590 config .is_valid = created .is_valid
8691 config .validation_error = created .validation_error
92+ config .validation_error_details = created .validation_error_details
8793 config .created = created .created
8894 config .modified = created .modified
8995 logger .info ('Creation of discovery config "%s" successful' , config .name )
@@ -94,17 +100,24 @@ def update_discovery_config(self, config: DiscoveryConfig) -> DiscoveryConfig:
94100 Performs a full update of the discovery config.
95101
96102 The config must have its `id` set
97- (i.e., it must have been previously created or retrieved from the server) .
103+ and its `yaml` content present .
98104 """
99105
100106 if config .id is None :
101- raise ValueError ("Cannot update a discovery config that has not been created yet (id is None)" )
107+ raise DataMasqueArgumentError ("Cannot update a discovery config that has not been created yet (id is None)" )
108+
109+ if not config .yaml :
110+ raise DataMasqueArgumentError (
111+ "Cannot update a discovery config without YAML content (yaml is empty or unset); "
112+ "list results omit YAML, so fetch the full config with `get_discovery_config` first"
113+ )
102114
103115 data = config .model_dump (exclude_none = True , by_alias = True , mode = "json" )
104116 response = self .make_request ("PUT" , f"/api/discovery/configs/{ config .id } /" , data = data )
105117 updated = DiscoveryConfig .model_validate (response .json ())
106118 config .is_valid = updated .is_valid
107119 config .validation_error = updated .validation_error
120+ config .validation_error_details = updated .validation_error_details
108121 config .modified = updated .modified
109122 logger .debug ('Update of discovery config "%s" successful' , config .name )
110123 return config
@@ -123,6 +136,42 @@ def create_or_update_discovery_config(self, config: DiscoveryConfig) -> Discover
123136
124137 return self .create_discovery_config (config )
125138
139+ def validate_discovery_config (self , config : DiscoveryConfig ) -> DiscoveryConfig :
140+ """Validates a discovery config against the server."""
141+
142+ if not config .yaml :
143+ raise DataMasqueArgumentError (
144+ "Cannot validate a discovery config without YAML content (yaml is empty or unset); "
145+ "list results omit YAML, so fetch the full config with `get_discovery_config` first"
146+ )
147+
148+ temporary = DiscoveryConfig (
149+ name = f"dm_python_validate_{ uuid .uuid4 ().hex } " ,
150+ yaml = config .yaml ,
151+ config_type = config .config_type ,
152+ )
153+ data = temporary .model_dump (exclude_none = True , by_alias = True , mode = "json" )
154+ response = self .make_request ("POST" , "/api/discovery/configs/" , data = data )
155+
156+ payload = response .json ()
157+ raw_id = payload .get ("id" ) if isinstance (payload , dict ) else None
158+ created_id = DiscoveryConfigId (raw_id ) if isinstance (raw_id , str ) else None
159+
160+ try :
161+ created = DiscoveryConfig .model_validate (payload )
162+ config .is_valid = created .is_valid
163+ config .validation_error = created .validation_error
164+ config .validation_error_details = created .validation_error_details
165+ finally :
166+ if created_id is not None :
167+ self ._delete_best_effort (
168+ lambda : self .delete_discovery_config_by_id_if_exists (created_id ),
169+ f'temporary validation config "{ temporary .name } "' ,
170+ )
171+
172+ logger .debug ('Validation of discovery config "%s" complete' , config .name )
173+ return config
174+
126175 def delete_discovery_config_by_id_if_exists (self , config_id : DiscoveryConfigId ) -> None :
127176 """
128177 Deletes the discovery config with the given ID.
0 commit comments