基類 派生類 類的繼承與約束、python 項目架構邏輯設計

用法

一、在基類中定義全部的方法,在各個派生類中繼承基類,派生類能夠直接調用基類中的方法,基類中的方法就是默認配置方法,若項自定義方法能夠在派生類中自定義方法。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
View Code

約束

class BaseHandler(object):
    def handler(self):
        """
        約束全部的派生類都必須實現handler方法
        :return:
        """
        raise NotImplementedError('handler must be implemented')
        

class AgentHandler(BaseHandler):
    """
    繼承BaseHandler 當調用handler方法時若自身無此方法則會拋出異常提醒
    """
    def  handler(self):
        pass
View Code

 實際應用實例(以cmdb 資產採集爲例)

功能概述:資產採集分爲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

src/engine/base.py

#!/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)
View Code

src/engine/agent.py

#!/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)
View Code

src/engine/ssh.py

#!/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

src/engine/salt.py

#!/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]
View Code

python 項目架構設計和類的使用總結

  • 相同屬性的功能模塊放在相同目錄(資產採集插件disk.py memory.py 都在放在plugins目錄下)
  • 每個功能都放在一個單獨的py文件中定義一個對應的類,而不是這些類都寫在同一個py文件中。這樣作的好處:一、便於維護,若是哪一個模塊刪除修改單獨進行不影響總體 二、每一個都是獨立的一個py 文件,這樣能夠對這些功能模塊在配置文件中以字典的形式註冊,此爲可插拔可擴展模式。
  • 不一樣的功能定義在各自的模塊(py文件)下定義本身的類,每一個功能類中要實現的功能經過定義不一樣的方法(函數)來分步驟實現。
  • 各個功能類中每一個功能類中相同屬性的方法定義成相同的函數名稱(AgentHandler、SSHHandler、類中都定義了handler、cmd 函數),有時候是必須名稱一致。
  • 因爲不一樣條件下調用不一樣的功能類,根據配置文件配置而導入不一樣的類,此時類的引入爲變量模式,要使用類中的方法時(cls.handler)此時方法名稱必須一致。
  • 上述請況不只須要方法名成相同,並且每一個類中必須存在handler 類,因此此處採用繼承約束,定義一個基類供這些類繼承,基類中定義handler 方法,調用此方法時拋出異常(提示派生類必須定義此方法,此爲約束)
  • 各個功能類中的方法不只功能屬性相同並且代碼也一致,此時可在基類中定義此方法,供這些類來繼承,這樣既簡化代碼也更有邏輯性。
  • A B C 三個類都有相同的方法且代碼相同,可定義一個基類D定義這個方法便可,它們功能繼承。於此同時A B 兩個類也有另外一個方法相同代碼,此時定義一個基類E ,E中定義這個方法,那麼AB 怎麼可以同時繼承E D 中的方法呢,此時A B 繼承E,E繼承D,AB 既繼承了E 中的方法,也經過E 間接繼承了D 中的方法。
  • 多個模塊中的類須要引入相同的模塊中的變量,能夠在它們繼承的基類中定義 def __init__(self):  self.asset_api = settings.ASSET_API ,而後再基類中經過self.asset_api 引入
相關文章
相關標籤/搜索