python ansible api + fastapi写华为网络设备下发api接口

#encoding=utf-8

from fastapi import Body,FastAPI,Depends,Query
from typing import Optional,List
from pydantic import BaseModel
from ruamel import yaml

#参考 https://zhuanlan.zhihu.com/p/118411015

import json
import shutil
from ansible.module_utils.common.collections import ImmutableDict
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
from ansible import context
import ansible.constants as C


class ResultCallback(CallbackBase):
    """
    重写callbackBase类的部分方法
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}
        self.task_ok = {}
    def v2_runner_on_unreachable(self, result):
        self.host_unreachable[result._host.get_name()] = result

    def v2_runner_on_ok(self, result, **kwargs):
        self.host_ok[result._host.get_name()] = result

    def v2_runner_on_failed(self, result, **kwargs):
        self.host_failed[result._host.get_name()] = result

class MyAnsiable2():
    def __init__(self,
        connection='local',  # 连接方式 local 本地方式,smart ssh方式
        remote_user=None,    # 远程用户
        ack_pass=None,       # 提示输入密码
        sudo=None, sudo_user=None, ask_sudo_pass=None,
        module_path=None,    # 模块路径,可以指定一个自定义模块的路径
        become=True,         # 是否提权
        become_method='sudo',  # 提权方式 默认 sudo 可以是 su
        become_user='root',  # 提权后,要成为的用户,并非登录用户
       check=False, diff=False,
        listhosts=None, listtasks=None,listtags=None,
        verbosity=3,
        syntax=None,
        start_at_task=None,
        inventory=None):

        # 函数文档注释
        """
        初始化函数,定义的默认的选项值,
        在初始化的时候可以传参,以便覆盖默认选项的值
        """
        context.CLIARGS = ImmutableDict(
            connection=connection,
            remote_user=remote_user,
            ack_pass=ack_pass,
            sudo=sudo,
            sudo_user=sudo_user,
            ask_sudo_pass=ask_sudo_pass,
            module_path=module_path,
            become=become,
            become_method=become_method,
            become_user=become_user,
            verbosity=verbosity,
            listhosts=listhosts,
            listtasks=listtasks,
            listtags=listtags,
            syntax=syntax,
            start_at_task=start_at_task,
        )

        # 三元表达式,假如没有传递 inventory, 就使用 "localhost,"
        # 确定 inventory 文件
        self.inventory = inventory if inventory else "localhost,"

        # 实例化数据解析器
        self.loader = DataLoader()

        # 实例化 资产配置对象
        self.inv_obj = InventoryManager(loader=self.loader, sources=self.inventory)

        # 设置密码,可以为空字典,但必须有此参数
        self.passwords = {}

        # 实例化回调插件对象
        self.results_callback = ResultCallback()

        # 变量管理器
        self.variable_manager = VariableManager(self.loader, self.inv_obj)


    def run(self, hosts='localhost', gether_facts="no", module="ping", args=''):
        play_source =  dict(
            name = "Ad-hoc",
            hosts = hosts,
            gather_facts = gether_facts,
            tasks = [
                # 这里每个 task 就是这个列表中的一个元素,格式是嵌套的字典
                # 也可以作为参数传递过来,这里就简单化了。
                {"action":{"module": module, "args": args}},
            ])

        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

        tqm = None
        try:
            tqm = TaskQueueManager(
                      inventory=self.inv_obj ,
                      variable_manager=self.variable_manager,
                      loader=self.loader,
                      passwords=self.passwords,
                      stdout_callback=self.results_callback)

            result = tqm.run(play)
        finally:
            if tqm is not None:
                tqm.cleanup()
            shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)

    def playbook(self,playbooks):
        from ansible.executor.playbook_executor import PlaybookExecutor

        playbook = PlaybookExecutor(playbooks=playbooks,  # 注意这里是一个列表
                        inventory=self.inv_obj,
                        variable_manager=self.variable_manager,
                        loader=self.loader,
                        passwords=self.passwords)

        # 使用回调函数
        playbook._tqm._stdout_callback = self.results_callback

        result = playbook.run()


    def get_result(self):
      result_raw = {'success':{},'failed':{},'unreachable':{}}

      # print(self.results_callback.host_ok)
      for host,result in self.results_callback.host_ok.items():
          result_raw['success'][host] = result._result
      for host,result in self.results_callback.host_failed.items():
          result_raw['failed'][host] = result._result
      for host,result in self.results_callback.host_unreachable.items():
          result_raw['unreachable'][host] = result._result

      # 最终打印结果,并且使用 JSON 继续格式化
      print(json.dumps(result_raw, indent=4))
      return json.dumps(result_raw, indent=4)

#生成playbook文件和hosts文件
def gen_file(cmd_lst, ip_lst):
    data = [{
        "name":"ColudEngine Command",
        "hosts":"test",
        "connection":"network_cli",
        "gather_facts":"no",
        "vars":{
            "cli":{
                "host":"{{inventory_hostname}}",
                "port":"{{ansible_ssh_port}}",
                "username":"{{ansible_ssh_user}}",
                "password":"{{ansible_ssh_pass}}",
                "transport":"cli"
            }
        },
        "tasks":[
        {
            "name":"1.config",
            "ansible.netcommon.cli_command":{
                "command":"{{item}}",
                "prompt":["Y/N"],
                "answer":"Y"
            },
            "loop":cmd_lst,
            "register":"output",
        },
        {"debug": "msg={{output}}"}
    ],
    }]

    path = "device_test.yml"
    with open(path,'w',encoding='utf-8') as f:
        yaml.dump(data,f,Dumper=yaml.RoundTripDumper)

    with open("hosts",'w',encoding='utf-8') as f1:
        f1.write("[test] \n")
        for ip in ip_lst:
            f1.write("{} \n".format(ip))
        f1.write("[test:vars] \n")
        f1.write("ansible_connection = network_cli \n")
        f1.write("ansible_network_os = ce \n")
        f1.write("ansible_port = 22 \n")
        f1.write("ansible_ssh_user = xxx \n")
        f1.write("ansible_ssh_pass = xxx \n")

def ansible_single(cmd,ip):
    cmd_lst = []
    ip_lst = []
    cmd_lst.append(cmd)
    ip_lst.append(ip)
    gen_file(cmd_lst,ip_lst)
    ansible2 = MyAnsiable2(inventory='hosts',connection='smart')
    ansible2.playbook(playbooks=['device_test.yml'])
    stdout_dict = json.loads(ansible2.get_result())
    return stdout_dict

def ansible_lst(cmd_lst,ip_lst):
    gen_file(cmd_lst, ip_lst)
    ansible2 = MyAnsiable2(inventory='hosts', connection='smart')
    ansible2.playbook(playbooks=['device_test.yml'])
    stdout_dict = json.loads(ansible2.get_result())
    return stdout_dict

app = FastAPI()

@app.get("single")
async def test(result:dict = Depends(ansible_single)):
    return result

@app.put("list")
async def test(cmd:list,ip:list):
    result = ansible_lst(cmd,ip)
    return result

### postman 测试
#Body格式为json
# {
#     "cmd":["xxx"],
#     "ip":["xxx"],
# }
<think>好的,我现在需要回答用户关于华为YANG模型具体使用实例和场景的问题。首先,我要回顾之前的对话,确保信息连贯。用户之前询问华为数通产品是否支持YANG模型,我回答了支持的概况,现在需要更深入的具体例子和场景。 用户可能希望了解实际中如何应用YANG模型,比如配置管理、自动化运维、遥测等。我需要拆分成不同的应用场景,每个场景给出具体例子,说明YANG模型如何在这些情况下使用。 接下来,我需要考虑用户可能的背景。他们可能是网络工程师或开发人员,想要在实际项目中应用华为设备的自动化管理。因此,实例需要具体,最好包含协议、工具和操作步骤,但不过于技术细节,保持易懂。 需要确保涵盖华为YANG模型的不同用途,如配置下发、状态查询、数据采集,以及与第三方系统的集成。同时,可能需要提到华为的特定工具或平台,如iMaster NCE,或者使用NETCONF/RESTCONF协议的例子。 还要注意版本差异,不同设备可能支持不同模型,需要提醒用户查阅官方文档。同时,可能存在的私有扩展和标准模型的区别,需要简要说明。 需要结构清晰,分点列出不同的场景,每个场景下有实例说明。例如,自动化配置、网络状态监控、与SDN控制器集成等。每个实例需要具体说明使用什么协议、模型,以及大致流程。 另外,可能需要提供获取模型的方法和工具,如命令行查看、官网下载,或者使用Pyang解析,这些在之前的回答中已经部分涉及,但可以在此处作为补充。 最后,确保语言简洁,避免专业术语过多,必要时进行解释。例如,解释NETCONF协议的作用,或者Telemetry是什么,但保持整体回答的流畅性。以下是</think>华为YANG模型的具体使用实例和典型场景,结合实际网络管理需求,展示其如何实现高效、自动化的设备操作: --- ### **1. 自动化设备配置管理** #### **场景**:批量修改交换机接口配置(如VLAN、速率) - **实现步骤**: 1. **定义YANG模型**:使用标准接口模型(如`ietf-interfaces.yang`)或华为扩展模型(`huawei-ifm.yang`)描述接口参数。 2. **生成XML/JSON配置**:基于YANG模型编配置数据(例如设置接口VLAN为100)。 3. **通过NETCONF协议下发**:使用工具(如Python的`ncclient`库)将配置推送到设备。 ```xml <!-- 示例:通过NETCONF配置接口VLAN --> <config> <ifm:interfaces xmlns:ifm="urn:huawei:yang:huawei-ifm"> <ifm:interface> <ifm:name>GigabitEthernet0/0/1</ifm:name> <ifm:type>Ethernet</ifm:type> <ifm:l2Attribute> <ifm:vlan-id>100</ifm:vlan-id> </ifm:l2Attribute> </ifm:interface> </ifm:interfaces> </config> ``` - **优势**:避免手动CLI逐台配置,减少人为错误。 --- ### **2. 实时网络状态监控(Telemetry)** #### **场景**:监控路由器CPU利用率并实时告警 - **实现步骤**: 1. **选择YANG模型**:使用华为性能监控模型(如`huawei-devm.yang`)定义采集指标(CPU使用率)。 2. **订阅数据流**:通过gRPC或Telemetry协议订阅设备实时数据。 3. **流式数据处理**:将数据推送至分析平台(如Prometheus+Grafana),触发阈值告警。 ```python # 示例:订阅CPU利用率的YANG路径 subscription = { "sensor-path": "huawei-devm:devm/cpuInfos/cpuInfo", "sample-interval": 5000 # 5秒采集一次 } ``` - **优势**:秒级实时监控,替代传统SNMP轮询。 --- ### **3. SDN控制器集中管控** #### **场景**:通过iMaster NCE控制器管理全网设备 - **实现流程**: 1. **控制器建模**:iMaster NCE内置华为YANG模型库,自动解析设备能力。 2. **下发全网策略**:例如配置QoS策略,控制器通过NETCONF将YANG格式策略下发至所有设备。 3. **状态同步**:设备通过YANG模型反馈配置状态,控制器统一展示。 - **典型应用**:企业网/数据中心自动化策略部署。 --- ### **4. 设备故障快速排查** #### **场景**:批量查询接口错误计数 - **操作示例**: 1. **构建YANG查询请求**:使用`huawei-ifm`模型查询接口统计信息。 2. **通过RESTCONF获取数据**: ```bash GET /restconf/data/huawei-ifm:interfaces/interface=GigabitEthernet0/0/1 Headers: Accept: application/yang-data+json ``` 3. **解析结果**:直接获取JSON格式的错误包计数(如`input-errors`字段)。 - **优势**:标准化数据结构,便于集成运维脚本。 --- ### **5. 第三方系统集成** #### **场景**:与Zabbix/Ansible等工具对接 - **实现方式**: - **Ansible**:使用`ansible-netconf`模块调用华为YANG模型配置设备。 - **Zabbix**:通过YANG模型定义监控项,自动生成设备监控模板。 ```yaml # Ansible示例:使用YANG模型关闭接口 - name: Shutdown interface community.netconf.netconf_config: target: running xml: | <config> <ifm:interfaces xmlns:ifm="urn:huawei:yang:huawei-ifm"> <ifm:interface> <ifm:name>GigabitEthernet0/0/2</ifm:name> <ifm:adminStatus>down</ifm:adminStatus> </ifm:interface> </ifm:interfaces> </config> ``` --- ### **6. 设备版本升级兼容性校验** #### **场景**:升级前验证配置是否兼容新版本 - **步骤**: 1. 从新版本设备导出YANG模型。 2. 使用工具(如`pyang`)对比新旧模型差异。 3. 检查现有配置是否符合新模型约束,避免升级后配置失效。 --- ### **关键工具与资源** - **华为YANG Browser**:可视化查看模型结构与字段含义。 - **Pyang/Yanglint**:校验YANG文件语法及生成代码。 - **GitHub仓库**:部分开源模型可从[Huawei YANG Models](https://github.com/华为YANG模型仓库)获取。 --- ### **注意事项** - **模型版本匹配**:设备OS版本需与YANG模型版本一致。 - **混合模型使用**:同时调用标准模型(如`ietf-ip`)和华为扩展模型时,需注意命名空间冲突。 通过上述实例可以看出,YANG模型在华为设备中深度融入自动化运维、智能分析等场景,是构建“零接触网络”(Zero-Touch Network)的核心技术基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值