88
99import os
1010
11- from datamasque .client import DataMasqueClient
12- from datamasque .client .exceptions import DataMasqueApiError , DataMasqueTransportError
11+ from datamasque .client import DataMasqueClient , DataMasqueIfmClient
12+ from datamasque .client .exceptions import DataMasqueApiError , DataMasqueTransportError , IfmAuthError
1313from datamasque .client .models .dm_instance import DataMasqueInstanceConfig
14+ from datamasque .client .models .ifm import DataMasqueIfmInstanceConfig
1415
1516from datamasque_cli .config import Config , Profile , load_config
1617from datamasque_cli .output import ErrorCode , abort
@@ -59,25 +60,45 @@ def _resolve_profile(config: Config, profile_name: str | None) -> Profile:
5960 return profile
6061
6162
63+ def _resolve_profile_with_verify (profile_name : str | None ) -> tuple [Profile , bool ]:
64+ """Resolve the active `Profile` and apply env-var overrides for `verify_ssl`."""
65+ env_profile = profile_from_env () if profile_name is None else None
66+ if env_profile is not None :
67+ profile = env_profile
68+ else :
69+ config = load_config ()
70+ profile = _resolve_profile (config , profile_name )
71+ return profile , _verify_ssl_from_env (default = profile .verify_ssl )
72+
73+
74+ def _authenticate_or_abort (
75+ client : DataMasqueClient | DataMasqueIfmClient ,
76+ url : str ,
77+ * ,
78+ verify_ssl : bool ,
79+ failure_label : str = "Authentication" ,
80+ extra_auth_excs : tuple [type [Exception ], ...] = (),
81+ ) -> None :
82+ try :
83+ client .authenticate ()
84+ except DataMasqueTransportError as e :
85+ abort (_format_transport_error (url , e , verify_ssl = verify_ssl ), code = ErrorCode .TRANSPORT_ERROR )
86+ except (DataMasqueApiError , * extra_auth_excs ) as e :
87+ abort (f"{ failure_label } failed: { e } " , code = ErrorCode .AUTH_FAILED )
88+
89+
6290def get_client (profile_name : str | None = None ) -> DataMasqueClient :
6391 """Build and authenticate a `DataMasqueClient`.
6492
6593 Credential resolution order:
6694 1. Environment variables (DATAMASQUE_URL, DATAMASQUE_USERNAME, DATAMASQUE_PASSWORD)
6795 2. Named profile (--profile flag)
6896 3. Active profile from config file
69- """
70- # Env vars take precedence unless a specific profile was requested.
71- env_profile = profile_from_env () if profile_name is None else None
72- if env_profile is not None :
73- profile = env_profile
74- else :
75- config = load_config ()
76- profile = _resolve_profile (config , profile_name )
7797
78- # `DATAMASQUE_VERIFY_SSL` always wins over the stored profile so you can
79- # flip TLS verification per-call without re-running `dm auth login`.
80- verify_ssl = _verify_ssl_from_env (default = profile .verify_ssl )
98+ `DATAMASQUE_VERIFY_SSL` always wins over the stored profile so you can
99+ flip TLS verification per-call without re-running `dm auth login`.
100+ """
101+ profile , verify_ssl = _resolve_profile_with_verify (profile_name )
81102 instance_config = DataMasqueInstanceConfig (
82103 base_url = profile .url ,
83104 username = profile .username ,
@@ -86,14 +107,7 @@ def get_client(profile_name: str | None = None) -> DataMasqueClient:
86107 )
87108
88109 client = DataMasqueClient (instance_config )
89-
90- try :
91- client .authenticate ()
92- except DataMasqueTransportError as e :
93- abort (_format_transport_error (profile .url , e , verify_ssl = verify_ssl ), code = ErrorCode .TRANSPORT_ERROR )
94- except DataMasqueApiError as e :
95- abort (f"Authentication failed: { e } " , code = ErrorCode .AUTH_FAILED )
96-
110+ _authenticate_or_abort (client , profile .url , verify_ssl = verify_ssl )
97111 return client
98112
99113
@@ -107,3 +121,30 @@ def _format_transport_error(url: str, error: Exception, *, verify_ssl: bool) ->
107121 if verify_ssl and any (term in str (error ).lower () for term in _SSL_HINT_TERMS ):
108122 message += "\n If this is a self-signed local build, retry with --insecure or set DATAMASQUE_VERIFY_SSL=false."
109123 return message
124+
125+
126+ def get_ifm_client (profile_name : str | None = None ) -> DataMasqueIfmClient :
127+ """Build and authenticate a `DataMasqueIfmClient`.
128+
129+ Credential resolution order matches `get_client`.
130+ The IFM base URL is derived as `<admin_url>/ifm`,
131+ matching the standard nginx topology that proxies `/ifm/` to the IFM container on the same hostname.
132+ """
133+ profile , verify_ssl = _resolve_profile_with_verify (profile_name )
134+ instance_config = DataMasqueIfmInstanceConfig (
135+ admin_server_base_url = profile .url ,
136+ ifm_base_url = f"{ profile .url .rstrip ('/' )} /ifm" ,
137+ username = profile .username ,
138+ password = profile .password ,
139+ verify_ssl = verify_ssl ,
140+ )
141+
142+ client = DataMasqueIfmClient (instance_config )
143+ _authenticate_or_abort (
144+ client ,
145+ profile .url ,
146+ verify_ssl = verify_ssl ,
147+ failure_label = "IFM authentication" ,
148+ extra_auth_excs = (IfmAuthError ,),
149+ )
150+ return client
0 commit comments