PyEZ - 即使超时值设置为较高值,成功提交后也会出现 RpcTimeoutError

问题描述 投票:0回答:1

我有一个使用 PyEZ 库的 Python (3.10) 脚本来连接到 Junos 设备并提交各种显示设置命令。尽管这两个步骤都成功,但在提交候选配置后,无论我为 Device 类和 Config 类的 commit() 方法设置什么超时值,我都会收到 RpcTimeoutError 。我只是不明白为什么会发生这种情况。提交在 5 分钟结束之前完成,因此 commit_config() 方法应返回 True。

我提交的显示设置命令:

delete interfaces ge-0/0/0 unit 500
delete class-of-service interfaces ge-0/0/0 unit 500
delete routing-options rib inet6.0 static route <ipv6 route>,

错误:

Error: RpcTimeoutError(host: hostname, cmd: commit-configuration, timeout: 360)

相关代码如下:

DEVICE_TIMEOUT = 360 # RPC timeout value in seconds
DEVICE_AUTOPROBE = 15


class JunosDeviceConfigurator:
    def __init__(self, user=NETCONF_USER, password=NETCONF_PASSWD) -> None:
        self.user = user
        self.password = password
        self.device = None
        Device.auto_probe = DEVICE_AUTOPROBE
        Device.timeout = DEVICE_TIMEOUT

    def connect(self) -> bool:
        try:
            self.device = Device(
                host=self._hostname, 
                user=self.user, 
                passwd=self.password, 
                port=22, huge_tree=True, 
                gather_facts=True,
                timeout=DEVICE_TIMEOUT)
            self.device.open()
            self.device.timeout = DEVICE_TIMEOUT
            self.logger.info(f'Connected to {self._hostname}')
            return True
        except ConnectRefusedError as err:
            self.logger.error(f'Connection refused to {self._hostname}: {str(err)}')
            return False
        except ConnectError as err:
            self.logger.error(f'Connection to {self._hostname} failed: {str(err)}')
            return False
        except Exception as err:
            self.logger.error(f'Error connecting to {self._hostname}: {str(err)}')
            return False

    def commit_config(self, commands: list, mode = 'exclusive'):
        if not self.device:
            self.connect()

        try:
            with Config(self.device, mode=mode) as cu:
                for command in commands:
                    cu.load(command, format='set')
          
                cu.commit(timeout=DEVICE_TIMEOUT)
            
                return True
        except Exception as e:
             self.logger.error(f'Error: {str(e)}')
    
        return False
python pyez
1个回答
0
投票

我创建了一个解决方法来处理“假”RPC 超时。该方法检查候选配置,如果 cu.diff() 的输出为 None,则该方法返回 True,否则存在 real RPC 超时,重试两次后将返回 False。这是最终的代码:

def commit_config(self, commands: list, mode='exclusive', max_retries=2) -> bool:
    """
    Commits configuration changes to a Juniper device using PyEZ.

    Args:
        commands (list): List of Junos OS configuration commands to be committed.
        mode (str, optional): The configuration mode to use ('exclusive' by default).
        max_retries (int, optional): Maximum number of retries in case of LockError or RpcTimeoutError.

    Returns:
        bool: True if the commit was successful, False otherwise.
    """
    if not self.device:
        self.connect()

    for _ in range(max_retries + 1):
        try:
            with Config(self.device, mode=mode) as cu:
                for command in commands:
                    cu.load(command, format='set')
                
                self.logger.info(f'Trying to commit candidate configuration on {self._hostname}.')
                cu.commit(timeout=DEVICE_TIMEOUT)
                
                return True
        except RpcTimeoutError as e:
            if cu.diff() is not None:
                self.logger.warning(f'RpcTimeoutError: {e}. Retrying in {RETRY_DELAY} seconds..')
                time.sleep(RETRY_DELAY)
            else:
                return True # Workaround: return True if the commit was successful despite RpcTimeoutError
        except LockError as e:
            self.logger.warning(f'LockError: {e}. Retrying in {RETRY_DELAY} seconds..')
            time.sleep(RETRY_DELAY)
        except ConfigLoadError as e:
            self.logger.warning(f'ConfigLoadError: {e}. Retrying in {RETRY_DELAY} seconds..')
            time.sleep(RETRY_DELAY)
        except CommitError as e:
            self.logger.error(e)
        except Exception as e:
            self.logger.error(f'Error: {str(e)}')
    
    return False

任何改进此代码的建议总是受欢迎的,但这个“修复”将在短期内帮助我..

© www.soinside.com 2019 - 2024. All rights reserved.