1
1
use super :: config:: ProxyWrapper ;
2
2
use super :: BridgeConfig ;
3
3
use crate :: bridge:: config:: BridgeLocation ;
4
+ use crate :: ConfigError ;
5
+ use c8y_api:: http_proxy:: read_c8y_credentials;
4
6
use camino:: Utf8PathBuf ;
5
7
use std:: borrow:: Cow ;
6
8
use std:: process:: Command ;
@@ -13,8 +15,10 @@ use tedge_config::models::AutoFlag;
13
15
use tedge_config:: models:: HostPort ;
14
16
use tedge_config:: models:: TemplatesSet ;
15
17
use tedge_config:: models:: TopicPrefix ;
18
+ use tedge_config:: models:: MQTT_SVC_TLS_PORT ;
16
19
use tedge_config:: models:: MQTT_TLS_PORT ;
17
20
use tedge_config:: tedge_toml:: ProfileName ;
21
+ use tedge_config:: TEdgeConfig ;
18
22
use which:: which;
19
23
20
24
#[ derive( Debug ) ]
@@ -201,6 +205,171 @@ impl From<BridgeConfigC8yParams> for BridgeConfig {
201
205
}
202
206
}
203
207
208
+ #[ derive( Debug ) ]
209
+ pub struct BridgeConfigC8yMqttServiceParams {
210
+ pub mqtt_host : HostPort < MQTT_SVC_TLS_PORT > ,
211
+ pub config_file : Cow < ' static , str > ,
212
+ pub tenant_id : String ,
213
+ pub remote_clientid : String ,
214
+ pub remote_username : Option < String > ,
215
+ pub remote_password : Option < String > ,
216
+ pub bridge_root_cert_path : Utf8PathBuf ,
217
+ pub bridge_certfile : Utf8PathBuf ,
218
+ pub bridge_keyfile : Utf8PathBuf ,
219
+ pub include_local_clean_session : AutoFlag ,
220
+ pub bridge_location : BridgeLocation ,
221
+ pub topic_prefix : TopicPrefix ,
222
+ pub profile_name : Option < ProfileName > ,
223
+ pub mqtt_schema : MqttSchema ,
224
+ pub keepalive_interval : Duration ,
225
+ }
226
+
227
+ impl TryFrom < ( & TEdgeConfig , Option < & ProfileName > ) > for BridgeConfigC8yMqttServiceParams {
228
+ type Error = ConfigError ;
229
+
230
+ fn try_from ( value : ( & TEdgeConfig , Option < & ProfileName > ) ) -> Result < Self , Self :: Error > {
231
+ let ( config, profile) = value;
232
+
233
+ let bridge_location = match config. mqtt . bridge . built_in {
234
+ true => BridgeLocation :: BuiltIn ,
235
+ false => BridgeLocation :: Mosquitto ,
236
+ } ;
237
+ let mqtt_schema = MqttSchema :: with_root ( config. mqtt . topic_root . clone ( ) ) ;
238
+ let c8y_config = config. c8y . try_get ( profile) ?;
239
+
240
+ let ( remote_username, remote_password) =
241
+ match c8y_config. auth_method . to_type ( & c8y_config. credentials_path ) {
242
+ AuthType :: Certificate => ( None , None ) ,
243
+ AuthType :: Basic => {
244
+ let ( username, password) = read_c8y_credentials ( & c8y_config. credentials_path ) ?;
245
+ ( Some ( username) , Some ( password) )
246
+ }
247
+ } ;
248
+
249
+ let config_file = if let Some ( profile_name) = & profile {
250
+ format ! ( "c8y-mqtt-svc@{profile_name}-bridge.conf" )
251
+ } else {
252
+ "c8y-mqtt-svc-bridge.conf" . to_string ( )
253
+ } ;
254
+ let params = BridgeConfigC8yMqttServiceParams {
255
+ mqtt_host : c8y_config. mqtt_service . url . or_config_not_set ( ) ?. clone ( ) ,
256
+ config_file : config_file. into ( ) ,
257
+ tenant_id : c8y_config. tenant_id . or_config_not_set ( ) ?. clone ( ) ,
258
+ bridge_root_cert_path : c8y_config. root_cert_path . clone ( ) . into ( ) ,
259
+ remote_clientid : c8y_config. device . id ( ) ?. clone ( ) ,
260
+ remote_username,
261
+ remote_password,
262
+ bridge_certfile : c8y_config. device . cert_path . clone ( ) . into ( ) ,
263
+ bridge_keyfile : c8y_config. device . key_path . clone ( ) . into ( ) ,
264
+ include_local_clean_session : c8y_config. bridge . include . local_cleansession . clone ( ) ,
265
+ bridge_location,
266
+ topic_prefix : c8y_config. mqtt_service . topic_prefix . clone ( ) ,
267
+ profile_name : profile. cloned ( ) ,
268
+ mqtt_schema,
269
+ keepalive_interval : c8y_config. bridge . keepalive_interval . duration ( ) ,
270
+ } ;
271
+
272
+ Ok ( params)
273
+ }
274
+ }
275
+
276
+ impl From < BridgeConfigC8yMqttServiceParams > for BridgeConfig {
277
+ fn from ( params : BridgeConfigC8yMqttServiceParams ) -> Self {
278
+ let BridgeConfigC8yMqttServiceParams {
279
+ mqtt_host,
280
+ config_file,
281
+ bridge_root_cert_path,
282
+ tenant_id,
283
+ mut remote_username,
284
+ remote_password,
285
+ remote_clientid,
286
+ bridge_certfile,
287
+ bridge_keyfile,
288
+ include_local_clean_session,
289
+ bridge_location,
290
+ topic_prefix,
291
+ profile_name,
292
+ mqtt_schema,
293
+ keepalive_interval,
294
+ } = params;
295
+
296
+ let address = mqtt_host
297
+ . to_string ( )
298
+ . parse :: < HostPort < MQTT_TLS_PORT > > ( )
299
+ . expect ( "MQTT service address must be in the expected format" ) ;
300
+
301
+ let topics: Vec < String > = vec ! [
302
+ // Outgoing
303
+ format!( r#"# out 1 {topic_prefix}/"# ) ,
304
+ // Incoming
305
+ format!( r#"$debug/$error in 1 {topic_prefix}/"# ) ,
306
+ ] ;
307
+
308
+ let auth_type = if remote_password. is_some ( ) {
309
+ AuthType :: Basic
310
+ } else {
311
+ AuthType :: Certificate
312
+ } ;
313
+
314
+ // When cert based auth is used, provide the tenant id as the username
315
+ if auth_type == AuthType :: Certificate {
316
+ remote_username = Some ( tenant_id. clone ( ) ) ;
317
+ }
318
+
319
+ let ( include_local_clean_session, mosquitto_version) = match include_local_clean_session {
320
+ AutoFlag :: True => ( true , None ) ,
321
+ AutoFlag :: False => ( false , None ) ,
322
+ AutoFlag :: Auto => is_mosquitto_version_above_2 ( ) ,
323
+ } ;
324
+
325
+ let service_name = format ! ( "mosquitto-{topic_prefix}-bridge" ) ;
326
+ let health = mqtt_schema. topic_for (
327
+ & EntityTopicId :: default_main_service ( & service_name) . unwrap ( ) ,
328
+ & Channel :: Health ,
329
+ ) ;
330
+
331
+ Self {
332
+ cloud_name : "c8y-mqtt" . into ( ) ,
333
+ config_file,
334
+ connection : if let Some ( profile) = & profile_name {
335
+ format ! ( "edge_to_c8y_mqtt_service@{profile}" )
336
+ } else {
337
+ "edge_to_c8y_mqtt_service" . into ( )
338
+ } ,
339
+ address,
340
+ remote_username,
341
+ remote_password,
342
+ bridge_root_cert_path,
343
+ remote_clientid,
344
+ local_clientid : if let Some ( profile) = & profile_name {
345
+ format ! ( "CumulocityMqttService@{profile}" )
346
+ } else {
347
+ "CumulocityMqttService" . into ( )
348
+ } ,
349
+ bridge_certfile,
350
+ bridge_keyfile,
351
+ use_mapper : true ,
352
+ use_agent : true ,
353
+ try_private : false ,
354
+ start_type : "automatic" . into ( ) ,
355
+ clean_session : true ,
356
+ include_local_clean_session,
357
+ local_clean_session : false ,
358
+ notifications : true ,
359
+ notifications_local_only : true ,
360
+ notification_topic : health. name ,
361
+ bridge_attempt_unsubscribe : false ,
362
+ topics,
363
+ bridge_location,
364
+ connection_check_attempts : 3 ,
365
+ auth_type,
366
+ mosquitto_version,
367
+ keepalive_interval,
368
+ proxy : None ,
369
+ }
370
+ }
371
+ }
372
+
204
373
/// Return whether or not mosquitto version is >= 2.0.0
205
374
///
206
375
/// As mosquitto doesn't provide a `--version` flag, this is a guess.
0 commit comments