一、在基類中定義全部的方法,在各個派生類中繼承基類,派生類能夠直接調用基類中的方法,基類中的方法就是默認配置方法,若項自定義方法能夠在派生類中自定義方法。python
二、cmdb 資產採集插件disk.py memory.py 每一個插件類中都定義了相同的方法,因此爲了簡約代碼相同的方法能夠定義在基類中供這些插件去繼承調用。每一個插件執行時到須要讀取settings.py 中的信息,此時能夠在基類中import settings.py 中的配置變量信息,在插件中直接self.變量去引用。json
三、在基類中定義方法,方法中拋出異常,異常內容爲提示必須建立此方法,派生類繼承基類,若派生類中爲定義基類中方法則調用時拋出異常,提示派生類必須自定義該方法,此爲約束。api
class BaseHandler(object): def func(self): print("方法一") def func1(self): print ("方法二") class AgentHandler(BaseHandler): """ 繼承BaseHandler 無需自定義fun 等方法能夠直接繼承使用,若須要自定義新的fun方法能夠自定義 """ def handler(self): pass
class BaseHandler(object): def handler(self): """ 約束全部的派生類都必須實現handler方法 :return: """ raise NotImplementedError('handler must be implemented') class AgentHandler(BaseHandler): """ 繼承BaseHandler 當調用handler方法時若自身無此方法則會拋出異常提醒 """ def handler(self): pass
功能概述:資產採集分爲ssh /salt /agent 三種模式,每種模式對應三種應用模塊,每一個應用類中都是固定的兩個方法cmd和handler,cmd 實現salt/ssh 的遠程登陸功能,handler 實現主機列表信息獲取,調用資產採集模塊採集資產信息,發送數據到api。架構
模塊類的繼承關係: AgentHandler繼承BaseHandler,SaltHandler、SSHHandler經過SaltAndSSHHandler間接繼承BaseHandler,BaseHandler 下的cmd handler對它們進行約束;併發
SaltHandler和SSHHandler 下的handler 函數具備相同的功能及代碼,因此handler 函數寫在 SaltAndSSHHandler 類下供它們繼承,爲了能讓它們繼承Basehandler 類下的約束,SaltAndSSHHandler 繼承Basehandlerapp
#!/usr/bin/python # -*- coding:utf-8 -*- import json import requests from config import settings from ..plugins import get_server_info class BaseHandler(object): def __init__(self): self.asset_api = settings.ASSET_API #獲取配置文件中資產入庫接口地址,供繼承BaseHandler 的類調用 def cmd(self,command, hostname=None): #約束全部的派生類都必須實現handler方法 raise NotImplementedError('cmd must be implemented') def handler(self): """ 約束全部的派生類都必須實現handler方法 :return: """ raise NotImplementedError('handler must be implemented') class SaltAndSSHHandler(BaseHandler): def handler(self): """ 處理SSH/SALT模式下的資產採集 說明:因爲ssh或salt 模式都是先獲取主機列表,在開啓線程池批量遠程獲取數據,具備相同的方法, 因此在SaltAndSSHHandler 基類中定義handler 方法供他們繼承 :return: """ #引入線程池 from concurrent.futures import ThreadPoolExecutor # 1. 獲取未採集的主機的列表 r1 = requests.get(url=self.asset_api) hostname_list = r1.json() #二、實例一個20個線程的線程池對象,循環主機列表,每次20線程同時執行資產採集發送任務。 pool = ThreadPoolExecutor(20) for hostname in hostname_list: pool.submit(self.task, hostname) def task(self, hostname): """ 資產採集,數據發送 說明:因爲開啓了線程池,資產採集的操做必須以函數形式放在for 循環中以線程池的方式批量同時執行。 :param hostname: :return: """ info = get_server_info(self, hostname) # 2. 發送到api r1 = requests.post( url=self.asset_api, data=json.dumps(info).encode('utf-8'), headers={ 'Content-Type': 'application/json' } ) print(r1)
#!/usr/bin/python # -*- coding:utf-8 -*- import json import requests from .base import BaseHandler from ..plugins import get_server_info class AgentHandler(BaseHandler): def cmd(self,command,hostname=None): import subprocess return subprocess.getoutput(command) def handler(self): """ 處理Agent模式下的資產採集:網卡、內存、硬盤,併發送到接口 :return: """ # 1. 經過調用get_server_info獲取全部的資產信息:網卡、內存、硬盤 info = get_server_info(self) # 2. 發送到api r1 = requests.post( url=self.asset_api, data=json.dumps(info).encode('utf-8'), headers={ 'Content-Type':'application/json' } ) print(r1)
#!/usr/bin/python # -*- coding:utf-8 -*- from config import settings from .base import SaltAndSSHHandler class SSHHandler(SaltAndSSHHandler): def cmd(self, command, hostname=None): """ 調用paramiko遠程鏈接主機並執行命令,依賴rsa :param hostname:主機名 :param command: 要執行的命令 :return: """ import paramiko private_key = paramiko.RSAKey.from_private_key_file(settings.SSH_PRIVATE_KEY) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname=hostname, port=settings.SSH_PORT, username=settings.SSH_USER, pkey=private_key) stdin, stdout, stderr = ssh.exec_command(command) result = stdout.read() ssh.close() return result
View Codessh
#!/usr/bin/python # -*- coding:utf-8 -*- from .base import SaltAndSSHHandler class SaltHandler(SaltAndSSHHandler): def cmd(self, command, hostname=None): """ 調用saltstack遠程鏈接主機並執行命令(saltstack的master) :param hostname:主機名 :param command: 要執行的命令 :return: """ import salt.client local = salt.client.LocalClient() result = local.cmd(hostname, 'cmd.run', [command]) return result[hostname]