74
74
import logging
75
75
import os
76
76
from pathlib import Path , PurePosixPath
77
+ from pprint import pformat
77
78
import tempfile
78
79
from typing import Any , List
79
80
@@ -118,6 +119,20 @@ def __init__(self):
118
119
)
119
120
120
121
122
+ def dict_to_str (dict : dict ) -> str :
123
+ """Converts the dict to string while hiding the 'environment' argument from the dictionary,
124
+ if the environment variable 'PYFLUENT_HIDE_LOG_SECRETS' is '1'.
125
+ This is useful for logging purposes, to avoid printing sensitive information such as license server details.
126
+ """
127
+
128
+ if "environment" in dict and os .getenv ("PYFLUENT_HIDE_LOG_SECRETS" ) == "1" :
129
+ modified_dict = dict .copy ()
130
+ modified_dict .pop ("environment" )
131
+ return pformat (modified_dict )
132
+ else :
133
+ return pformat (dict )
134
+
135
+
121
136
@all_deprecators (
122
137
deprecate_arg_mappings = [
123
138
{
@@ -158,9 +173,12 @@ def configure_container_dict(
158
173
args : List[str]
159
174
List of Fluent launch arguments.
160
175
mount_source : str | Path, optional
161
- Existing path in the host operating system that will be mounted to ``mount_target``.
176
+ Path on the host system to mount into the container. This directory will serve as the working directory
177
+ for the Fluent process inside the container. If not specified, PyFluent's current working directory will
178
+ be used.
162
179
mount_target : str | Path, optional
163
- Path inside the container where ``mount_source`` will be mounted to.
180
+ Path inside the container where ``mount_source`` will be mounted. This will be the working directory path
181
+ visible to the Fluent process running inside the container.
164
182
timeout : int, optional
165
183
Time limit for the Fluent container to start, in seconds. By default, 30 seconds.
166
184
port : int, optional
@@ -213,71 +231,85 @@ def configure_container_dict(
213
231
See also :func:`start_fluent_container`.
214
232
"""
215
233
216
- if (
217
- container_dict
218
- and "environment" in container_dict
219
- and os .getenv ("PYFLUENT_HIDE_LOG_SECRETS" ) == "1"
220
- ):
221
- container_dict_h = container_dict .copy ()
222
- container_dict_h .pop ("environment" )
223
- logger .debug (f"container_dict before processing: { container_dict_h } " )
224
- del container_dict_h
225
- else :
226
- logger .debug (f"container_dict before processing: { container_dict } " )
234
+ logger .debug (f"container_dict before processing:\n { dict_to_str (container_dict )} " )
235
+
236
+ # Starting with 'mount_source' because it is not tied to the 'working_dir'.
237
+ # The intended 'mount_source' logic is as follows, if it is not directly specified:
238
+ # 1. If 'file_transfer_service' is provided, use its 'mount_source'.
239
+ # 2. Try to use the environment variable 'PYFLUENT_CONTAINER_MOUNT_SOURCE', if it is set.
240
+ # 3. Use the value from 'pyfluent.CONTAINER_MOUNT_SOURCE', if it is set.
241
+ # 4. If 'volumes' is specified in 'container_dict', try to infer the value from it.
242
+ # 5. Finally, use the current working directory, which is always available.
227
243
228
244
if not mount_source :
229
245
if file_transfer_service :
230
246
mount_source = file_transfer_service .mount_source
231
247
else :
232
248
mount_source = os .getenv (
233
249
"PYFLUENT_CONTAINER_MOUNT_SOURCE" ,
234
- pyfluent .CONTAINER_MOUNT_SOURCE or os . getcwd () ,
250
+ pyfluent .CONTAINER_MOUNT_SOURCE ,
235
251
)
236
252
237
- elif "volumes" in container_dict :
238
- logger .warning (
239
- "'volumes' keyword specified in 'container_dict', but "
240
- "it is going to be overwritten by specified 'mount_source'."
241
- )
242
- container_dict .pop ("volumes" )
253
+ if "volumes" in container_dict :
254
+ if len (container_dict ["volumes" ]) != 1 :
255
+ logger .warning (
256
+ "Multiple volumes being mounted in the Docker container, "
257
+ "Assuming the first mount is the working directory for Fluent."
258
+ )
259
+ volumes_string = container_dict ["volumes" ][0 ]
260
+ if mount_source :
261
+ logger .warning (
262
+ "'volumes' keyword specified in 'container_dict', but "
263
+ "it is going to be overwritten by specified 'mount_source'."
264
+ )
265
+ else :
266
+ mount_source = volumes_string .split (":" )[0 ]
267
+ logger .debug (f"mount_source: { mount_source } " )
268
+ inferred_mount_target = volumes_string .split (":" )[1 ]
269
+ logger .debug (f"inferred_mount_target: { inferred_mount_target } " )
270
+
271
+ if not mount_source :
272
+ logger .debug ("No container 'mount_source' specified, using default value." )
273
+ mount_source = os .getcwd ()
243
274
244
- if not os .path .exists (mount_source ):
245
- os .makedirs (mount_source )
275
+ # The intended 'mount_target' logic is as follows, if it is not directly specified:
276
+ # 1. If 'working_dir' is specified in 'container_dict', use it as 'mount_target'.
277
+ # 2. Use the environment variable 'PYFLUENT_CONTAINER_MOUNT_TARGET', if it is set.
278
+ # 3. Try to infer the value from the 'volumes' keyword in 'container_dict', if available.
279
+ # 4. Finally, use the value from 'pyfluent.CONTAINER_MOUNT_TARGET', which is always set.
246
280
247
281
if not mount_target :
248
- mount_target = os .getenv (
249
- "PYFLUENT_CONTAINER_MOUNT_TARGET" , pyfluent .CONTAINER_MOUNT_TARGET
250
- )
251
- elif "volumes" in container_dict :
252
- logger .warning (
253
- "'volumes' keyword specified in 'container_dict', but "
254
- "it is going to be overwritten by specified 'mount_target'."
255
- )
256
- container_dict .pop ("volumes" )
282
+ if "working_dir" in container_dict :
283
+ mount_target = container_dict ["working_dir" ]
284
+ else :
285
+ mount_target = os .getenv ("PYFLUENT_CONTAINER_MOUNT_TARGET" )
286
+
287
+ if "working_dir" in container_dict and mount_target :
288
+ # working_dir will be set later to the final value of mount_target
289
+ container_dict .pop ("working_dir" )
290
+
291
+ if not mount_target and "volumes" in container_dict :
292
+ mount_target = inferred_mount_target
293
+
294
+ if not mount_target :
295
+ logger .debug ("No container 'mount_target' specified, using default value." )
296
+ mount_target = pyfluent .CONTAINER_MOUNT_TARGET
257
297
258
298
if "volumes" not in container_dict :
259
299
container_dict .update (volumes = [f"{ mount_source } :{ mount_target } " ])
260
300
else :
261
- logger .debug (f"container_dict['volumes']: { container_dict ['volumes' ]} " )
262
- if len (container_dict ["volumes" ]) != 1 :
263
- logger .warning (
264
- "Multiple volumes being mounted in the Docker container, "
265
- "using the first mount as the working directory for Fluent."
266
- )
267
- volumes_string = container_dict ["volumes" ][0 ]
268
- mount_target = ""
269
- for c in reversed (volumes_string ):
270
- if c == ":" :
271
- break
272
- else :
273
- mount_target += c
274
- mount_target = mount_target [::- 1 ]
275
- mount_source = volumes_string .replace (":" + mount_target , "" )
276
- logger .debug (f"mount_source: { mount_source } " )
277
- logger .debug (f"mount_target: { mount_target } " )
301
+ container_dict ["volumes" ][0 ] = f"{ mount_source } :{ mount_target } "
302
+
278
303
logger .warning (
279
- f"Starting Fluent container mounted to { mount_source } , with this path available as { mount_target } for the Fluent session running inside the container."
304
+ f"Configuring Fluent container to mount to { mount_source } , "
305
+ f"with this path available as { mount_target } for the Fluent session running inside the container."
280
306
)
307
+
308
+ if "working_dir" not in container_dict :
309
+ container_dict .update (
310
+ working_dir = mount_target ,
311
+ )
312
+
281
313
port_mapping = {port : port } if port else {}
282
314
if not port_mapping and "ports" in container_dict :
283
315
# take the specified 'port', OR the first port value from the specified 'ports', for Fluent to use
@@ -315,11 +347,7 @@ def configure_container_dict(
315
347
labels = {"test_name" : test_name },
316
348
)
317
349
318
- if "working_dir" not in container_dict :
319
- container_dict .update (
320
- working_dir = mount_target ,
321
- )
322
-
350
+ # Find the server info file name from the command line arguments
323
351
if "command" in container_dict :
324
352
for v in container_dict ["command" ]:
325
353
if v .startswith ("-sifile=" ):
@@ -343,6 +371,20 @@ def configure_container_dict(
343
371
os .close (fd )
344
372
container_server_info_file = PurePosixPath (mount_target ) / Path (sifile ).name
345
373
374
+ logger .debug (
375
+ f"Using server info file '{ container_server_info_file } ' for Fluent container."
376
+ )
377
+
378
+ # If the 'command' had already been specified in the 'container_dict',
379
+ # maintain other 'command' arguments but update the '-sifile' argument,
380
+ # as the 'mount_target' or 'working_dir' may have changed.
381
+ if "command" in container_dict :
382
+ for i , item in enumerate (container_dict ["command" ]):
383
+ if item .startswith ("-sifile=" ):
384
+ container_dict ["command" ][i ] = f"-sifile={ container_server_info_file } "
385
+ else :
386
+ container_dict ["command" ] = args + [f"-sifile={ container_server_info_file } " ]
387
+
346
388
if not fluent_image :
347
389
if not image_tag :
348
390
image_tag = os .getenv (
@@ -384,16 +426,13 @@ def configure_container_dict(
384
426
container_dict ["environment" ] = {}
385
427
container_dict ["environment" ]["FLUENT_LAUNCHED_FROM_PYFLUENT" ] = "1"
386
428
387
- fluent_commands = [f"-sifile={ container_server_info_file } " ] + args
388
-
389
- container_dict_default = {}
390
- container_dict_default .update (
391
- command = fluent_commands ,
429
+ container_dict_base = {}
430
+ container_dict_base .update (
392
431
detach = True ,
393
432
auto_remove = True ,
394
433
)
395
434
396
- for k , v in container_dict_default .items ():
435
+ for k , v in container_dict_base .items ():
397
436
if k not in container_dict :
398
437
container_dict [k ] = v
399
438
@@ -404,6 +443,13 @@ def configure_container_dict(
404
443
container_dict ["mount_source" ] = mount_source
405
444
container_dict ["mount_target" ] = mount_target
406
445
446
+ logger .debug (
447
+ f"Fluent container timeout: { timeout } , container_grpc_port: { container_grpc_port } , "
448
+ f"host_server_info_file: '{ host_server_info_file } ', "
449
+ f"remove_server_info_file: { remove_server_info_file } "
450
+ )
451
+ logger .debug (f"container_dict after processing:\n { dict_to_str (container_dict )} " )
452
+
407
453
return (
408
454
container_dict ,
409
455
timeout ,
@@ -458,21 +504,6 @@ def start_fluent_container(
458
504
remove_server_info_file ,
459
505
) = container_vars
460
506
461
- if os .getenv ("PYFLUENT_HIDE_LOG_SECRETS" ) != "1" :
462
- logger .debug (f"container_vars: { container_vars } " )
463
- else :
464
- config_dict_h = config_dict .copy ()
465
- config_dict_h .pop ("environment" )
466
- container_vars_tmp = (
467
- config_dict_h ,
468
- timeout ,
469
- port ,
470
- host_server_info_file ,
471
- remove_server_info_file ,
472
- )
473
- logger .debug (f"container_vars: { container_vars_tmp } " )
474
- del container_vars_tmp
475
-
476
507
try :
477
508
if is_compose ():
478
509
config_dict ["fluent_port" ] = port
0 commit comments