Skip to content
3 changes: 3 additions & 0 deletions changelogs/fragments/559-aaa-accounting-support.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- sonic_aaa - Add Accounting support for AAA module (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/559).
35 changes: 35 additions & 0 deletions plugins/module_utils/network/sonic/argspec/aaa/aaa.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,41 @@ def __init__(self, **kwargs):
},
'type': 'dict'
},
'accounting': {
'options': {
'commands_accounting': {
'options': {
'accounting_method': {
'choices': ['tacacs+', 'logging'],
'elements': 'str',
'type': 'list'
},
'accounting_record_type': {
'choices': ['START_STOP', 'STOP_ONLY'],
'type': 'str'
},
'accounting_console_exempt': {'type': 'bool'}
},
'type': 'dict'
},
'session_accounting': {
'options': {
'accounting_method': {
'choices': ['tacacs+', 'logging'],
'elements': 'str',
'type': 'list'
},
'accounting_record_type': {
'choices': ['START_STOP', 'STOP_ONLY'],
'type': 'str'
},
'accounting_console_exempt': {'type': 'bool'}
},
'type': 'dict'
}
},
'type': 'dict'
},
'name_service': {
'options': {
'group': {
Expand Down
106 changes: 106 additions & 0 deletions plugins/module_utils/network/sonic/config/aaa/aaa.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@

AAA_AUTHENTICATION_PATH = '/data/openconfig-system:system/aaa/authentication/config'
AAA_AUTHORIZATION_PATH = '/data/openconfig-system:system/aaa/authorization'
AAA_COMMANDS_ACCOUNTING_PATH = '/data/openconfig-system:system/aaa/accounting/openconfig-system-ext:commands/config'
AAA_SESSION_ACCOUNTING_PATH = '/data/openconfig-system:system/aaa/accounting/openconfig-system-ext:session/config'
AA_AUTHORIZATION_PATH = '/data/openconfig-system:system/aaa/authorization'
AAA_NAME_SERVICE_PATH = '/data/openconfig-system:system/aaa/openconfig-aaa-ext:name-service/config'
PATCH = 'patch'
DELETE = 'delete'
Expand Down Expand Up @@ -290,6 +293,29 @@ def get_modify_aaa_requests(self, commands):
payload = {'openconfig-system:config': authentication_cfg_dict}
requests.append({'path': AAA_AUTHENTICATION_PATH, 'method': PATCH, 'data': payload})

# Accounting modification handling
accounting = commands.get('accounting')
if accounting:
for acct_key, path in [
('commands_accounting', AAA_COMMANDS_ACCOUNTING_PATH),
('session_accounting', AAA_SESSION_ACCOUNTING_PATH)
]:
acct_data = accounting.get(acct_key)
if acct_data:
accounting_cfg_dict = {}
accounting_method = acct_data.get('accounting_method')
accounting_record_type = acct_data.get('accounting_record_type')
accounting_console_exempt = acct_data.get('accounting_console_exempt')
if accounting_method:
accounting_cfg_dict['accounting-method'] = accounting_method
if accounting_record_type:
accounting_cfg_dict['accounting-record-type'] = accounting_record_type
if accounting_console_exempt is not None:
accounting_cfg_dict['accounting-console-exempt'] = accounting_console_exempt
if accounting_cfg_dict:
payload = {'openconfig-system-ext:config': accounting_cfg_dict}
requests.append({'path': path, 'method': PATCH, 'data': payload})

# Authorization modification handling
authorization = commands.get('authorization')
if authorization:
Expand Down Expand Up @@ -341,6 +367,8 @@ def get_delete_aaa_requests(self, commands, is_delete_all):
requests.append(self.get_delete_request(AAA_AUTHENTICATION_PATH, None))
requests.append(self.get_delete_request(AAA_AUTHORIZATION_PATH, None))
requests.append(self.get_delete_request(AAA_NAME_SERVICE_PATH, None))
requests.append(self.get_delete_request(AAA_COMMANDS_ACCOUNTING_PATH, None))
requests.append(self.get_delete_request(AAA_SESSION_ACCOUNTING_PATH, None))
return requests

# Authentication deletion handling
Expand All @@ -365,6 +393,23 @@ def get_delete_aaa_requests(self, commands, is_delete_all):
if login_mfa_console is not None:
requests.append(self.get_delete_request(AAA_AUTHENTICATION_PATH, 'openconfig-mfa:login-mfa-console'))

# Accounting deletion handling
accounting = commands.get('accounting')
if accounting:
for acct_key, path in [
('commands_accounting', AAA_COMMANDS_ACCOUNTING_PATH),
('session_accounting', AAA_SESSION_ACCOUNTING_PATH)
]:
acct_data = accounting.get(acct_key)
if acct_data:
if acct_data.get('accounting_method'):
requests.append(self.get_delete_request(path, 'accounting-method'))
if acct_data.get('accounting_record_type'):
requests.append(self.get_delete_request(path, 'accounting-record-type'))
# Default is false
if acct_data.get('accounting_console_exempt'):
requests.append(self.get_delete_request(path, 'accounting-console-exempt'))

# Authorization deletion handling
authorization = commands.get('authorization')
if authorization:
Expand Down Expand Up @@ -446,6 +491,39 @@ def get_diff_aaa(self, base_cfg, compare_cfg):
else:
cfg_dict['authentication'] = authentication

# Accounting diff handling
accounting = base_cfg.get('accounting')
if accounting:
accounting_dict = {}
for acct_type in ['commands_accounting', 'session_accounting']:
acct = accounting.get(acct_type)
if acct:
accounting_method = acct.get('accounting_method')
accounting_record_type = acct.get('accounting_record_type')
accounting_console_exempt = acct.get('accounting_console_exempt')
compare_accounting = compare_cfg.get('accounting')
if compare_accounting:
compare_acct = compare_accounting.get(acct_type)
if compare_acct:
acct_dict = {}
compare_accounting_method = compare_acct.get('accounting_method')
compare_accounting_record_type = compare_acct.get('accounting_record_type')
compare_accounting_console_exempt = compare_acct.get('accounting_console_exempt')
if accounting_method and accounting_method != compare_accounting_method:
acct_dict['accounting_method'] = accounting_method
if accounting_record_type and accounting_record_type != compare_accounting_record_type:
acct_dict['accounting_record_type'] = accounting_record_type
if accounting_console_exempt is not None and accounting_console_exempt != compare_accounting_console_exempt:
acct_dict['accounting_console_exempt'] = accounting_console_exempt
if acct_dict:
accounting_dict[acct_type] = acct_dict
else:
accounting_dict[acct_type] = acct
else:
accounting_dict[acct_type] = acct
if accounting_dict:
cfg_dict['accounting'] = accounting_dict

# Authorization diff handling
authorization = base_cfg.get('authorization')
if authorization:
Expand Down Expand Up @@ -507,15 +585,19 @@ def get_replaced_config(self, want, have):
self.remove_default_entries(have)
authentication = want.get('authentication')
authorization = want.get('authorization')
accounting = want.get('accounting')
name_service = want.get('name_service')
cfg_authentication = have.get('authentication')
cfg_authorization = have.get('authorization')
cfg_accounting = have.get('accounting')
cfg_name_service = have.get('name_service')

if authentication and cfg_authentication and authentication != cfg_authentication:
config_dict['authentication'] = cfg_authentication
if authorization and cfg_authorization and authorization != cfg_authorization:
config_dict['authorization'] = cfg_authorization
if accounting and cfg_accounting and accounting != cfg_accounting:
config_dict['accounting'] = cfg_accounting
if name_service and cfg_name_service and name_service != cfg_name_service:
config_dict['name_service'] = cfg_name_service

Expand All @@ -525,6 +607,7 @@ def post_process_generated_config(self, data):
if data:
authentication = data.get('authentication')
authorization = data.get('authorization')
accounting = data.get('accounting')
name_service = data.get('name_service')

if authentication:
Expand All @@ -543,6 +626,19 @@ def post_process_generated_config(self, data):
data['authorization'].pop('login_auth_method')
if not data['authorization']:
data.pop('authorization')
if accounting:
default_entries = {'accounting_console_exempt': False}
for acct_key in ['commands_accounting', 'session_accounting']:
acct_data = accounting.get(acct_key)
if acct_data:
if 'accounting_method' in acct_data and not acct_data['accounting_method']:
acct_data.pop('accounting_method')
for option, value in default_entries.items():
acct_data.setdefault(option, value)
if acct_data == default_entries:
accounting.pop(acct_key)
if not accounting:
data.pop('accounting')
if name_service:
for method in ('group', 'netgroup', 'passwd', 'shadow', 'sudoers'):
if method in name_service and not name_service[method]:
Expand All @@ -560,3 +656,13 @@ def remove_default_entries(self, data):
authentication.pop('login_mfa_console')
if not authentication:
data.pop('authentication')
accounting = data.get('accounting')
if accounting:
for acct_key in ['commands_accounting', 'session_accounting']:
acct_data = accounting.get(acct_key)
if acct_data and acct_data.get('accounting_console_exempt') is False:
acct_data.pop('accounting_console_exempt')
if not acct_data:
accounting.pop(acct_key)
if not accounting:
data.pop('accounting')
37 changes: 37 additions & 0 deletions plugins/module_utils/network/sonic/facts/aaa/aaa.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,43 @@ def update_aaa(self, module):
if authorization_dict:
config_dict['authorization'] = authorization_dict

# Accounting configuration handling
accounting_dict = {}
commands_acct_cfg = self.get_config(module, 'accounting/openconfig-system-ext:commands/config', 'openconfig-system-ext:config')
if commands_acct_cfg:
commands_acct_dict = {}
accounting_method = commands_acct_cfg.get('accounting-method')
accounting_record_type = commands_acct_cfg.get('accounting-record-type')
accounting_console_exempt = commands_acct_cfg.get('accounting-console-exempt')

if accounting_method:
commands_acct_dict['accounting_method'] = accounting_method
if accounting_record_type:
commands_acct_dict['accounting_record_type'] = accounting_record_type
if accounting_console_exempt is not None:
commands_acct_dict['accounting_console_exempt'] = accounting_console_exempt
if commands_acct_dict:
accounting_dict['commands_accounting'] = commands_acct_dict

session_acct_cfg = self.get_config(module, 'accounting/openconfig-system-ext:session/config', 'openconfig-system-ext:config')
if session_acct_cfg:
session_acct_dict = {}
accounting_method = session_acct_cfg.get('accounting-method')
accounting_record_type = session_acct_cfg.get('accounting-record-type')
accounting_console_exempt = session_acct_cfg.get('accounting-console-exempt')

if accounting_method:
session_acct_dict['accounting_method'] = accounting_method
if accounting_record_type:
session_acct_dict['accounting_record_type'] = accounting_record_type
if accounting_console_exempt is not None:
session_acct_dict['accounting_console_exempt'] = accounting_console_exempt
if session_acct_dict:
accounting_dict['session_accounting'] = session_acct_dict

if accounting_dict:
config_dict['accounting'] = accounting_dict

# Name-service configuration handling
name_service_cfg = self.get_config(module, 'openconfig-aaa-ext:name-service/config', 'openconfig-aaa-ext:config')
if name_service_cfg:
Expand Down
Loading