CMDB開發之服務器數據採集

服務器數據採集與接收

採集數據可以有n種方法。但是我們並不需要太高深的知識,python基礎足矣。現在完成的是一個Python獲取linux服務器資源的腳本。

#!/usr/bin/env python3
#coding:utf-8
import os
import uuid
import socket

#獲取主機名
hostname = socket.gethostname()
#獲取ip地址,不確定獲取那個
ip = socket.gethostbyname(hostname)
#mac地址
mac = uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
mac = ":".join([mac[i:i+2] for i in range(0,11,2)])
#cpu型號
with os.popen("cat /proc/cpuinfo") as f:
    for line in f.readlines():
        key,value = line.split(":")
        key = key.strip()
        value = value.strip()
        if key == "model name":
           cpuData = value
           break
#內存大小
with os.popen("cat /proc/meminfo") as f:
    for line in f.readlines():
        key,value = line.split(":")
        key = key.strip()
        value = value.strip()
        if key == "MemTotal":
           MemTotal = value
           break

print(MemTotal)

效果如下:

but,上面的方法沒有將數據進行統籌,所以我們需要將數據進行一次整合

#!/usr/bin/env python3
#coding:utf-8
import os
import uuid
import socket
result = {}

#獲取主機名
hostname = socket.gethostname()
result["hostname"] = hostname

#獲取ip地址,不確定獲取那個
ip = socket.gethostbyname(hostname)
result["ip"] = ip

#mac地址
mac = uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
mac = ":".join([mac[i:i+2] for i in range(0,11,2)])
result["mac"] = mac

#cpu型號
with os.popen("cat /proc/cpuinfo") as f:
    for line in f.readlines():
        key,value = line.split(":")
        key = key.strip()
        value = value.strip()
        if key == "model name":
           cpuData = value
           break
result["cpu"] = cpuData
#內存大小
with os.popen("cat /proc/meminfo") as f:
    for line in f.readlines():
        key,value = line.split(":")
        key = key.strip()
        value = value.strip()
        if key == "MemTotal":
           MemTotal = value
           break
result["memtotal"] = MemTotal

print(result)

效果如下:

但是我們又會發現這樣做還是不夠好,我們應該將有參數的放到函數或類當中,那麼我們試試用類和裝飾器寫一寫,進行簡單的結構編寫。

#!/usr/bin/env python3
#coding:utf-8
import os
import uuid
import socket

class GetData(object):
    def __init__(self):
        self.result = {} #實例化最終的結果
def getData_byFile(self,command,keyword):
	  “”“
統一的獲取文件當中參數的方法
”“”
        result = ""
        with os.popen(command) as f:
        for line in f.readlines():
                key,value = line.split(":")
                key = key.strip()
                value = value.strip()
                if key == keyword:
                    result = value
                    break
         return result 

    def get_cpu(self):
        command = "cat /proc/cpuinfo"
        keyword = "model name"
        cpuData = self.getData_byFile(command,keyword)
        return cpuData
    def get_mem(self):
        command = "cat /proc/meminfo"
        keyword = "MemTotal"
        meminfo = self.getData_byFile(command,keyword)
        return meminfo
    def get_hostname(self):
        hostname = socket.gethostname()
        return hostname
    def get_ip(self):
        ip = socket.gethostbyname(hostname)
        return ip
    def get_mac(self):
        mac = uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
        mac = ":".join([mac[i:i+2] for i in range(0,11,2)])
        result["mac"] = mac
        return mac

在上面的基礎上我們再進行優化一次

#!/usr/bin/env python3
#coding:utf-8
import os
import uuid
import socket

class GetData(object):
    def __init__(self):
        self.result = {}
    def getData_byFile(self,command,keyword):
        result = ""
        with os.popen(command) as f:
            for line in f.readlines():
                key,value = line.split(":")
                key = key.strip()
                value = value.strip()
                if key == keyword:
                    result = value
                    break
        return result

    def get_cpu(self):
        command = "cat /proc/cpuinfo"
        keyword = "model name"
        cpuData = self.getData_byFile(command,keyword)
        return cpuData
    def get_mem(self):
        command = "cat /proc/meminfo"
        keyword = "MemTotal"
        meminfo = self.getData_byFile(command,keyword)

    def get_cpu(self):
        command = "cat /proc/cpuinfo"
        keyword = "model name"
        cpuData = self.getData_byFile(command,keyword)
        return cpuData
    def get_mem(self):
        command = "cat /proc/meminfo"
        keyword = "MemTotal"
        meminfo = self.getData_byFile(command,keyword)
        return meminfo
    def get_hostname(self):
        self.hostname = socket.gethostname()
        return self.hostname
    def get_ip(self):
        ip = socket.gethostbyname(self.hostname)
        return ip
    def get_mac(self):
        mac = uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
        mac = ":".join([mac[i:i+2] for i in range(0,11,2)])
        return mac
    def getAll(self):
        self.result = {
           "mac": self.get_mac(),
           "hostname": self.get_hostname(),
           "ip": self.get_ip(),
           "cpuData": self.get_cpu(),
           "memtotal": self.get_mem()
        }

if __name__ == "__main__":
    data = GetData()
    data.getAll()
print(data.result)

but,在生成鍵值對這裏我們不必單獨進行生成,我們可以寫一個裝飾器,將其放入我們的字典中。

#!/usr/bin/env python3
#coding:utf-8
import os
import uuid
import socket

class GetData(object):
    def __init__(self):
        self.result = {}

    def getResult(fun):
        def inner(self):
            key,value = fun(self)
            self.result[key] = value #這裏需要鍵值對
        return inner

    def getData_byFile(self,command,keyword):
        result = ""
        with os.popen(command) as f:
            for line in f.readlines():
                key,value = line.split(":")
                key = key.strip()
                value = value.strip()
                if key == keyword:
                    result = value
                    break
        return result

    @getResult
    def get_cpu(self):
        command = "cat /proc/cpuinfo"
        keyword = "model name"
        cpuData = self.getData_byFile(command,keyword)
        return "cpu",cpuData
    @getResult
    def get_mem(self):
        command = "cat /proc/meminfo"
        keyword = "MemTotal"
        meminfo = self.getData_byFile(command,keyword)
        return "meminfo",meminfo
    @getResult
    def get_hostname(self):
        self.hostname = socket.gethostname()
        return "hostname",self.hostname
    @getResult
    def get_ip(self):
        ip = socket.gethostbyname(self.hostname)
        return "ip",ip
    @getResult
    def get_mac(self):
        mac = uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
        mac = ":".join([mac[i:i+2] for i in range(0,11,2)])
        return "mac",mac
    def getAll(self):
        self.result = {
           "mac": self.get_mac(),
           "hostname": self.get_hostname(),
           "ip": self.get_ip(),
           "cpuData": self.get_cpu(),
           "memtotal": self.get_mem()
        }

if __name__ == "__main__":
    data = GetData()
    data.get_cpu()
    data.get_mem()
    data.get_hostname()
    print(data.result)

到這裏一個比較完整的腳本就完成了,當然也還是有可以優化的地方,值得注意的是我們在查詢ip的時候是調用了我們的主機名來進行查詢的。所以說一定要有先後順序進行查詢,如果先查詢ip就會報錯。

查看裝飾的步驟

  1. get_houstname作爲參數,傳入getResult
  2. key,value = fun(self)實例化了get_houstname          key = hostname value = self.hostname
  3. 不論裝飾器裝飾了啥,返回的都是inner函數
  4.  self.method == method(self)

服務器數據採集的發送

我們開始設置我們的接口

\ALLENCMDB\Server\views.py

from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
from django.views.generic import View


class Api(View):
    def post(self,request):
        if request.POST:
            postData = request.POST
            return HttpResponse(postData)

    def get(self,request):
        if request.GET:
            getData = request.GET["key"]
            return HttpResponse(getData)

設置好url,通過瀏覽器訪問沒有問題

那麼我們通過腳本來測試一下,首先保證你的Linux服務器能夠與你的服務器能夠互相ping通

WebServer:192.168.1.32

LinuxServer:192.168.1.53

然後在linuxserver上編寫腳本,注意,如果Django服務器想被其他人訪問自己,那麼需要監聽所有ip

然後用腳本請求,我們進行請求的代碼

#!/usr/bin/env python3
#coding:utf-8

import requests

url = "http://192.168.2.215:8000/API/"
data = {
   "type": "user_login",
    "data": {
       "username": "root",
       "password": "123456"
    },
    "token": ""
}

response = requests.post(url,data = data)
with open("1.html","w") as f:
    f.write(response.content)
print(response)

在接口請求的過程當中,如果發現請求的數據發送不成功,請將嵌套部分進行json封裝
請求的代碼

#!/usr/bin/env python3
#coding:utf-8

import json
import requests

url = "http://192.168.2.215:8000/API/"
#對發送數據嵌套部分進行json封裝
login_data = json.dumps({
        "username": "root",
        "password": "123456"
})

data = {
   "type": "user_login",
   "data": login_data,
    "token": ""
}


response = requests.post(url,data = data)
result = response.json()
print(result)

\ALLENCMDB\Server\views.py

import json
from django.views.generic import View
from django.http import JsonResponse,HttpResponse

class Api(View):
    def __init__(self,**kwargs):
        View.__init__(self,**kwargs)
        self.result = {
            "status": "",
            "data": {}
        }

    def post(self,request):
        """
        處理post請求
        """
        if request.POST:
            postData = request.POST
            post_type = postData.get("type") #獲取類型
            if post_type == "user_login":
                login_data = json.loads(postData.get("data")) #獲取登錄數據,這裏獲取的是提交的json字符串
                username = login_data.get("username") #獲取用戶名
                self.result["status"] = "success"
                self.result["data"]["token"] = "211314"
            else:
                self.result["status"] = "error"
                self.result["data"]["error"] = "no method named %s"%postData
            return JsonResponse(self.result)


    def get(self, request):
        """
        處理get請求
        """
        if request.GET:
            getData = request.GET.get("key")
            return HttpResponse(getData)

我們利用上述腳本請求的時候會報錯, 這裏我們一定要注意類視圖的一些特性。

然後將我們的視圖代碼修改

from django.views.generic import View
from django.http import JsonResponse,HttpResponse

class Api(View):
    	"""
       """
    def __init__(self,**kwargs):
        View.__init__(self,**kwargs)
        self.result = {
            "status": "",
            "data": {}
        }

    def post(self,request):
        """
        處理post請求
        """
        if request.POST:
            postData = request.POST.get("type")
            if postData == "user_login":
                self.result["status"] = "success"
                self.result["data"]["token"] = "211314"
            else:
                self.result["status"] = "error"
                self.result["data"]["error"] = "no method named %s"%postData
            return JsonResponse(self.result)


    def get(self, request):
        """
        處理get請求
        """
        if request.GET:
            getData = request.GET.get("key")
            return HttpResponse(getData)

完善我們的token機制

上面我們已經疏通了我們接口的基本樣式,那麼我們現在來完成完整的接口請求流程。

1. 確定我們的登錄用戶

進行登錄邏輯的編寫,首先完善登錄的基本邏輯

import json

from django.views.generic import View
from django.http import JsonResponse,HttpResponse

from Service.models import LoginUser,Service,APIToken


class API(View):
    def __init__(self,**kwargs):
        View.__init__(self,**kwargs)
        self.result = {
            "status": "",
            "data": {}
        }

    def post(self,request):
        """
        處理post請求
        """
        if request.POST:
            postData = request.POST
            post_type = postData.get("type") #獲取類型
            login_data = json.loads(postData.get("data"))  # 獲取登錄數據,這裏獲取的是提交的json字符串
            if post_type == "user_login":
                username = login_data.get("username") #獲取接口提交的用戶名
                password = login_data.get("password") #獲取接口提交的密碼
                try:
                    loginUser = LoginUser.objects.get(username = username)
                except:
                    self.result["status"] = "error"
                    self.result["data"]["error"] = "no user named %s"%username
                else:
                    db_password = loginUser.password
                    if password == db_password:
                        self.result["status"] = "success"
                        self.result["data"]["token"] = "201314"
                    else:
                        self.result["status"] = "success"
                        self.result["data"]["token"] = "%s's password is wrong"%username
            else:
                self.result["status"] = "error"
                self.result["data"]["error"] = "no method named %s"%postData
            return JsonResponse(self.result)


    def get(self, request):
        """
        處理get請求
        """
        if request.GET:
            getData = request.GET.get("key")
            return HttpResponse(getData)

在我們真正的代碼實現過程當中,我們登錄成功需要幹兩件事情

  1. 生成token

我們採用 用戶名+當前時間戳進行hash MD5加密的方法生成token

  1. 保存token到數據庫,然後下發token
class Api(View):
    def __init__(self,**kwargs):
        pass
    def post(self,request):
        pass

    def get(self,request):
        pass

    def makeToken(self, username):
        """
         我們採用 用戶名+當前時間戳進行hash MD5加密的方法生成token:
        """
        time_stamp = str(time.time())  # 獲取了當前時間的時間戳,並轉化爲字符串
        value = username + time_stamp  # 進行用戶名和字符串類型的時間戳的拼接
        # md5加密,並返回
        md5 = hashlib.md5()
        md5.update(value.encode())
        token = md5.hexdigest()
        return token

我們來看一下token的使用,我們藉助服務器信息註冊來使用一下token

Token使用,我們實際上使用的是一種校驗的方法

class Api(View):
    def __init__(self,**kwargs):
        pass
    def post(self,request):
        pass

    def get(self,request):
        pass

    def makeToken(self, username):
        pass
    def tokenValid(self,token):
        """
        校驗token
        """
        try:
            db_token = APIToken.objects.get(value = token)
        except:
            return "token error"
        else:
            # 從數據庫取出的時間轉換爲時間戳
            db_time_tuple = db_token.time.timetuple() #轉換時間的格式爲元組格式
            db_time_stamp = time.mktime(db_time_tuple) #講元組格式的時間轉換爲時間戳
            # 當前的時間轉換爲時間戳
            now_time_tuple = datetime.datetime.now().timetuple()  # 轉換時間的格式爲元組格式
            now_time_stamp = time.mktime(now_time_tuple)  # 講元組格式的時間轉換爲時間戳

            if 0 < now_time_stamp - db_time_stamp < 3600: #秒
                return "ok"
            else:
                db_token.delete()
                return "time out"

我們來編寫服務器註冊的案例

import time
import json
import hashlib
import datetime

from django.views.generic import View
from django.http import JsonResponse,HttpResponse

from Service.models import LoginUser,Service,APIToken


class API(View):
    def __init__(self,**kwargs):
        View.__init__(self,**kwargs)
        self.result = {
            "status": "",
            "data": {}
        }

    def post(self,request):
        """
        處理post請求
        """
        if request.POST:
            post_type = request.POST.get("type") #獲取類型
            postData = json.loads(request.POST.get("data"))  # 獲取登錄數據,這裏獲取的是提交的json字符串
            if post_type == "user_login":
                username = postData.get("username") #獲取接口提交的用戶名
                password = postData.get("password") #獲取接口提交的密碼
                try:
                    loginUser = LoginUser.objects.get(username = username)
                except:
                    self.result["status"] = "error"
                    self.result["data"]["error"] = "no user named %s"%username
                else:
                    db_password = loginUser.password
                    if password == db_password:
                        token = self.makeToken(username) #調用方法生成token
                        #將token存入數據庫
                        db_token = APIToken() #實例化api token數據模型,傳入值
                        db_token.value = token
                        db_token.time = datetime.datetime.now()
                        db_token.user_id = loginUser.id #這裏調用上面登錄時候的用戶id進行token對應
                        db_token.save()

                        self.result["status"] = "success"
                        self.result["data"]["token"] = token
                    else:
                        self.result["status"] = "success"
                        self.result["data"]["token"] = "%s's password is wrong"%username
            elif post_type == "addServer":
                if postData:
                    postToken = request.POST.get("token")
                    if postToken and self.tokenValid(postToken) == "ok":
                        #獲取數據
                        ip = postData.get("ip")
                        mac = postData.get("mac")
                        cpu = postData.get("cpu")
                        memory = postData.get("memory")
                        hostname = postData.get("hostname")
                        #保存數據
                        server = Service()
                        server.ip = ip
                        server.mac = mac
                        server.cpu = cpu
                        server.memory = memory
                        server.hostname = hostname
                        server.isalive = "false"
                        server.save()
                        self.result["status"] = "success"
                        self.result["data"]["result"] = "save success"
                    else:
                        self.result["status"] = "error"
                        self.result["data"]["error"] = "token error"
                else:
                    self.result["status"] = "error"
                    self.result["data"]["error"] = "data error"

            else:
                self.result["status"] = "error"
                self.result["data"]["error"] = "no method named %s"%postData
            return JsonResponse(self.result)


    def get(self, request):
        """
        處理get請求
        """
        if request.GET:
            getData = request.GET.get("key")
            return HttpResponse(getData)

    def makeToken(self,username):
        """
         我們採用 用戶名+當前時間戳進行hash MD5加密的方法生成token:
        """
        time_stamp = str(time.time()) #獲取了當前時間的時間戳,並轉化爲字符串
        value = username + time_stamp #進行用戶名和字符串類型的時間戳的拼接
        #md5加密,並返回
        md5 = hashlib.md5()
        md5.update(value.encode())
        token = md5.hexdigest()
        return token
    def tokenValid(self,token):
        """
        校驗token
        """
        try:
            db_token = APIToken.objects.get(value = token)
        except:
            return "token error"
        else:
            # 從數據庫取出的時間轉換爲時間戳
            db_time_tuple = db_token.time.timetuple() #轉換時間的格式爲元組格式
            db_time_stamp = time.mktime(db_time_tuple) #講元組格式的時間轉換爲時間戳
            # 當前的時間轉換爲時間戳
            now_time_tuple = datetime.datetime.now().timetuple()  # 轉換時間的格式爲元組格式
            now_time_stamp = time.mktime(now_time_tuple)  # 講元組格式的時間轉換爲時間戳

            if 0 < now_time_stamp - db_time_stamp < 3600: #秒
                return "ok"
            else:
                db_token.delete()
                return "time out"

請求的腳本:

#!/usr/bin/env python3
#coding:utf-8
import json
import requests

url = "http://192.168.1.32:8000/Api/"
#對發送數據嵌套部分進行json封裝
server_data = json.dumps({
        "ip": "192.169.1.53",
        "mac": "00:01:6C:06:A6:29",
        "cpu": "Intel(R) Core(TM) i7-3632QM CPU @ 2.20GHz",
        "memory": "180000KB",
        "hostname": "saltmaster",
})

data = {
   "type": "addServer",
   "data":  server_data,
   "token": "a97ff61fddb10e52064563952e511bd7"#這裏的token是根據前面的腳本請求得到的token
}

response = requests.post(url,data = data)
result = response.json()
print(result)

實際工作當中,我們請求的代碼會寫出如下

#!/usr/bin/env python3
#coding:utf-8

import json
import requests

class RequestApi:
    def __init__(self,username,password,url):
        self.url = url #傳入地址
        self.request_data = json.dumps({
            "username": username,
            "password": password
        }) #定義了登錄的數據
        self.requestData = {
            "type": "user_login",
            "data": self.request_data,
            "token": ""
        } #定義發送的數據
        self.token = self.request("post").get("data").get("token")

    def request(self,method):
        """
        method是我們用get還是post請求
        """
        #發起請求
        response = requests.request(method,url = self.url,data = self.requestData)
        result = response.json()
        return result
    def addServer(self):
        server_data = json.dumps({
        "ip": "192.169.1.5.",
        "mac": "00:01:6C:06:A6:29",
        "cpu": "Intel(R) Core(TM) i7-3632QM CPU @ 2.20GHz",
        "memory": "180000KB",
        "hostname": "saltmaster",
        })
        self.reqeustData["data"] = server_data
        self.requestData["type"] = "addServer"
        self.requestData["token"] = self.token
        self.request("post")



if __name__ == "__main__":
    url = "http://192.168.1.32:8000/Api/"
    username = "allen"
    password = "123"
    req = RequestApi(username,password,url)
    print(req.token)

效果如下:

當然我們也可以進行批量插入服務器信息,方便後面的Vue分頁使用數據:

#!/usr/bin/env python3
#coding:utf-8

import json
import requests

url = "http://192.168.1.32:8000/Api/"
for i in range(1,101):
    server_data = json.dumps({
        "ip":"192.168.1.%s"%i,
        "mac":"00:0C:29:8B:9A:85",
        "cpu":"Intel(R) Core(TM) i7-7500 CPU @ 3.40GHz",
        "memory":"521314KB",
        "disk":"8888MB"
     })
    data = {
        "type":"addServer",
        "data":server_data,
        "token":"95d1244538e89f5bf91a4e6dd9b6918d"
    }
    response = requests.post(url,data = data)
    result = response.json()
    print(result)

效果如下:

上面的信息中在存入數據庫時打錯了字段名稱,所以disk字段沒有信息,修改後正常存入信息 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章