1.消除硬编码
第一个就是它有硬编码的情况,什么是硬编码,什么是硬编码就是说在代码里面,你用的一些变量它是写死的,比如说我们刚才调用connect APId的时候它的,ip地址端口用户名和密码都是我们写死的,什么192.168.3.106,用户名,密码,如果它的对端的这个端口它变了,或者说是密码用户名一般不会变。它的密码改变我们是不是要去修改代码,如果在实际工作中这样是非常不方便的,而且是有一定风险的,修改代码就意味着它可能是bug产生的边缘。所以说我们最好把这个可配置的代码,和变量分离开来。就是说消除硬编码的一个办法就是让它可配置。
2.异常捕捉
其次就是异常的捕捉,我们可以看到刚开始我们想列了,那个设置hot key机制时候,它调用connect方法,就抛出来一个sshaexception这个异常,但是我们并没有对它进行处理。这样的话就会在 实际的工作中它就非常的不好,甚至是有一些风险,因为不捕获这个异常的话,可能你的代码,就没办法在执行下去了,然后你写了这个软件可能就当掉了实际生产环境下,是一个非常严重的问题。
3.封装
另外就是进行一下封装,我们看到Paramiko它是对这个,它其实就是对ssh协议的一个封装,然而我们在实际的使用Paramiko的过程中,可以针对自己项目的需要。对它进行二次封装,就是说我封装成我们大家,一起,团队的人它更方便的使用它,甚至它可以不知道Paramiko这个的存在,而调用你封装的接口。来进行一个更方便的操作。
那我们就看实际的过程中我们是怎样来解决这几个问题的,首先就是消除硬编码的问题,我们引入另外一个ConfigParser这个库,ConfigParser就是可以把这个配置很方便的读进来。
config = ConfigParser.ConfigParser()
然后它有一个read的API就是读取文件。
那现在我们就一起来建立一个文件,叫做config.ini
[ssh]
host=192.168.3.105
port=22
usr=allen
pwd=123
timeout=1.0
然后我们read这个config.ini
config.read(‘config.ini’)
那么这些硬编码的地方,就可以换成对应的配置
client.connect(hostname= config.get(‘ssh’,’host’), port= config.getint(‘ssh’,’ port’), username= config.get(‘ssh’,’ username’), password= config.get(‘ssh’,’ password’), timeout= config.getfloat(‘ssh’,’ timeout’))
我们可以来运行看一下
这样我们把这些变量给替换成用这个配置来解析出来它实际的值。我们就是用这个ConfigParser来完成的,现在它运行的是非常的好,然后我们就把这些实际的参数给用配置给它隐藏起来,如果将来我们配置一旦更改的时候我们只需要更改这个config.ini就可以,然后我们来看一下,如何进行异常的捕获。
首先这个connect它会抛出这个异常的时候我们其实就应该用Python的try来捕获它,然后用这个except Exception,e:可以把异常给打印出来。
try:
self.client.connect(hostname=self.host, port=self.port, username=self.usr, password=self.pwd, timeout=self.timeout)
return True
except Exception,e:
print e
这个时候呢一旦开启的时候我们记得要把它给close掉。避免造成资源的浪费
self.client.connect(hostname=self.host, port=self.port, username=self.usr, password=self.pwd, timeout=self.timeout)
return True
except Exception,e:
print 'caught ', e
try:
self.client.close()
return False
except:
pass
其实这样的话就把这个,简单的看一下异常的捕获,其实这个地方抛出捕获的时候我们就在这把它给捕获了,其实这个exec_command它也是会抛出异常。
接下来我们就对它进行一个封装,如何封装,封装它是一个面向对象的一个特点,就会面向对象方法的一个特点,所以说我们把一些细节给隐藏起来,怎么隐藏呢,就是通过类。
我们可以新建一个ParamikoClient这个类。
class ParamikoClient:
然后其实我们在它的初始化函数中就可以把config这个文件名给传进来。
def __init__(self, ini_file):
然后就可以进行一些初始化的工作,这个config要变成main自身的变量,这个Client也是变成它的一个成员,这个类的对象的一个成员。
self. config= ConfigParser. ConfigParser ()
self. Config. read(' config.ini ')
self. Client= paramiko.SSHClient()
self. Client= set_missing_host_key_policy(paramiko.AutoAddPolicy())
然后我们还可以,定义它的connect方法,connect方法的时候就可以把这部分全部,拷贝过来。
self.client.connect(hostname=self.host, port=self.port, username=self.usr, password=self.pwd, timeout=self.timeout)
return True
except Exception,e:
print 'caught ', e
try:
self.client.close()
return False
except:
pass
然后最终这样就可以最后我们在封装一个如何执行命令的
def run_command(self, cmd_str):
stdin, stdout, stderr = self.client.exec_command(cmd_str)
for line in stdout:
print line
这样一个类我么我们就做好了我们在用这个类来建立一个ParamikoClient。
client = ParamikoClient('config.ini')
我们调用它的connect方法来接,
client.connect()
然后
client.run_command('date')
它把直接就把这个指令结果输出来了,我们还可以运行一下刚才输的查询远程机器的这个内存信息的指令。
client = ParamikoClient('config.ini')
client.connect()
client.run_command('cat/proc/meminfo')
我们这样就看到到了这个从它编码,到进行一个更优雅实现的这么一个过程。
其实还有一个跟好的做法就是把这个ParamikoClient这个类单独放到一个文件里面,封装性会更好。