前戏:项目目的
是一个运维自动化管理项目:
为了减少人工干预,降低人员成本
---
资产管理
--操作管理
避免人员直接操作服务器,使用后台去统一操作
一:实现方式
(一)Agent基于shell命令实现(在服务器去上安装Agent,在服务器本机定时自动去获取信息,发送到数据库,然后后台获取数据进行处理)
注意:一般我们不会直接将数据直接传递到数据库,会将数据传递到API接口先进行处理,过滤,然后才会发送到数据库。
注意:数据是由服务器agent主动发送至API
实现方案:
本地执行cmd命令。
方法一:os.system("命令") 不可以返回数据
方法二:subprocess模块,使用进程执行命令,可以获取到数据Popen("命令"),进程.stdout.read()<py2>或者直接getoutput("命令")<py3>
def agent(self,cmd):
import subprocess
try:
ret =
subprocess.getoutput(cmd)
except AttributeError:
sub = subprocess.Popen(args=cmd,shell=True,stdout=
subprocess.PIPE)
sub.wait()
ret =
sub.stdout.read()
return ret
python实现agent
优点:信息采集快,由服务器自己采集信息传递到API
缺点:每台服务器都必须安装Agent
(二)SSH方法:使用paramiko模块,通过中控机服务器统一去获取指定服务器的信息。
paramiko模块了解
def ssh(self,cmd):
import paramiko
#1.创建SSH对象
ssh =
paramiko.SSHClient()
#2.加上这句话不用担心选yes的问题,会自动选上
#3.用ssh连接远程主机时,第一次连接时会提示是否继续进行远程连接,选择yes
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=
"远程主机名",port=
"远程端口",username=
"用户名",password=
"密码")
#执行命令,获取结果到标准输入\出\错误流中
stdin,stdout,stderr =
ssh.exec_command(cmd)
#4.获取命令结果
result =
stdout.read()
#5.关闭连接
ssh.close()
paramiko实现远程命令执行(方法一:使用用户名,密码)
def ssh(self,cmd):
import paramiko
#1.创建SSH对象
ssh =
paramiko.SSHClient()
#2.加上这句话不用担心选yes的问题,会自动选上
#用ssh连接远程主机时,第一次连接时会提示是否继续进行远程连接,选择yes
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#3.获取私钥
private_key = paramiko.RSAKey.from_private_key_file(
"文件:其中保存了私钥,用于解密")
#4.通过私钥去连接远程服务器(前提是自己的公钥已经在对方的authorized_keys文件中,paramiko已实现)
ssh.connect(hostname=
"远程主机名",port=
"远程端口",username=
"用户名",pkey=
"私钥private_key")
#5.执行命令,获取结果到标准输入\出\错误流中
stdin,stdout,stderr =
ssh.exec_command(cmd)
#6.获取命令结果
result =
stdout.read()
#7.关闭连接
ssh.close()
return result
paramiko使用私钥去登录远程服务器执行命令
优点:不需要为服务器安装agent等软件
缺点:速度慢,适用于服务器少得时候
(三)saltstack:使用master对slave进行操作,基于列队实现(使用广)
#
1. 安装saltstack
# rpm --import https:
//repo.saltstack.com/yum/redhat/6/x86_64/latest/SALTSTACK-GPG-KEY.pub
#
#
"""
Master: yum install salt-
master
Master准备:
a. 配置文件,监听本机IP
vim /etc/salt/
master
interface: 本机IP地址
b. 启动master
/etc/init.d/salt-
master start
Slave: yum install salt-
minion
Slave准备:
a. 配置文件,连接那个master
vim /etc/salt/
minion
master: 远程master地址
b. 启动slave
/etc/init.d/salt-
minion start
2. 创建关系
查看
Master:salt-key -
L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
c1.com
c2.com
c3.com
Rejected Keys:
接受
Master:salt-key -
a c1.com
Accepted Keys:
c1.com
c2.com
Denied Keys:
Unaccepted Keys:
c3.com
Rejected Keys:
3. 执行命令
master:
salt 'c1.com' cmd.run
'ifconfig'
import salt.client
local =
salt.client.LocalClient()
result = local.cmd(
'c2.salt.com',
'cmd.run', [
'ifconfig'])
"""
saltstack安装
def salt(self,cmd):
import subprocess
result = subprocess.getoutput(
"Salt '主机名' cmd.run '"+cmd+
"'")
return result
中控机执行命令:subprocess执行salt
def salt(self,cmd):
import salt.client
local =
salt.client.LocalClient()
result = local.cmd(self.hostname,
'cmd.run',[cmd])
return result[self.hostname]
中控机执行命令:salt.client
优点:快,开发成本低
缺点:依赖saltstack
(四)使用puppet(使用ruby写的,python不易扩展)
优点:自动汇报
缺点:ruby实现
二:代码实现(客户端)
bin目录(含启动文件)
from src.script import client
import os,sys
BASEDIR =
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASEDIR)
if __name__ ==
"__main__":
client()
start.py启动文件
conf目录(含配置文件)
import os
BASEDIR =
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MODE =
"Agent" #SSH Salt
PLUGINS =
{
'basic':
'src.plugins.basic.BasicPlugin',
'disk':
'src.plugins.disk.DiskPlugin',
'mem':
'src.plugins.mem.MemPlugin',
# 'nic':
'src.plugins.nic.NicPlugin',
}
# 如果采用SSH方式,则需要配置SSH的KEY和USER
SSH_PRIVATE_KEY =
"/home/auto/.ssh/id_rsa"
SSH_USER =
"root"
SSH_PORT =
22
# 用于API认证的KEY
KEY =
'299095cc-1330-11e5-b06a-a45e60bec08b'
# 用于API认证的请求头
AUTH_KEY_NAME =
'auth-key'
ASSET_API =
"http://127.0.0.1:8000/API/asset"
# Agent模式保存服务器唯一ID的文件
CERT_FILE_PATH = os.path.join(BASEDIR,
'conf',
'cert')
TEST_MODE = True
setting.py
...
cert含有主机名信息
lib目录(含有链接库)
class BaseResponse(
object):
def __init__(self):
self.status =
True
self.message =
None
self.data =
None
self.error = None
response.py定义一种数据格式用于在客户端传递
import json
as default_json
from .response import BaseResponse
def conv(obj):
return obj.__dict__
class Json(
object):
@staticmethod
def dumps(response):
return default_json.dumps(response,
default=conv)
serialize.py序列化上面的数据,将其变为可以在网络上传递的数据
log目录(记录日志)
client.py定义多种类,不同的方法与API交互
from conf import setting
from .client import *
def client():
if setting.MODE ==
'Agent': #
"Agent" #SSH Salt
cli =
AutoAgent()
elif setting.MODE ==
"SSH":
cli =
AutoSSH()
elif setting.MODE ==
"Salt":
cli =
AutoSalt()
else:
raise Exception("配置信息出错")
cli.process()
script.py脚本,根据配置文件去选择实例化那种类,执行process方法获取数据
二级目录:plugins目录
from conf import setting
from lib.response import BaseResponse
def pack(hostname=
None):
response =
{}
for k,v
in setting.PLUGINS.items():
file_name,cls_name = v.rsplit(
'.',maxsplit=
1)
pk = __import__(file_name,fromlist=
True)
if hasattr(pk,cls_name):
obj =
getattr(pk,cls_name)()
response[k] =
obj.execute(hostname)
return response
__init__.py定义pack方法去依次获取数据
from conf import setting
class BasePlugin(
object):
def __init__(self):
mode_list = [
'Agent',
'Salt',
'SSH']
self.mode =
setting.MODE
if self.mode not
in mode_list:
raise Exception("请选择正确的管理模式")
def shell_cmd(self,cmd):
if self.mode ==
"SSH":
ret =
self.ssh(cmd)
elif self.mode ==
"Salt":
ret =
self.salt(cmd)
else:
ret =
self.agent(cmd)
return ret
def execute(self,hostname=
None):
self.hostname =
hostname
#windows:systeminfo详细信息 ver版本号 linux:cat /etc/issue |
grep Linux
sys_ver = self.shell_cmd(
"ver")
pat =
"command not found"
if pat
in sys_ver: #是linux...还是继续判断吧,应该不需要了
sys_ver = self.shell_cmd(
"head -n 1 /etc/issue")
if "Linux" in sys_ver:
return self.linux()
elif "Windows" in sys_ver:
return self.windows()
else:
raise Exception("只支持linux和windows平台")
def linux(self):
raise Exception("请重载linux函数")
def windows(self):
raise Exception("请实现windows方法")
def write(self,output):
import os
with open(os.path.join(setting.BASEDIR,'file',
"test.txt"),
"w")
as fp:
fp.write(output)
def agent(self,cmd):
import subprocess
try:
ret =
subprocess.getoutput(cmd)
except AttributeError:
sub = subprocess.Popen(args=cmd,shell=True,stdout=
subprocess.PIPE)
sub.wait()
ret =
sub.stdout.read()
return ret
def salt(self,cmd):
import subprocess
result = subprocess.getoutput(
"Salt '主机名' cmd.run '"+cmd+
"'")
return result
# import salt.client
# local =
salt.client.LocalClient()
# result = local.cmd(self.hostname,
'cmd.run',[cmd])
# return result[self.hostname]
def ssh(self,cmd):
import paramiko
ssh =
paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
private_key = paramiko.RSAKey.from_private_key_file(
"文件:其中保存了私钥,用于解密")
ssh.connect(hostname=
"远程主机名",port=
"远程端口",username=
"用户名",pkey=
"私钥private_key")
stdin,stdout,stderr =
ssh.exec_command(cmd)
result =
stdout.read()
ssh.close()
return result
base.py定义基类,实现部分方法
from .
base import BasePlugin
import re
from conf import setting
import traceback
from lib.response import BaseResponse
class BasicPlugin(BasePlugin):
def __init__(self):
super(BasicPlugin, self).__init__()
self.Basic_data =
{} # 存放我们获取的数据
def windows(self):
response =
BaseResponse()
try:
# 获取主机名
output = self.shell_cmd(
"hostname")
self.Basic_data['hostname'] =
output
output = self.shell_cmd(
"ver")
#获取操作平台
ret = re.search(
"(.*)\s*\[",output)
if ret:
self.Basic_data['os_platform'] = ret.group(
1)
# 获取系统版本
ret = re.search(
"\[(.*)\]",output)
if ret:
self.Basic_data['os_version'] = ret.group(
1)
response.data =
self.Basic_data
except Exception as e:
msg =
"%s window memory plugins error: %s"
response.status =
False
response.error = msg %
(self.hostname, traceback.format_exc()) # traceback.format_exc()返回前面错误的信息
return response
def linux(self):
# 获取返回的字符串
output = self.shell_cmd(
"查看硬盘")
# 进行正则匹配,放入Mem_data中
return self.Basic_data
basic.py获取主板信息
from .
base import BasePlugin
from conf import setting
import re,traceback
from lib.response import BaseResponse
class DiskPlugin(BasePlugin):
def __init__(self):
super(DiskPlugin, self).__init__()
self.Disk_data = {
'Slot':
'slot',
'Raw Size':
'capacity',
'Inquiry':
'model',
'PD Type':
'pd_type'}
def windows(self):
response =
BaseResponse()
try:
if setting.TEST_MODE ==
True:
import os
with open(os.path.join(setting.BASEDIR,'file',
'disk.out'),
"r")
as fp:
output =
fp.read()
else:
# 获取返回的字符串
output = self.shell_cmd(
"wmic logicaldisk")
response.data =
self.parse(output)
except Exception as e:
msg =
"%s window disk plugin error: %s"
response.status =
False
response.error = msg %
(self.hostname,traceback.format_exc()) #traceback.format_exc()返回前面错误的信息
return response
def linux(self):
# 获取返回的字符串
output = self.shell_cmd(
"查看硬盘")
# 进行正则匹配,放入Mem_data中
return self.Disk_data
def parse(self,content):
response =
{}
result =
[] #模拟多台 使用4个\n分割
for row_line
in content.split(
"\n\n\n\n"):
result.append(row_line)
for item
in result:
temp_dict =
{}
for row
in item.split(
'\n'):
if not row.strip():
continue
if len(row.split(
":")) !=
2:
continue
key,val = row.split(
":")
name =
self.patter_match(key)
if name:
if key ==
'Raw Size':
val = re.search(
"(\d+\.\d+)",val.strip())
if not val:
val =
0
else:
val = val.group(
1)
temp_dict[name] =
val
if temp_dict:
response[temp_dict['slot']] =
temp_dict
return response
def patter_match(self,key):
for k,v
in self.Disk_data.items():
if key.startswith(k):
return v
return False
disk.py获取硬盘信息
from .
base import BasePlugin
from conf import setting
import traceback
from lib.response import BaseResponse
class MemPlugin(BasePlugin):
def __init__(self):
super(MemPlugin, self).__init__()
self.Mem_data =
{
'Size':
'capacity',
'Locator':
'slot',
'Type':
'model',
'Speed':
'speed',
'Manufacturer':
'manufacturer',
'Serial Number':
'sn',
}
def windows(self):
response =
BaseResponse()
try:
if setting.TEST_MODE ==
True:
import os
with open(os.path.join(setting.BASEDIR, 'file',
'memory.out'),
"r")
as fp:
output =
fp.read()
else:
# 获取返回的字符串
output = self.shell_cmd(
"wmic memorychip")
response.data =
self.parse(output)
except Exception as e:
msg =
"%s window memory plugins error: %s"
response.status =
False
response.error = msg %
(self.hostname, traceback.format_exc()) # traceback.format_exc()返回前面错误的信息
return response
def linux(self):
# 获取返回的字符串
output = self.shell_cmd(
"查看内存")
# 进行正则匹配,放入Mem_data中
return self.Mem_data
def parse(self,content):
response =
{}
result =
[] #模拟多台 使用4个\n分割
for row_line
in content.split(
"Memory Device"):
result.append(row_line)
for item
in result:
for row
in item.split(
'\n\t'):
if not row.strip():
continue
if len(row.split(
":")) !=
2:
continue
key,val = row.split(
":")
name =
self.patter_match(key)
if name:
response[name] =
val
return response
def patter_match(self,key):
for k,v
in self.Mem_data.items():
if key.startswith(k):
return v
return False
mem.py获取内存信息
file文件目录(含有测试的文件,文件包含各种命令下的数据)
Enclosure Device ID:
32
Slot Number: 0
Drive's postion: DiskGroup: 0, Span: 0, Arm: 0
Enclosure position:
0
Device Id: 0
WWN: 5000C5007272C288
Sequence Number: 2
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SAS
Raw Size: 279.396 GB [
0x22ecb25c Sectors]
Non Coerced Size: 278.896 GB [
0x22dcb25c Sectors]
Coerced Size: 278.875 GB [
0x22dc0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: LS08
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x5000c5007272c289
SAS Address(1):
0x0
Connected Port Number: 0(path0)
Inquiry Data: SEAGATE ST300MM0006 LS08S0K2B5NV
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Hard Disk Device
Drive Temperature :29C (84.20 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Port-
1 :
Port status: Active
Port's Linkspeed: Unknown
Drive has flagged a S.M.A.R.T alert : No
Enclosure Device ID: 32
Slot Number: 1
Drive's postion: DiskGroup: 0, Span: 0, Arm: 1
Enclosure position:
0
Device Id: 1
WWN: 5000C5007272DE74
Sequence Number: 2
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SAS
Raw Size: 279.396 GB [
0x22ecb25c Sectors]
Non Coerced Size: 278.896 GB [
0x22dcb25c Sectors]
Coerced Size: 278.875 GB [
0x22dc0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: LS08
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x5000c5007272de75
SAS Address(1):
0x0
Connected Port Number: 0(path0)
Inquiry Data: SEAGATE ST300MM0006 LS08S0K2B5AH
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Hard Disk Device
Drive Temperature :29C (84.20 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Port-
1 :
Port status: Active
Port's Linkspeed: Unknown
Drive has flagged a S.M.A.R.T alert : No
Enclosure Device ID: 32
Slot Number: 2
Drive's postion: DiskGroup: 1, Span: 0, Arm: 0
Enclosure position:
0
Device Id: 2
WWN: 50025388A075B731
Sequence Number: 2
Media Error Count: 0
Other Error Count: 1158
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SATA
Raw Size: 476.939 GB [
0x3b9e12b0 Sectors]
Non Coerced Size: 476.439 GB [
0x3b8e12b0 Sectors]
Coerced Size: 476.375 GB [
0x3b8c0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: 1B6Q
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x500056b37789abee
Connected Port Number: 0(path0)
Inquiry Data: S1SZNSAFA01085L Samsung SSD 850 PRO 512GB EXM01B6Q
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Solid State Device
Drive: Not Certified
Drive Temperature :25C (77.00 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Drive
's NCQ setting : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Drive has flagged a S.M.A.R.T alert : No
Enclosure Device ID: 32
Slot Number: 3
Drive's postion: DiskGroup: 1, Span: 0, Arm: 1
Enclosure position:
0
Device Id: 3
WWN: 50025385A02A074F
Sequence Number: 2
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SATA
Raw Size: 476.939 GB [
0x3b9e12b0 Sectors]
Non Coerced Size: 476.439 GB [
0x3b8e12b0 Sectors]
Coerced Size: 476.375 GB [
0x3b8c0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: 6B0Q
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x500056b37789abef
Connected Port Number: 0(path0)
Inquiry Data: S1AXNSAF912433K Samsung SSD 840 PRO Series DXM06B0Q
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Solid State Device
Drive: Not Certified
Drive Temperature :28C (82.40 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Drive
's NCQ setting : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Drive has flagged a S.M.A.R.T alert : No
Enclosure Device ID: 32
Slot Number: 4
Drive's postion: DiskGroup: 1, Span: 1, Arm: 0
Enclosure position:
0
Device Id: 4
WWN: 50025385A01FD838
Sequence Number: 2
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SATA
Raw Size: 476.939 GB [
0x3b9e12b0 Sectors]
Non Coerced Size: 476.439 GB [
0x3b8e12b0 Sectors]
Coerced Size: 476.375 GB [
0x3b8c0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: 5B0Q
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x500056b37789abf0
Connected Port Number: 0(path0)
Inquiry Data: S1AXNSAF303909M Samsung SSD 840 PRO Series DXM05B0Q
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Solid State Device
Drive: Not Certified
Drive Temperature :27C (80.60 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Drive
's NCQ setting : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Drive has flagged a S.M.A.R.T alert : No
Enclosure Device ID: 32
Slot Number: 5
Drive's postion: DiskGroup: 1, Span: 1, Arm: 1
Enclosure position:
0
Device Id: 5
WWN: 50025385A02AB5C9
Sequence Number: 2
Media Error Count: 0
Other Error Count: 0
Predictive Failure Count: 0
Last Predictive Failure Event Seq Number: 0
PD Type: SATA
Raw Size: 476.939 GB [
0x3b9e12b0 Sectors]
Non Coerced Size: 476.439 GB [
0x3b8e12b0 Sectors]
Coerced Size: 476.375 GB [
0x3b8c0000 Sectors]
Firmware state: Online, Spun Up
Device Firmware Level: 6B0Q
Shield Counter: 0
Successful diagnostics completion on : N/
A
SAS Address(0):
0x500056b37789abf1
Connected Port Number: 0(path0)
Inquiry Data: S1AXNSAFB00549A Samsung SSD 840 PRO Series DXM06B0Q
FDE Enable: Disable
Secured: Unsecured
Locked: Unlocked
Needs EKM Attention: No
Foreign State: None
Device Speed: 6.0Gb/
s
Link Speed: 6.0Gb/
s
Media Type: Solid State Device
Drive: Not Certified
Drive Temperature :28C (82.40 F)
PI Eligibility: No
Drive is formatted
for PI information: No
PI: No PI
Drive's write cache : Disabled
Drive
's NCQ setting : Disabled
Port-
0 :
Port status: Active
Port's Linkspeed: 6.0Gb/s
Drive has flagged a S.M.A.R.T alert : No
Exit Code: 0x00
disk.out
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: 1024 MB
Form Factor: DIMM
Set: None
Locator: DIMM #0
Bank Locator: BANK #0
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #1
Bank Locator: BANK #1
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #2
Bank Locator: BANK #2
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #3
Bank Locator: BANK #3
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #4
Bank Locator: BANK #4
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #5
Bank Locator: BANK #5
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #6
Bank Locator: BANK #6
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
Memory Device
Total Width: 32 bits
Data Width: 32 bits
Size: No Module Installed
Form Factor: DIMM
Set: None
Locator: DIMM #7
Bank Locator: BANK #7
Type: DRAM
Type Detail: EDO
Speed: 667 MHz
Manufacturer: Not Specified
Serial Number: Not Specified
Asset Tag: Not Specified
Part Number: Not Specified
Rank: Unknown
memory.out
.....
三:代码实现(API接口Django实现)
API目录
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.http import HttpResponse,JsonResponse
from repository import models
from API import config
from utils import auth
import importlib
import json
class AssetView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **
kwargs):
return super(AssetView, self).dispatch(request, *args, **
kwargs)
@method_decorator(auth.api_auth)
def get(self,request,*args,**
kwargs):
pass
@method_decorator(auth.api_auth)
def post(self,request,*args,**
kwargs):
'''
获取传递的数据,进行添加,修改
:param request:
:param args:
:param kwargs:
:return:1000成功,
1001,接口授权失败,1002数据库中资产不存在
'''
#获取所有信息
# print(request.body.decode('utf-8')) #带转义符的字符串
server_info = json.loads(request.body.decode(
"utf-8"))
# print(server_info) #字符串
server_info =
json.loads(server_info)
#获取主机名
hostname = server_info[
'basic'][
'data'][
'hostname']
ret = {
"code":
1000,
"message":
'[%s]更新完成'%
hostname}
#根据主机名去数据库中获取相关信息
server_obj = models.Server.objects.filter(hostname=hostname).select_related(
'asset').first()
if not server_obj:
ret['code'] =
1002
ret['message'] =
'[%s]资产不存在'
return JsonResponse(ret)
for k,v
in config.PLUGINS_DICT.items():
module_path,cls_name = v.rsplit(
'.',
1)
cls =
getattr(importlib.import_module(module_path),cls_name)
response =
cls.process(server_obj,server_info,None)
if not response.status:
ret['code'] =
1003
ret['message'] =
"[%s]资产更新异常" %
hostname
if hasattr(cls,
'update_last_time'):
cls.update_last_time(server_obj,None)
return JsonResponse(ret)
views.py实现数据处理MBV实现获取数据和发送数据
二级目录service
from repository import models
import traceback,datetime
from utils.response import BaseResponse
from utils.agorithm import *
class HandleBasic(
object):
@staticmethod
def process(server_obj,server_info,user_obj):
response =
BaseResponse()
try:
log_list =
[]
main_board = server_info[
'basic'][
'data']
if main_board[
'os_platform'] !=
server_obj.os_platform:
log_list.append("系统由%s变更为%s"%(server_obj.os_platform,main_board[
'os_platform']))
server_obj.os_platform = main_board[
'os_platform']
if main_board[
'os_version'] !=
server_obj.os_version:
log_list.append("系统由%s变更为%s"%(server_obj.os_version,main_board[
'os_version']))
server_obj.os_version = main_board[
'os_version']
server_obj.save()
if log_list:
models.AssetRecord.objects.create(asset_obj=server_obj.asset,creator=user_obj,content=
';'.join(log_list))
except Exception as e:
response.status =
False
models.ErrorLog.objects.create(asset_obj=server_obj.asset,title=
"basic-run",
content=
traceback.format_exc())
return response
@staticmethod
def update_last_time(server_obj,user_obj):
response =
BaseResponse()
try:
current_date =
datetime.date.today()
server_obj.asset.latest_date =
current_date
server_obj.asset.save()
models.AssetRecord.objects.create(asset_obj=server_obj.asset,creator=user_obj,content=
"资产汇报")
except Exception as e:
response.status =
False
models.ErrorLog.objects.create(asset_obj=server_obj.asset,title=
"basic-run",
content=
traceback.format_exc())
return response
class HandleDisk(
object):
@staticmethod
def process(server_obj,server_info,user_obj):
response =
BaseResponse()
try:
disk_info = server_info[
'disk']
if not disk_info[
'status']:
response.status =
False
models.ErrorLog.objects.create(
asset_obj=
server_obj.asset,
title=
"disk-plugins",
content=disk_info[
'error']
)
return response
client_disk_dict = disk_info[
'data']
#获取服务器下的所有硬盘设备
disk_obj_list = models.Disk.objects.filter(server_obj=
server_obj)
#获取插槽
disk_slots = map(lambda x:x, (item.slot
for item
in disk_obj_list))
update_list = get_intersection(
set(client_disk_dict.keys()),
set(disk_slots))
add_list =
get_exclude(client_disk_dict.keys(),update_list)
del_list =
get_exclude(disk_slots,update_list)
HandleDisk._add_disk(add_list,client_disk_dict,server_obj,user_obj)
HandleDisk._update_disk(update_list,disk_obj_list,client_disk_dict,server_obj,user_obj)
HandleDisk._del_disk(del_list,disk_obj_list,server_obj,user_obj)
except Exception as e:
response.status =
False
models.ErrorLog.objects.create(
asset_obj=
server_obj.asset,
title=
"disk-plugins",
content=
traceback.format_exc()
)
return response
@staticmethod
def _add_disk(add_list,client_disk_dict,server_obj,user_obj):
for item
in add_list:
cur_disk_dict =
client_disk_dict[item]
log_str =
"[新增硬盘]插槽位{slot};容量为{capacity};硬盘类型为{pd_type};型号为{model}".format(**
cur_disk_dict)
cur_disk_dict['server_obj'] =
server_obj
models.Disk.objects.create(**
cur_disk_dict)
models.AssetRecord.objects.create(
asset_obj=server_obj.asset,creator=user_obj,content=
log_str
)
@staticmethod
def _del_disk(del_lsit,disk_objs,server_obj,user_obj):
for item
in disk_objs:
if item.slot
in del_lsit:
log_str =
"[移除硬盘]插槽位{slot};容量为{capacity};硬盘类型为{pd_type};型号为{model}".format(item.__dict__)
item.delete()
models.AssetRecord.objects.create(
asset_obj =
server_obj.asset,
creator =
user_obj,
content =
log_str
)
@staticmethod
def _update_disk(update_list,disk_objs,client_disk_dict,server_obj,user_obj):
for item
in disk_objs:
if item.slot
in update_list:
log_list =
[]
new_model = client_disk_dict[item.slot][
'model']
if item.model !=
new_model:
log_list.append("[更新硬盘]插槽为%s:型号由%s变更为%s"%
(item.slot,item.model,new_model))
item.model =
new_model
new_capacity = client_disk_dict[item.slot][
'capacity']
new_capacity =
float(new_capacity)
if new_capacity !=
item.capacity:
log_list.append("[更新硬盘]插槽为%s:容量由%sGB变更为%sGB"%
(item.slot,item.capacity,new_capacity))
item.capacity =
new_capacity
new_pd_type = client_disk_dict[item.slot][
'pd_type']
if item.pd_type !=
new_pd_type:
log_list.append("[更新硬盘]插槽为%s:类型由%s变更为%s"%
(item.slot,item.pd_type,new_pd_type))
item.pd_type =
new_pd_type
item.save()
if log_list:
models.AssetRecord.objects.create(
asset=
server_obj.asset,
creator=
user_obj,
content=
';'.join(log_list)
)
asset.py资产管理
utils工具目录
import hashlib,time,redis
from CMDBAPI import settings
from django.http import JsonResponse
def api_auth_method(request):
auth_key =
settings.KEY
auth_name =
settings.AUTH_KEY_NAME
auth_data = request.META[
'HTTP_'+
auth_name.upper()]
auth_val,auth_time = str(auth_data).split(
'|')
#1:时间上的验证
if float(auth_time) +
10 <
time.time():
return False
#2:数据是否过期,先从redis获取数据{auth_val:auth_time}
rd = redis.Redis(host=
"localhost",port=
6379)
r_time = rd.
get(auth_val)
if r_time:
return False
#3:验证数据是否被修改
ha = hashlib.md5(auth_key.encode(
"utf-8"))
ha.update(("%s|%s" % (auth_key, auth_time)).encode(
"utf-8"))
encryption =
ha.hexdigest()
if encryption !=
auth_val:
return False
rd.set(auth_val,auth_time)
return True
def api_auth(func):
def inner(request,*args,**
kwargs):
if not api_auth_method(request):
return JsonResponse({
"code":
1001,
"message":
"API授权失败"},json_dumps_params={
'ensure_ascii': False})
return func(request,*args,**
kwargs)
return inner
auth.py权限认证,对传递的数据进行过滤,其中使用redis
def get_intersection(*
args):
'''
获取集合的并集
:param args: set集合
:return: 并集列表
'''
base = args[
0]
result =
base.intersection(*
args)
return list(result)
def get_exclude(total,part):
'''
获取差集
:param total:
:param part:
:return:
'''
result =
[]
for item
in total:
if item
in part:
pass
else:
result.append(item)
return result
agorithm.py处理数据,获取差并集来代表数据更新删除,添加
四:数据库实现
class UserProfile(models.Model):
'''
用户信息
'''
name = models.CharField(
"姓名",max_length=
32)
email = models.EmailField(
"邮箱")
phone = models.CharField(
"座机",max_length=
32)
mobile = models.CharField(
"手机",max_length=
32)
class Meta:
verbose_name_plural =
"用户表"
def __str__(self):
return self.name
class AdminInfo(models.Model):
'''
用户登录管理信息
与用户信息表时一对一关系
'''
user_info = models.OneToOneField(
"UserProfile")
username = models.CharField(
"用户名",max_length=
64)
password = models.CharField(
"密码",max_length=
64)
class Meta:
verbose_name_plural =
"管理员表"
def __str__(self):
return self.user_info.name
class UserGroup(models.Model):
'''
用户组:业务是按照用户组分配,而不是某个人
每个人可以有多个组
每个组有多个人
'''
name = models.CharField(max_length=
32,unique=
True)
users = models.ManyToManyField(
"UserProfile")
class Meta:
verbose_name_plural =
"用户组"
def __str__(self):
return self.name
class BusinessUnit(models.Model):
'''
业务线
'''
name = models.CharField(
"业务线",max_length=
64,unique=
True)
contact = models.ForeignKey(
"UserGroup",verbose_name=
"业务联系人",related_name=
"c") #多个人,所以按组来分配
manager = models.ForeignKey(
"UserGroup",verbose_name=
"系统管理员",related_name=
"m")
class Meta:
verbose_name_plural =
"业务线"
def __str__(self):
return self.name
class IDC(models.Model):
'''
机房信息:楼层和机房
'''
name = models.CharField(
"机房",max_length=
32)
floor = models.IntegerField(
"楼层",
default=
1)
class Meta:
verbose_name_plural =
"机房表"
def __str__(self):
return self.name
class Tag(models.Model):
'''
资产标签:以前是做什么的,web服务器....,一个资产可以有多个标签,一个标签可以有端个资产
'''
name = models.CharField(
"标签",max_length=
32,unique=
True)
class Meta:
verbose_name_plural =
"标签表"
def __str__(self):
return self.name
class Asset(models.Model):
'''
资产信息表,所有资产公共信息(交换机,服务器,防火墙等)
'''
device_type_choices =
(
(1,
"服务器"),
(2,
"交换机"),
(3,
"防火墙"),
)
device_status_choices =
(
(1,
"上架"),
(2,
"在线"),
(3,
"离线"),
(4,
"下架")
)
device_type_id = models.IntegerField(choices=device_type_choices,
default=
1)
device_status_id = models.IntegerField(choices=device_status_choices,
default=
1)
cabinet_num = models.CharField(
"机柜号",max_length=
32,
null=True,blank=
True)
cabinet_order = models.CharField(
"机柜中的序号",max_length=
32,
null=True,blank=
True)
idc = models.ForeignKey(
"IDC",verbose_name=
"IDC机房",
null=True,blank=
True)
business_unit = models.ForeignKey(
"BusinessUnit",verbose_name=
"属于的业务线",
null=True,blank=
True)
tag = models.ManyToManyField(
"Tag")
latest_date = models.DateField(
null=
True)
create_at = models.DateTimeField(auto_now_add=
True)
class Meta:
verbose_name_plural =
"资产表"
def __str__(self):
return "%s-%s-%s" %
(self.idc.name,self.cabinet_num,self.cabinet_order)
class Server(models.Model):
'''
服务器信息:服务器和资产是一对一关系,一个资产下有一个服务器,或者交换机,或者...
'''
asset = models.OneToOneField(
'Asset')
hostname = models.CharField(max_length=
128,unique=
True)
sn = models.CharField(
'SN号',max_length=
64,db_index=
True)
manafacturer = models.CharField(
"制造商",max_length=
64,
null=True,blank=
True)
model = models.CharField(
"型号",max_length=
64,
null=True,blank=
True)
manage_ip = models.GenericIPAddressField(
"管理IP",
null=True,blank=
True)
os_platform = models.CharField(
"系统",max_length=
32,
null=True,blank=
True)
os_version = models.CharField(
"系统版本",max_length=
32,
null=True,blank=
True)
cpu_count = models.IntegerField(
"CPU个数",
null=True,blank=
True)
cpu_physical = models.IntegerField(
"CPU物理个数",
null=True,blank=
True)
cpu_model = models.CharField(
"CPU型号",max_length=
128,
null=True,blank=
True)
create_at = models.DateTimeField(auto_now_add=True,blank=
True)
class Meta:
verbose_name_plural =
"服务器列表"
def __str__(self):
return self.hostname
class NetworkDevice(models.Model):
'''
其他网络设备表,交换机...
'''
asset = models.OneToOneField(
"asset")
management_ip = models.CharField(
"管理IP",max_length=
64,blank=True,
null=
True)
vlan_ip = models.CharField(
"VlanIP",max_length=
64,blank=True,
null=
True)
intranet_ip = models.CharField(
'内网IP', max_length=
128, blank=True,
null=
True)
sn = models.CharField(
'SN号', max_length=
64, unique=
True)
manufacture = models.CharField(verbose_name=u
'制造商', max_length=
128,
null=True, blank=
True)
model = models.CharField(
'型号', max_length=
128,
null=True, blank=
True)
port_num = models.SmallIntegerField(
'端口个数',
null=True, blank=
True)
device_detail = models.CharField(
'设置详细配置', max_length=
255,
null=True, blank=
True)
class Meta:
verbose_name_plural =
"网络设备"
class Disk(models.Model):
'''
硬盘信息
'''
slot = models.CharField(
"插槽位",max_length=
8)
model = models.CharField(
"硬盘类型",max_length=
32)
capacity = models.FloatField(
"磁盘容量GB")
pd_type = models.CharField(
"磁盘类型",max_length=
32)
server_obj = models.ForeignKey(
"Server",related_name=
'disk')
class Meta:
verbose_name_plural =
"硬盘表"
def __str__(self):
return self.slot
class NIC(models.Model):
'''
网卡信息
'''
name = models.CharField(
"网卡名称",max_length=
128)
hwaddr = models.CharField(
"网卡mac地址",max_length=
64)
netmask = models.CharField(max_length=
64)
idaddrs = models.CharField(
"IP地址",max_length=
256)
up = models.BooleanField(
default=
False)
server_obj = models.ForeignKey(
"Server",related_name=
"nic")
class Meta:
verbose_name_plural =
"网卡表"
def __str__(self):
return self.name
class Memory(models.Model):
'''
内存信息表
'''
slot = models.CharField(
"插槽位",max_length=
32)
manafacturer = models.CharField(
"制造商",max_length=
32,
null=True,blank=
True)
model = models.CharField(
"型号",max_length=
64)
capacity = models.FloatField(
"容量",
null=True,blank=
True)
sn = models.CharField(
"内存SN号",max_length=
64,
null=True,blank=
True)
speed = models.CharField(
"速度",max_length=
16,
null=True,blank=
True)
server_obj = models.ForeignKey(
"Server",related_name=
"memory")
class Meta:
verbose_name_plural =
"内存表"
def __str__(self):
return self.slot
class AssetRecord(models.Model):
'''
资产变更记录
'''
asset_obj = models.ForeignKey(
"Asset",related_name=
'ar')
content = models.TextField(
null=
True)
creator = models.ForeignKey(
"UserProfile",
null=True,blank=
True) #creator为空,代表是资产汇报的数据
create_at = models.DateTimeField(auto_now_add=
True)
class Meta:
verbose_name_plural =
"资产记录表"
def __str__(self):
return "%s-%s-%s" %
(self.asset_obj.idc.name, self.asset_obj.cabinet_num, self.asset_obj.cabinet_order)
class ErrorLog(models.Model):
'''
错误日志
'''
asset_obj = models.ForeignKey(
"Asset",
null=True,blank=
True)
title = models.CharField(max_length=
16)
content =
models.TextField()
create_at = models.DateTimeField(auto_now_add=
True)
class Meta:
verbose_name_plural =
"错误日志表"
def __str__(self):
return self.title
数据库表结构
五:后台管理(实现动态编辑数据)
from django.shortcuts import render,HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.db import transaction
from django.views import View
from repository import models
import json,traceback
# Create your views here.
class Assert(View):
def get(self,request,*args,**
kwargs):
return render(request,
"asset.html")
class AssertJson(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **
kwargs):
return super(AssertJson, self).dispatch(request,*args,**
kwargs)
def get(self,request,*args,**
kwargs):
config_list =
[
{
'field': None,
'display': True,
'title':
"选项",
'text': {
'content':
"<input type='checkbox'/>",
'kwargs': {}},
'attrs': {}
},
{
'field':
"id",
'display': False,
'title':
"ID",
'text': {},
'attrs': {}
},
{
'field':
"cabinet_num",
'display':True,
'title':
"机柜号",
'text': {
"content":
"{n}",
"kwargs":{
'n':
"@cabinet_num"}},
'attrs': {
'name':
'cabinet_num',
'origin':
'@cabinet_num',
'edit-able': True,
'edit-type':
'input'}
},
{
'field':
"cabinet_order",
'display': True,
'title':
"机柜位置",
'text':{
"content":
"{n}",
"kwargs":{
'n':
"@cabinet_order"}},
'attrs': {
'name':
'cabinet_order',
'origin':
'@cabinet_order',
'edit-able': True,
'edit-type':
'input'}
},
{
'field':
"device_type_id",
'display': True,
'title':
"资产类型",
'text': {
"content":
"{n}",
"kwargs": {
'n':
"@@device_type_choices"}},
'attrs': {
'name':
'device_type_id',
'origin':
'@device_type_id',
'edit-able': True,
'edit-type':
'select',
'global-name':
'device_type_choices'}
},
{
'field':
"device_status_id",
'display': True,
'title':
"设备状态",
'text': {
"content":
"{n}",
"kwargs": {
'n':
"@@device_status_choices"}},
'attrs': {
'name':
'device_status_id',
'origin':
'@device_status_id',
'edit-able': True,
'edit-type':
'select',
'global-name':
'device_status_choices'}
},
{
'field':
"idc__id",
'display': False,
'title':
"IDC",
'text': {},
'attrs': {}
},
{
'field':
"idc__name",
'display': True,
'title':
"IDC机房",
'text': {
"content":
"{n}",
"kwargs": {
'n':
"@idc__name"}},
'attrs': {
'name':
'idc_id',
'origin':
'@idc__id',
'edit-able': True,
'edit-type':
'select',
'global-name':
'idc_choices'}
},
{
'field': None,
'display': True,
'title':
"操作",
"text":{
"content":
"<a href='/asset.html/{m}'>{n}</a>",
"kwargs":{
'n':
"点击查看",
"m":
"@id"}},
'attrs': {}
},
]
#获取数据库中的数据
req_list =
[]
for item
in config_list:
if item[
'field']:
req_list.append(item['field'])
content = models.Asset.objects.all().values(*
req_list)
content =
list(content)
#获取类型
global_data =
{
'device_type_choices':models.Asset.device_type_choices,
'device_status_choices':models.Asset.device_status_choices,
'idc_choices':list(models.IDC.objects.values_list(
'id',
'name')),
}
response =
{
'table_config':config_list,
'content':content,
'global_data':global_data,
}
return HttpResponse(json.dumps(response))
def put(self,request,*args,**
kwargs):
ret =
{
'status':True,
'message':None,
}
data = json.loads(request.body.decode(
"utf-8"))
try:
with transaction.atomic():
AssetObj =
models.Asset.objects
for item
in data:
AssetObj.filter(id=item[
'id']).update(**
item)
except Exception as e:
ret['status'] =
False
ret['message'] =
traceback.format_exc()
return HttpResponse(json.dumps(ret))
Django后台View视图代码:注意配置数据的格式
<!DOCTYPE html>
<html lang=
"en">
<head>
<meta charset=
"UTF-8">
<title>Title</title>
<link rel=
"stylesheet" href=
"/statics/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<div style=
"width: 1000px;margin: 0 auto;">
<h1>资源列表</h1>
<div
class=
"btn-group" role=
"group">
<button id=
"idCheckAll" type=
"button" class=
"btn btn-default">全选</button>
<button id=
"idReverseAll" type=
"button" class=
"btn btn-default">反选</button>
<button id=
"idCancelAll" type=
"button" class=
"btn btn-default">取消</button>
<button id=
"idEditMode" type=
"button" class=
"btn btn-default">进入编辑模式</button>
<button type=
"button" class=
"btn btn-default">批量删除</button>
<button id=
"idSave" type=
"button" class=
"btn btn-default">保存</button>
<button type=
"button" class=
"btn btn-default">添加</button>
</div>
<table
class=
"table table-bordered">
<thead id=
"table_th"></thead>
<tbody id=
"table_tb"></tbody>
</table>
</div>
</body>
</html>
<script src=
"/statics/js/jquery.js"></script>
<script src=
"/statics/js/nbplugin.js"></script>
<script>
$(function(){
$.NB("/Backend/asset-join.html");
})
</script>
Html前端代码
(function(){
var requestUrl =
null;
/*自定义字符串格式化函数*/
String.prototype.format=
function(kwargs){
var ret=
this.replace(/\{(\w+)\}/
g,function(g,g1){
return kwargs[g1];
})
return ret
}
function bindSave(){
$("#idSave").click(function(){
var postList =
[];
var flag =
false;
//判断是否有数据被修改
//先找到修改过的行
$(
"#table_tb").find(
"tr[has-edit='true']").each(function(){
var temp =
{};
var id = $(
this).attr(
"row-id");
$(this).find(
"td[edit-able='true']").each(function(){
var origin = $(
this).attr(
"origin");
var newVal = $(
this).attr(
"new-val");
if(newVal && newVal !=
origin){
var name = $(
this).attr(
"name");
temp[name] =
newVal;
flag =
true
}
});
//如果被修改过,添加到postList中
if(flag){
temp['id'] =
id;
postList.push(temp);
}
});
if(flag){
$.ajax({
'url':requestUrl,
'type':
'PUT',
//put表示更新数据
'data':JSON.stringify(postList),
'dataType':
"json",
success:function(response){
if(response.status){
alert("更新成功");
init();
}else{
alert("更新失败:"+
response.message);
}
}
})
}
})
}
function bindReverse(){
$("#idReverseAll").click(function(){
var editing = $(
"#idEditMode").hasClass(
"btn-warning");
$("#table_tb").find(
":checkbox").each(function(){
if(editing){
//若是点击了编辑模式,则是需要进入或退出编辑模式
if($(
this).prop(
"checked")){
$tr = $(
this).parents(
"tr");
trOutEditMode($tr);
$(this).prop(
"checked",
false);
}else{
$tr = $(
this).parents(
"tr");
trIntoEditMode($tr);
$(this).prop(
"checked",
true);
}
}else{
//只需要修改复选框按钮状态
$(
this).prop(
"checked",!$(
this).prop(
"checked"));
}
})
})
}
function bindCancelAll(){
$("#idCancelAll").click(function(){
var editing = $(
"#idEditMode").hasClass(
"btn-warning");
$("#table_tb").find(
":checkbox").each(function(){
if(editing){
if($(
this).prop(
"checked")){
$tr = $(
this).parents(
"tr");
trOutEditMode($tr);
$(this).prop(
"checked",
false);
}
}else{
if($(
this).prop(
"checked")){
$(this).prop(
"checked",
false);
}
}
});
});
}
function bindCheckAll() {
$("#idCheckAll").click(function(){
var editing = $(
"#idEditMode").hasClass(
"btn-warning");
if(editing){
$("#table_tb").find(
":checkbox").each(function(){
if($(
this).prop(
"checked")){
//无操作
}
else{
$tr = $(
this).parents(
"tr");
trIntoEditMode($tr);
$(this).prop(
"checked",
true);
}
})
}else{
$("#table_tb").find(
":checkbox").each(function(){
if(!$(
this).prop(
"checked")){
$(this).prop(
"checked",
true);
}
})
}
})
}
function bindCheckBox(){
$("#table_tb").on(
'click',
':checkbox',function(){
if($(
"#idEditMode").hasClass(
"btn-warning")){
var ck = $(
this).prop(
"checked");
$currentTr = $(
this).parents(
"tr");
if(ck){
//进入编辑模式
trIntoEditMode($currentTr);
}else{
//退出编辑模式
trOutEditMode($currentTr);
}
}
})
}
function trIntoEditMode($tr){
$tr.addClass("success");
//添加样式
$tr.attr(
"has-edit",
"true");
//代表进入了编辑模式,传递数据的时候会去看他
$tr.children().each(function(){
var edit_enable = $(
this).attr(
"edit-able");
var edit_type = $(
this).attr(
"edit-type");
if(edit_enable ==
"true"){
if(edit_type ==
"select"){
var global_name = $(
this).attr(
"global-name");
var origin = $(
this).attr(
"origin");
var tag = document.createElement(
'select');
tag.className =
"form-control";
$.each(window[global_name],function(k,v){
var optag = document.createElement(
"option");
optag.setAttribute("value",v[
0]);
optag.innerHTML = v[
1];
tag.append(optag);
});
$(tag).val(origin);
$(this).html(tag);
}else if(edit_type ==
"input"){
var innerText = $(
this).text();
var tag = document.createElement(
"input");
tag.className =
"form-control";
tag.value =
innerText;
$(this).html(tag)
}
}
})
}
function trOutEditMode($tr) {
$tr.removeClass("success");
//添加样式
$tr.children().each(function(){
var edit_enable = $(
this).attr(
"edit-able");
var edit_type = $(
this).attr(
"edit-type");
if(edit_enable ==
"true"){
if(edit_type ==
"select"){
var $
select = $(
this).children().first();
var newId = $
select.val();
var newText = $
select[
0].selectedOptions[
0].text;
$(this).attr(
"new-val",newId);
$(this).html(newText);
}else if(edit_type ==
"input"){
var $input = $(
this).children().first();
var inputValue =
$input.val();
$(this).html(inputValue);
$(this).attr(
"new-val",inputValue);
}
}
})
}
function bindEditMode(){
$("#idEditMode").click(function(){
var editstatus = $(
this).hasClass(
"btn-warning");
if(!
editstatus){
/*进入编辑模式*/
$(this).addClass(
"btn-warning");
$(this).text(
"退出编辑模式");
$("#table_tb").find(
":checked").each(function(){
var $tr = $(
this).parents(
"tr");
trIntoEditMode($tr);
})
}else{
/*退出编辑模式*/
$(this).removeClass(
"btn-warning");
$(this).text(
"进入编辑模式");
$("#table_tb").find(
":checked").each(function(){
var $tr = $(
this).parents(
"tr");
trOutEditMode($tr);
})
}
})
}
function init(){
$("#table_th").empty();
$("#table_tb").empty();
$.ajax({
url:requestUrl,
type:"get",
dataType:"json",
success:function(response){
initGlobal(response.global_data);
initHeader(response.table_config);
intiContent(response.table_config,response.content);
}
})
}
function initGlobal(gloable_data) {
$.each(gloable_data,function(k,v){
window[k] =
v
})
}
function initHeader(table_config){
var tr = document.createElement(
"tr");
$.each(table_config,function(k,v){
if(v.display){
var th = document.createElement(
"th");
th.innerHTML =
v.title;
tr.append(th);
}
})
$("#table_th").append(tr);
}
function intiContent(table_config,content){
$.each(content,function(k,item){
var tr = document.createElement(
"tr");
$.each(table_config,function(k1,tit){
if(tit.display){
var td = document.createElement(
"td");
/*生成文本信息*/
var kwargs = {};
/*将格式化的信息放在该对象中保存,之后我们生成文本信息的时候直接从这里面去取*/
$.each(tit.text.kwargs,function(k2,v2) {
if(v2.substring(
0,
2) ==
"@@"){
var index =
item[tit.field];
var global_name = v2.substring(
2,v2.length);
kwargs[k2] =
getValueFromGlobalByID(global_name,index)
}else if(v2[
0] ==
"@"){
kwargs[k2] = item[v2.substring(
1,v2.length)]
}else{
kwargs[k2] =
v2
}
});
/*设置属性*/
$.each(tit.attrs,function(k3,v3){
if(v3[
0] ==
"@"){
td.setAttribute(k3,item[v3.substring(1,v3.length)])
}else{
td.setAttribute(k3,v3)
}
})
/*内联代码*/
td.innerHTML =
tit.text.content.format(kwargs);
tr.append(td)
}
})
$(tr).attr("row-id",item[
'id'])
$("#table_tb").append(tr)
})
}
function getValueFromGlobalByID(global_name,index){
var ret =
null;
$.each(window[global_name],function(k,v){
if(v[
0] ==
index){
ret = v[
1]
return false
}
})
return ret
}
jQuery.extend({
'NB':function (url){
requestUrl =
url;
init();
bindEditMode();
bindCheckBox();
bindCheckAll();
bindCancelAll();
bindReverse();
bindSave();
},
})
})()
自定义js插件:实现动态获取,编辑数据
六:CMDB项目总结
1. 四种采集资产的方式(掌握3种)
唯一标识的处理(选用主机名<人为定制规则>
,因为其他的也是不具有唯一性,SN码在虚拟机上是一致的)
2. API
API验证(时间验证,同一时间请求过滤,加密密匙)3次验证,(同加密cookie+时间限制+
访问记录)
数据库表设计
3. 后台管理
js自定制插件(前端+后端配置),减少CURD操作
转载于:https://www.cnblogs.com/ssyfj/p/9060367.html