22import logging
33import os
44
5+ from tests .common .devices .base import AnsibleHostBase
6+ import re
57
6- class AosHost ():
8+ def _raise_err (msg ):
9+ raise Exception (msg )
10+
11+ class AosHost (AnsibleHostBase ):
712 """
813 @summary: Class for Accton switch
914 For running ansible module on the Accton switch
1015 """
1116
1217 def __init__ (self , ansible_adhoc , hostname , user , passwd , gather_facts = False ):
18+ AnsibleHostBase .__init__ (self , ansible_adhoc , hostname )
1319 self .hostname = hostname
14- self .user = user
15- self .passwd = passwd
1620 self .localhost = ansible_adhoc (inventory = 'localhost' , connection = 'local' , host_pattern = "localhost" )["localhost" ]
1721
22+ self .admin_conn_props = {
23+ 'ansible_connection' : 'network_cli' ,
24+ 'ansible_network_os' :'aos' ,
25+ 'ansible_become_method' : 'enable' ,
26+ 'ansible_user' : user ,
27+ 'ansible_password' : passwd
28+ }
29+
1830 def _exec_jinja_template (self , task_name , jinja_template ):
1931 inventory = 'lab'
2032 ansible_root = '../ansible/'
@@ -97,3 +109,86 @@ def exec_template(self, ansible_root, ansible_playbook, inventory, **kwargs):
97109
98110 if res ["localhost" ]["rc" ] != 0 :
99111 raise Exception ("Unable to execute template\n {}" .format (res ["localhost" ]["stdout" ]))
112+
113+ # delegate AOS related commands to Ansible
114+ def __getattr__ (self , module_name ):
115+ if not module_name .startswith ('aos_' ):
116+ return None
117+ self .host .options ['variable_manager' ].extra_vars .update (self .admin_conn_props )
118+ return super (AosHost , self ).__getattr__ (module_name )
119+
120+ def _has_cli_cmd_failed (self , cmd_output_obj ):
121+ return 'failed' in cmd_output_obj and cmd_output_obj ['failed' ]
122+
123+ def cli_command (self , cmd ):
124+ return self .aos_command (commands = [cmd ])['stdout' ][0 ]
125+
126+ def get_auto_negotiation_mode (self , port ):
127+ return self .get_speed (port ) == 'Auto'
128+
129+ def set_auto_negotiation_mode (self , port , enabled ):
130+ if self .get_auto_negotiation_mode (port ) == enabled :
131+ return True
132+ if enabled :
133+ out = self .aos_config (
134+ lines = ['negotiation' ],
135+ parents = ['interface {}' .format (port )])
136+ else :
137+ out = self .aos_config (
138+ lines = ['no negotiation' ],
139+ parents = ['interface {}' .format (port )])
140+ return not self ._has_cli_cmd_failed (out )
141+
142+ def get_speed (self , port ):
143+ output = self .cli_command ('show interfaces status {}' .format (port ))
144+
145+ found_txt = extract_val ('Speed-duplex' , output )
146+ if found_txt is None :
147+ _raise_err ('Not able to extract interface %s speed from output: %s' % (port , output ))
148+
149+ return speed_gb_to_mb (found_txt )
150+
151+ def get_supported_speeds (self , port ):
152+ """Get supported speeds for a given interface
153+
154+ Args:
155+ interface_name (str): Interface name
156+
157+ Returns:
158+ list: A list of supported speed strings or None
159+ """
160+ output = self .cli_command ('show interfaces status {}' .format (port ))
161+ found_txt = extract_val ('Capabilities' , output )
162+
163+ if found_txt is None :
164+ _raise_err ('Failed to find port speeds list in output: %s' % output )
165+
166+ speed_list = found_txt .split (',' )
167+ return list (map (speed_gb_to_mb , speed_list ))
168+
169+ def set_speed (self , interface_name , speed ):
170+
171+ if not speed :
172+ # other set_speed implementations advertise port speeds when speed=None
173+ # but in AOS autoneg activation and speeds advertisement is done via a single CLI cmd
174+ # so this branch left nop intentionally
175+ return True
176+ speed = speed_mb_to_gb (speed )
177+ out = self .aos_config (
178+ lines = ['speed {}' .format (speed )],
179+ parents = 'interface %s' % interface_name )
180+ return not self ._has_cli_cmd_failed (out )
181+
182+ def speed_gb_to_mb (speed ):
183+ res = re .search (r'(\d+)(\w)' , speed )
184+ if not res :
185+ return speed
186+ speed = res .groups ()[0 ]
187+ return speed + '000'
188+
189+ def speed_mb_to_gb (val ):
190+ return '{}Gfull' .format (int (val ) // 1000 )
191+
192+ def extract_val (prop_name , output ):
193+ found_txt = re .search (r'{}\s+:\s+(.+)' .format (prop_name ), output )
194+ return found_txt .groups ()[0 ] if found_txt else None
0 commit comments