@@ -394,6 +394,10 @@ class HostConfigDaemon:
394
394
self .config_db .connect (wait_for_init = True , retry_on = True )
395
395
syslog .syslog (syslog .LOG_INFO , 'ConfigDB connect success' )
396
396
397
+ # Load DEVICE metadata configurations
398
+ self .device_config = {}
399
+ self .device_config ['DEVICE_METADATA' ] = self .config_db .get_table ('DEVICE_METADATA' )
400
+
397
401
self .aaacfg = AaaCfg ()
398
402
self .iptables = Iptables ()
399
403
self .ntpcfg = NtpCfg (self .config_db )
@@ -421,75 +425,106 @@ class HostConfigDaemon:
421
425
ntp_global = self .config_db .get_table ('NTP' )
422
426
self .ntpcfg .load (ntp_global , ntp_server )
423
427
424
- def update_feature_state (self , feature_name , state , feature_table ):
425
- if self .cached_feature_states [feature_name ] == "always_enabled" :
426
- if state != "always_enabled" :
427
- syslog .syslog (syslog .LOG_INFO , "Feature '{}' service is always enabled"
428
- .format (feature_name ))
429
- entry = self .config_db .get_entry ('FEATURE' , feature_name )
430
- entry ['state' ] = 'always_enabled'
431
- self .config_db .set_entry ('FEATURE' , feature_name , entry )
432
- return
428
+ def get_target_state (self , feature_name , state ):
429
+ template = jinja2 .Template (state )
430
+ target_state = template .render (self .device_config )
431
+ entry = self .config_db .get_entry ('FEATURE' , feature_name )
432
+ entry ["state" ] = target_state
433
+ self .config_db .set_entry ("FEATURE" , feature_name , entry )
433
434
434
- self . cached_feature_states [ feature_name ] = state
435
+ return target_state
435
436
437
+ def get_feature_attribute (self , feature_name , feature_table ):
436
438
has_timer = ast .literal_eval (feature_table [feature_name ].get ('has_timer' , 'False' ))
437
439
has_global_scope = ast .literal_eval (feature_table [feature_name ].get ('has_global_scope' , 'True' ))
438
440
has_per_asic_scope = ast .literal_eval (feature_table [feature_name ].get ('has_per_asic_scope' , 'False' ))
439
441
440
442
# Create feature name suffix depending feature is running in host or namespace or in both
441
- feature_name_suffix_list = (([feature_name ] if has_global_scope or not self .is_multi_npu else []) +
442
- ([(feature_name + '@' + str (asic_inst )) for asic_inst in range (device_info .get_num_npus ())
443
- if has_per_asic_scope and self .is_multi_npu ]))
443
+ feature_names = (
444
+ ([feature_name ] if has_global_scope or not self .is_multi_npu else []) +
445
+ ([(feature_name + '@' + str (asic_inst )) for asic_inst in range (device_info .get_num_npus ())
446
+ if has_per_asic_scope and self .is_multi_npu ])
447
+ )
444
448
445
- if not feature_name_suffix_list :
449
+ if not feature_names :
446
450
syslog .syslog (syslog .LOG_ERR , "Feature '{}' service not available"
447
451
.format (feature_name ))
448
452
449
453
feature_suffixes = ["service" ] + (["timer" ] if has_timer else [])
450
454
451
- if state == "enabled" :
452
- start_cmds = []
453
- for feature_name_suffix in feature_name_suffix_list :
454
- for suffix in feature_suffixes :
455
- start_cmds .append ("sudo systemctl unmask {}.{}" .format (feature_name_suffix , suffix ))
456
- # If feature has timer associated with it, start/enable corresponding systemd .timer unit
457
- # otherwise, start/enable corresponding systemd .service unit
458
- start_cmds .append ("sudo systemctl enable {}.{}" .format (feature_name_suffix , feature_suffixes [- 1 ]))
459
- start_cmds .append ("sudo systemctl start {}.{}" .format (feature_name_suffix , feature_suffixes [- 1 ]))
460
- for cmd in start_cmds :
461
- syslog .syslog (syslog .LOG_INFO , "Running cmd: '{}'" .format (cmd ))
462
- try :
463
- subprocess .check_call (cmd , shell = True )
464
- except subprocess .CalledProcessError as err :
465
- syslog .syslog (syslog .LOG_ERR , "'{}' failed. RC: {}, output: {}"
466
- .format (err .cmd , err .returncode , err .output ))
467
- syslog .syslog (syslog .LOG_ERR , "Feature '{}.{}' failed to be enabled and started"
468
- .format (feature_name , feature_suffixes [- 1 ]))
469
- return
470
- syslog .syslog (syslog .LOG_INFO , "Feature '{}.{}' is enabled and started"
471
- .format (feature_name , feature_suffixes [- 1 ]))
472
- elif state == "disabled" :
473
- stop_cmds = []
474
- for feature_name_suffix in feature_name_suffix_list :
475
- for suffix in reversed (feature_suffixes ):
476
- stop_cmds .append ("sudo systemctl stop {}.{}" .format (feature_name_suffix , suffix ))
477
- stop_cmds .append ("sudo systemctl disable {}.{}" .format (feature_name_suffix , suffix ))
478
- stop_cmds .append ("sudo systemctl mask {}.{}" .format (feature_name_suffix , suffix ))
479
- for cmd in stop_cmds :
480
- syslog .syslog (syslog .LOG_INFO , "Running cmd: '{}'" .format (cmd ))
481
- try :
482
- subprocess .check_call (cmd , shell = True )
483
- except subprocess .CalledProcessError as err :
484
- syslog .syslog (syslog .LOG_ERR , "'{}' failed. RC: {}, output: {}"
485
- .format (err .cmd , err .returncode , err .output ))
486
- syslog .syslog (syslog .LOG_ERR , "Feature '{}' failed to be stopped and disabled" .format (feature_name ))
487
- return
488
- syslog .syslog (syslog .LOG_INFO , "Feature '{}' is stopped and disabled" .format (feature_name ))
489
- else :
490
- syslog .syslog (syslog .LOG_ERR , "Unexpected state value '{}' for feature '{}'"
491
- .format (state , feature_name ))
455
+ return feature_names , feature_suffixes
456
+
457
+ def enable_feature (self , feature_names , feature_suffixes ):
458
+ start_cmds = []
459
+ for feature_name in feature_names :
460
+ for suffix in feature_suffixes :
461
+ start_cmds .append ("sudo systemctl unmask {}.{}" .format (feature_name , suffix ))
462
+ # If feature has timer associated with it, start/enable corresponding systemd .timer unit
463
+ # otherwise, start/enable corresponding systemd .service unit
464
+ start_cmds .append ("sudo systemctl enable {}.{}" .format (feature_name , feature_suffixes [- 1 ]))
465
+ start_cmds .append ("sudo systemctl start {}.{}" .format (feature_name , feature_suffixes [- 1 ]))
466
+ for cmd in start_cmds :
467
+ syslog .syslog (syslog .LOG_INFO , "Running cmd: '{}'" .format (cmd ))
468
+ try :
469
+ subprocess .check_call (cmd , shell = True )
470
+ except subprocess .CalledProcessError as err :
471
+ syslog .syslog (syslog .LOG_ERR , "'{}' failed. RC: {}, output: {}"
472
+ .format (err .cmd , err .returncode , err .output ))
473
+ syslog .syslog (syslog .LOG_ERR , "Feature '{}.{}' failed to be enabled and started"
474
+ .format (feature_name , feature_suffixes [- 1 ]))
475
+ return
476
+
477
+ def disable_feature (self , feature_names , feature_suffixes ):
478
+ stop_cmds = []
479
+ for feature_name in feature_names :
480
+ for suffix in reversed (feature_suffixes ):
481
+ stop_cmds .append ("sudo systemctl stop {}.{}" .format (feature_name , suffix ))
482
+ stop_cmds .append ("sudo systemctl disable {}.{}" .format (feature_name , suffix ))
483
+ stop_cmds .append ("sudo systemctl mask {}.{}" .format (feature_name , suffix ))
484
+ for cmd in stop_cmds :
485
+ syslog .syslog (syslog .LOG_INFO , "Running cmd: '{}'" .format (cmd ))
486
+ try :
487
+ subprocess .check_call (cmd , shell = True )
488
+ except subprocess .CalledProcessError as err :
489
+ syslog .syslog (syslog .LOG_ERR , "'{}' failed. RC: {}, output: {}"
490
+ .format (err .cmd , err .returncode , err .output ))
491
+ syslog .syslog (syslog .LOG_ERR , "Feature '{}' failed to be stopped and disabled" .format (feature_name ))
492
+ return
493
+
494
+ def is_invariant_feature (self , feature_name , state , feature_table ):
495
+ invariant_feature = self .cached_feature_states [feature_name ] == "always_enabled" or \
496
+ self .cached_feature_states [feature_name ] == "always_disabled"
497
+ if invariant_feature :
498
+ invariant_state = self .cached_feature_states [feature_name ]
499
+ if state != invariant_state :
500
+ syslog .syslog (syslog .LOG_INFO , "Feature '{}' service is '{}'"
501
+ .format (feature_name , invariant_state ))
502
+ entry = self .config_db .get_entry ('FEATURE' , feature_name )
503
+ entry ['state' ] = invariant_state
504
+ self .config_db .set_entry ('FEATURE' , feature_name , entry )
492
505
506
+ if state == "always_disabled" :
507
+ feature_names , feature_suffixes = self .get_feature_attribute (feature_name , feature_table )
508
+ self .disable_feature (feature_names , feature_suffixes )
509
+ syslog .syslog (syslog .LOG_INFO , "Feature '{}' is stopped and disabled" .format (feature_name ))
510
+
511
+ return invariant_feature
512
+
513
+ def update_feature_state (self , feature_name , state , feature_table ):
514
+ if not self .is_invariant_feature (feature_name , state , feature_table ):
515
+ self .cached_feature_states [feature_name ] = state
516
+
517
+ feature_names , feature_suffixes = self .get_feature_attribute (feature_name , feature_table )
518
+ if state == "enabled" :
519
+ self .enable_feature (feature_names , feature_suffixes )
520
+ syslog .syslog (syslog .LOG_INFO , "Feature '{}.{}' is enabled and started"
521
+ .format (feature_name , feature_suffixes [- 1 ]))
522
+ elif state == "disabled" :
523
+ self .disable_feature (feature_names , feature_suffixes )
524
+ syslog .syslog (syslog .LOG_INFO , "Feature '{}' is stopped and disabled" .format (feature_name ))
525
+ else :
526
+ syslog .syslog (syslog .LOG_ERR , "Unexpected state value '{}' for feature '{}'"
527
+ .format (state , feature_name ))
493
528
494
529
def update_all_feature_states (self ):
495
530
feature_table = self .config_db .get_table ('FEATURE' )
@@ -500,13 +535,14 @@ class HostConfigDaemon:
500
535
501
536
state = feature_table [feature_name ]['state' ]
502
537
if not state :
503
- syslog .syslog (syslog .LOG_WARNING , "Eanble state of feature '{}' is None" .format (feature_name ))
538
+ syslog .syslog (syslog .LOG_WARNING , "Enable state of feature '{}' is None" .format (feature_name ))
504
539
continue
505
540
541
+ target_state = self .get_target_state (feature_name , state )
506
542
# Store the initial value of 'state' field in 'FEATURE' table of a specific container
507
- self .cached_feature_states [feature_name ] = state
543
+ self .cached_feature_states [feature_name ] = target_state
508
544
509
- self .update_feature_state (feature_name , state , feature_table )
545
+ self .update_feature_state (feature_name , target_state , feature_table )
510
546
511
547
def aaa_handler (self , key , data ):
512
548
self .aaacfg .aaa_update (key , data )
0 commit comments