前面讲到使用salt-api获取客户端数据,还有个遗留问题。在主机比较多时如何保证获取的主机不会有重复,比如使用ip来标识主机,如果配置了keepalived的vip,发生ip变动时就会导致获取的数据不是原主机的数据。可以使用salt-minion的id来标识每个主机,由于minion的id必须是唯一的,正好符合我们的要求。
面向对象中python2和3的区别
向下进行前还要先清楚面向对象中python2和3的区别
python2中有经典类和新式类
python3中只有新式类
python2
class A(): #经典类
pass
class B(object): #新式类
pass
python3
class A():
pass
class B(object):
pass
#这两个都是新式类
python2和3类继承也有区别
python2
class D():
def fun(self):
print "this is D"
class C():
def fun(self):
print "this is C"
class B(D):
pass
class A(B,C):
pass
a=A()
a.fun()
类的继承关系如上图。A继承B和C,B又继承自D。
在python2中A、B、C、D四个类都使用经典类。运行会执行D类中的fun方法,输出“this is D”。
a实例化A类,a调用fun方法,A类中没有fun方法就去父类B中找,B类中也没有就会去父类D中找,找到就会执行。
python2经典类查找使用的深度优先。
同样的使用新式类时,跟经典类执行是一样的结果。但是在某些情况下却是不同的。
上边代码稍微改动
class D(object):
def fun(self):
print "this is D"
class C(D):
def fun(self):
print "this is C"
class B(D):
pass
class A(B,C):
pass
a=A()
a.fun()
类的继承关系图如下
运行结果却是“this is C”,类的方法查找采用了广度优先。
a实例化A类,a调用fun方法,A类中没有fun方法就去父类B中找,B类中也没有就会去A的另一个父类C中找,找到就会执行,如果没有才会去更高的父类中查找。
所以新式类会根据不同情况采用深度优先或广度优先。
由于python3中没有了经典类,查找方法跟python2的新式类一样。
模块化获取cmdb的资源
创建一个demo.py文件,代码如下
import importlib
host_info = {
"disk":"fun.hosts.disk.Disk",
"cpu":"fun.hosts.cpu.Cpu",
}
path = host_info.get("disk")
module_path,class_name = path.rsplit(".",maxsplit=1) #从右以“.”切分字符串,只切分一次
module_name = importlib.import_module(module_path) #加载模块,同"from fun.hosts import disk"
info_class = getattr(module_name,class_name) #得到disk.py模块中的Disk类
test = info_class()
test.run()
创建的目录结果如下
disk.py中的代码如下:
class Disk(object):
def run(self):
print("this is disk_class")
执行demo.py就会输出"this is disk_class"。
demo中的代码写了那么多,其实功能跟直接加载模块disk模块差不多
from fun.hosts.disk import Disk
但这样做也有很多好处
1、可以在hosts目录下添加很多py文件,没有文件获取一种系统信息。如cpu.py,mem.py,hostname.py等,这样看起来比较简洁,而且一目了然就知道那个文件是做什么的。
2、代码好维护,方便其他人阅读、修改。
3、方便配置。在demo中的host_info字典中加载这些项目,可以根据需要来选取要获取的信息,不用做过多的更改。
host_info字典可以再单独写到一个文件中,作为配置文件使用。添加或删除某些项,只需要修改这个配置文件就可以。