netmiko模块

 

# 临时指定一下国内源
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple netmiko
# 升级(如果之前已经装了老版本)
pip3 install netmiko -U

 

#!/bin/python
# -*- coding:UTF-8 -*-
# pip install netmiko
from netmiko import ConnectHandler, SSHDetect
from netmiko.exceptions import NetMikoAuthenticationException, NetMikoTimeoutException
import threading
import datetime
import queue
import re, os
import logging

logging.basicConfig(filename='test.log', level=logging.DEBUG)
logger = logging.getLogger("netmiko")


def conn_info(ip):
    dev = {
        # 'device_type': 'huawei_serial',  # 指定设备类型,串口方式登陆,默认连接COM1,波特率9600
        # 'device_type': 'huawei_telnet',  # 指定设备类型,该类型适用于huawei设备,telnet方式
        'device_type': 'huawei',  # 该类型适用于huawei设备,ssh方式
        'host': ip,
        'port': 1022,  # ssh默认使用22,telnet默认使用23
        'username': 'admin',  # 设备管理员用户
        'password': 'TJuOO8Uz',  # 管理员用户密码
    }
    return dev


def conn_dev(dev_q):
    while not dev_q.empty():
        dev_ip = dev_q.get()
        try:
            dev_dict = conn_info(dev_ip)
            # guesser = SSHDetect(**dev_dict)
            # best_match = guesser.autodetect()
            # print('best_match is:{}'.format(best_match))
            # print('all guessers  is:{}'.format(guesser.potential_matches))
            # dev_dict['device_type'] = best_match
            dev_conn = ConnectHandler(**dev_dict)
            print("[%s] Connected." % dev_ip)
            output = dev_conn.send_config_from_file('cmds.txt')
            print(output)
            output = dev_conn.save_config()
            print(output)
            dev_conn.disconnect()
            print('[%s] done.\n' % dev_ip)
        except NetMikoAuthenticationException:
            print("[%s] Error! Please check username or password ..." % dev_ip)
        except NetMikoTimeoutException:
            print("[%s] Error! Connect time out ..." % dev_ip)
        except Exception as e:
            print('[%s] Error:%s' % (dev_ip, e))


if __name__ == "__main__":
    devs_ip = ['192.168.12.34', '192.168.12.35', '192.168.13.19']  # 需进行配置的交换机ip地址列表

    devs_q = queue.Queue()
    for dev in devs_ip:
        devs_q.put(dev)

    max_conn = 15  # 同时操作交换机数量(可增加或减少)

    ts = []  # 线程集合
    for i in range(max_conn):
        t = threading.Thread(target=conn_dev, args=(devs_q,))
        t.start()
        ts.append(t)
    for t in ts:
        t.join()

    print("Done.")
# !/usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ =
from netmiko import ConnectHandler
import os, re
import warnings
import threading
import queue
from netmiko.exceptions import NetMikoAuthenticationException, NetMikoTimeoutException
from typing import Optional, Any, Union, Sequence, Iterator, TextIO
from netmiko.no_enable import NoEnable
from netmiko.base_connection import DELAY_FACTOR_DEPR_SIMPLE_MSG
from netmiko.cisco_base_connection import CiscoBaseConnection
from netmiko.exceptions import NetmikoAuthenticationException
from netmiko import log

"""网络设备登录用户名和密码"""
dev_username = 'admin'
dev_password = '123456'

"""定义配置执行范围"""
Room = 'XXXX'
Network = 'XXXX'
Domain = 'XXXX'

PATH = os.path.dirname(os.path.abspath(__file__))
newpath = os.path.join(PATH, 'logs', Room, Network, Domain)
if not os.path.exists(newpath):
    os.makedirs(newpath)


class H3cBase(NoEnable, CiscoBaseConnection):
    prompt_pattern = r"[\]>]"
    password_change_prompt = r"(?:Change now|Please choose)"
    prompt_or_password_change = rf"(?:Change now|Please choose|{prompt_pattern})"

    def session_preparation(self) -> None:
        """Prepare the session after the connection has been established."""
        self.ansi_escape_codes = True
        # The _test_channel_read happens in special_login_handler()
        self.set_base_prompt()
        self.disable_paging(command="screen-length disable")

    def strip_ansi_escape_codes(self, string_buffer: str) -> str:
        """
        Huawei does a strange thing where they add a space and then add ESC[1D
        to move the cursor to the left one.

        The extra space is problematic.
        """
        code_cursor_left = chr(27) + r"\[\d+D"
        output = string_buffer
        pattern = rf" {code_cursor_left}"
        output = re.sub(pattern, "", output)

        return super().strip_ansi_escape_codes(output)

    def config_mode(
            self,
            config_command: str = "system-view",
            pattern: str = "",
            re_flags: int = 0,
    ) -> str:
        return super().config_mode(
            config_command=config_command, pattern=pattern, re_flags=re_flags
        )

    def exit_config_mode(self, exit_config: str = "return", pattern: str = r">") -> str:
        """Exit configuration mode."""
        return super().exit_config_mode(exit_config=exit_config, pattern=pattern)

    def check_config_mode(
            self, check_string: str = "]", pattern: str = "", force_regex: bool = False
    ) -> bool:
        """Checks whether in configuration mode. Returns a boolean."""
        return super().check_config_mode(check_string=check_string)

    def set_base_prompt(
            self,
            pri_prompt_terminator: str = ">",
            alt_prompt_terminator: str = "]",
            delay_factor: float = 1.0,
            pattern: Optional[str] = None,
    ) -> str:
        """
        Sets self.base_prompt

        Used as delimiter for stripping of trailing prompt in output.

        Should be set to something that is general and applies in multiple contexts.
        For Huawei this will be the router prompt with < > or [ ] stripped off.

        This will be set on logging in, but not when entering system-view
        """

        prompt = super().set_base_prompt(
            pri_prompt_terminator=pri_prompt_terminator,
            alt_prompt_terminator=alt_prompt_terminator,
            delay_factor=delay_factor,
            pattern=pattern,
        )

        # Strip off any leading HRP_. characters for USGv5 HA
        prompt = re.sub(r"^HRP_.", "", prompt, flags=re.M)

        # Strip off leading terminator
        prompt = prompt[1:]
        prompt = prompt.strip()
        self.base_prompt = prompt
        log.debug(f"prompt: {self.base_prompt}")
        return self.base_prompt

    def save_config(
            self, cmd: str = "save", confirm: bool = True, confirm_response: str = "y"
    ) -> str:
        """Save Config for H3cSSH

        Expected behavior:

        ######################################################################
        Warning: The current configuration will be written to the device.
        The current configuration will be written to the device. Are you sure? [Y/N]:y
        Please input the file name(*.cfg)[flash:/startup.cfg]
        (To leave the existing filename unchanged, press the enter key):
        flash:/startup.cfg exists, overwrite? [Y/N]:y
        Validating file. Please wait...
        Saved the current configuration to mainboard device successfully.
         Note: The configuration file will take effect after being activated
        ######################################################################
        """

        # Huawei devices might break if you try to use send_command_timing() so use send_command()
        # instead.
        if confirm:
            pattern = rf"(?:Are you sure|{self.prompt_pattern})"
            output = self._send_command_str(
                command_string=cmd,
                expect_string=pattern,
                strip_prompt=False,
                strip_command=False,
                read_timeout=100.0,
            )
            if confirm_response and "Are you sure" in output:
                output += self._send_command_str(
                    command_string=confirm_response,
                    expect_string=self.prompt_pattern,
                    strip_prompt=False,
                    strip_command=False,
                    read_timeout=100.0,
                )
            if 'press the enter key' in output:
                output += self._send_command_str(
                    command_string='\n',
                    expect_string=self.prompt_pattern,
                    strip_prompt=False,
                    strip_command=False,
                    read_timeout=100.0,
                )
            if 'exists, overwrite? [Y/N]:' in output:
                output += self._send_command_str(
                    command_string='y',
                    expect_string=self.prompt_pattern,
                    strip_prompt=False,
                    strip_command=False,
                    read_timeout=100.0,
                )
        # no confirm.
        else:
            # Some devices are slow so match on trailing-prompt if you can
            # cmd: str = "save force"
            output = self._send_command_str(
                command_string=cmd,
                strip_prompt=False,
                strip_command=False,
                read_timeout=100.0,
            )
        return output

    def cleanup(self, command: str = "quit") -> None:
        return super().cleanup(command=command)


class H3cSSH(H3cBase):
    """Huawei SSH driver."""

    def special_login_handler(self, delay_factor: float = 1.0) -> None:
        # Huawei prompts for password change before displaying the initial base prompt.
        # Search for that password change prompt or for base prompt.
        data = self.read_until_pattern(pattern=self.prompt_or_password_change)
        if re.search(self.password_change_prompt, data):
            self.write_channel("N" + self.RETURN)
            self.read_until_pattern(pattern=self.prompt_pattern)


class H3cTelnet(H3cBase):
    """Huawei Telnet driver."""

    def telnet_login(
            self,
            pri_prompt_terminator: str = r"",
            alt_prompt_terminator: str = r"",
            username_pattern: str = r"(?:user:|username|login|user name)",
            pwd_pattern: str = r"assword",
            delay_factor: float = 1.0,
            max_loops: int = 20,
    ) -> str:
        """Telnet login for Huawei Devices"""
        output = ""
        return_msg = ""
        try:
            # Search for username pattern / send username
            output = self.read_until_pattern(pattern=username_pattern, re_flags=re.I)
            return_msg += output
            self.write_channel(self.username + self.TELNET_RETURN)

            # Search for password pattern / send password
            output = self.read_until_pattern(pattern=pwd_pattern, re_flags=re.I)
            return_msg += output
            assert self.password is not None
            self.write_channel(self.password + self.TELNET_RETURN)

            # Waiting for the prompt or password change message
            output = self.read_until_pattern(pattern=self.prompt_or_password_change)
            return_msg += output

            # If password change prompt, send "N"
            if re.search(self.password_change_prompt, output):
                self.write_channel("N" + self.TELNET_RETURN)
                output = self.read_until_pattern(pattern=self.prompt_pattern)
                return_msg += output
                return return_msg
            elif re.search(self.prompt_pattern, output):
                return return_msg

            # Should never be here
            raise EOFError

        except EOFError:
            assert self.remote_conn is not None
            self.remote_conn.close()
            msg = f"Login failed: {self.host}"
            raise NetmikoAuthenticationException(msg)


class H3cVrpv8SSH(H3cSSH):
    def send_config_set(
            self,
            config_commands: Union[str, Sequence[str], Iterator[str], TextIO, None] = None,
            exit_config_mode: bool = False,
            **kwargs: Any,
    ) -> str:
        """Huawei VRPv8 requires you not exit from configuration mode."""
        return super().send_config_set(
            config_commands=config_commands, exit_config_mode=exit_config_mode, **kwargs
        )

    def commit(
            self,
            comment: str = "",
            read_timeout: float = 120.0,
            delay_factor: Optional[float] = None,
    ) -> str:
        """
        Commit the candidate configuration.

        Commit the entered configuration. Raise an error and return the failure
        if the commit fails.

        default:
           command_string = commit
        comment:
           command_string = commit comment <comment>

        delay_factor: Deprecated in Netmiko 4.x. Will be eliminated in Netmiko 5.
        """

        if delay_factor is not None:
            warnings.warn(DELAY_FACTOR_DEPR_SIMPLE_MSG, DeprecationWarning)

        error_marker = "Failed to generate committed config"
        command_string = "commit"

        if comment:
            command_string += f' comment "{comment}"'

        output = self.config_mode()
        output += self._send_command_str(
            command_string,
            strip_prompt=False,
            strip_command=False,
            read_timeout=read_timeout,
            expect_string=r"]",
        )
        output += self.exit_config_mode()

        if error_marker in output:
            raise ValueError(f"Commit failed with following errors:\n\n{output}")
        return output

    def save_config(self, *args: Any, **kwargs: Any) -> str:
        """Not Implemented"""
        raise NotImplementedError


def conn_info(ip):
    dev = {
        'host': ip,
        'port': 22,
        'username': dev_username,
        'password': dev_password,
    }
    return dev


def conn_dev(dev_q, newpath):
    while not dev_q.empty():
        dev_ip_dict = dev_q.get()
        dev_ip = dev_ip_dict.get('ip')
        dev_name = dev_ip_dict.get('devname')
        try:
            dev_dict = conn_info(dev_ip)
            dev_conn = H3cSSH(**dev_dict)
            print("[%s] Connected." % dev_ip)
            with open(newpath + '/exec.log', 'a', encoding='utf-8') as f:
                f.write("[%s] Connected.\n" % dev_ip)
            output1 = dev_conn.send_config_from_file(PATH + '/cmds.txt')
            output2 = dev_conn.save_config()
            dev_conn.disconnect()
            print('[%s] done.' % dev_ip)
            with open(newpath + '/exec.log', 'a', encoding='utf-8') as f:
                f.write('[%s] done.\n' % dev_ip)
            with open(newpath + '/{}.log'.format(dev_ip), 'w', encoding='utf-8') as f:
                f.write(output1 + output2)
        except NetMikoAuthenticationException:
            print("[%s] [%s] Error! Please check username or password ..." % (dev_name, dev_ip))
            with open(newpath + '/exec.log', 'a', encoding='utf-8') as f:
                f.write("[%s] [%s] Error! Please check username or password ...\n" % (dev_name, dev_ip))
        except NetMikoTimeoutException:
            print("[%s] [%s] Error! Connect time out ..." % (dev_name, dev_ip))
            with open(newpath + '/exec.log', 'a', encoding='utf-8') as f:
                f.write("[%s] [%s] Error! Connect time out ...\n" % (dev_name, dev_ip))
        except Exception as e:
            print('[%s] [%s] Error:%s' % (dev_name, dev_ip, e))
            with open(newpath + '/exec.log', 'a', encoding='utf-8') as f:
                f.write('[%s] [%s] Error:%s\n' % (dev_name, dev_ip, e))


if __name__ == "__main__":
    devs_ip = [{'devname': 'XXXX', 'ip': 'X.X.X.X'}, {'devname': 'XXXX', 'ip': 'X.X.X.X'}]
    devs_q = queue.Queue()
    for dev in devs_ip:
        if 'XXXX' == Room and 'XXXX' == Network and 'XXXX' == Domain:
            devs_q.put(dev)
    with open(newpath + '/vfws.log', 'w', encoding='utf-8') as f:
        f.write('设备数: %s' % devs_q.qsize())
    max_conn = 15  # 同时操作交换机数量
    ts = []  # 线程集合
    for i in range(max_conn):
        t = threading.Thread(target=conn_dev, args=(devs_q, newpath))
        t.start()
        ts.append(t)
    for t in ts:
        t.join()
H3C设备批量脚本
# netconf服务测试
[root@localhost ~]# ssh admin@192.168.1.1 -p 830 -s netconf

参考链接:
       https://github.com/ktbyers/netmiko
       https://github.com/openconfig/public/tree/master/release/models     # netconf
       https://www.cnblogs.com/dxnui119/p/15562592.html     # ncclient模块

posted @ 2023-09-25 10:32  風£飛  阅读(179)  评论(0编辑  收藏  举报