Advertisement
Guest User

Untitled

a guest
Feb 2nd, 2016
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.88 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import paramiko
  4. from argparse import ArgumentParser
  5. from ConfigParser import ConfigParser
  6. from crypt import Crypt
  7. from os import path
  8.  
  9. class NodeMonitor(object):
  10. """
  11. Class for running commands on a remote host using SSH.
  12. """
  13.  
  14. def __init__(self, config, crypt):
  15. """
  16. Constructor. Sets the configuration object and the class for encryption.
  17. :param config: ConfigParser
  18. :param crypt: class for en/decryption of usernames and passwords.
  19. """
  20. self.config = config
  21. self.crypt = crypt
  22.  
  23. def monitor(self, nodefilter, cmdfilter, customcmd, critical):
  24. """
  25. Runs the configured or custom commands on the given or on all configured
  26. nodes.
  27. :param nodefilter: list of nodes [str]
  28. :param cmdfilter: list of command-keys [str]
  29. :param customcmd: custom command str
  30. :param critical: flag for the inclusion of critical commands
  31. """
  32. for node in self.getNodes(nodefilter):
  33. try:
  34. connection = self.connect(
  35. node['host'],
  36. node['user'],
  37. node['pwd']
  38. )
  39. for cmd in self.getCmds(node, cmdfilter, customcmd, critical):
  40. print('\n{}: {}\n'.format(node['host'].upper(), cmd))
  41. try:
  42. self.execute(connection, cmd)
  43. except Exception, e:
  44. print('error. command could not be executed.\n\n{}'
  45. .format(e))
  46. except Exception, e:
  47. print('error.\n\n{}'.format(e))
  48. finally:
  49. connection.close()
  50.  
  51. def connect(self, host, username, password):
  52. """
  53. Establishes a SSH connection.
  54. :param host: hostname str
  55. :param username: username str
  56. :param password: password str
  57. :return paramiko ssh connection
  58. """
  59. username = self.crypt.decrypt(username)
  60. password = self.crypt.decrypt(password)
  61. connection = paramiko.SSHClient()
  62. connection.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  63. connection.connect(host, username=username, password=password)
  64.  
  65. return connection
  66.  
  67. def execute(self, connection, cmd):
  68. """
  69. Executes the given command using the provides paramiko ssh connection.
  70. :param connection: paramiko ssh connection
  71. :param cmd: command str
  72. """
  73. stdin, stdout, stderr = connection.exec_command(cmd)
  74. stdin.close()
  75.  
  76. try:
  77. for line in stdout.readlines():
  78. print(u'{}'.format(line).strip('\n\r'))
  79. for line in stderr.readlines():
  80. print(u'{}'.format(line).strip('\n\r'))
  81. finally:
  82. stdout.close()
  83. stderr.close()
  84.  
  85. def getNodesets(self):
  86. """
  87. Returns configured nodesets.
  88. :return {str: [str]}
  89. """
  90. nodesets = {}
  91. for key, value in self.config.items('DEFAULT'):
  92. if key.startswith('nodeset'):
  93. nodesets[key.split('.')[1]] = value.split()
  94.  
  95. return nodesets
  96.  
  97. def processNodefilter(self, nodefilter):
  98. """
  99. Extends the nodefilter with configured nodesets and converts the list
  100. into a set.
  101. :param nodefilter: list of nodes or nodesets to include [str]
  102. :return set(str)
  103. """
  104. if nodefilter:
  105. nodesets = self.getNodesets()
  106. filtrs = nodefilter[0:]
  107. for filtr in filtrs:
  108. if filtr in nodesets:
  109. nodefilter.extend(nodesets[filtr])
  110.  
  111. nodefilter = set(nodefilter)
  112. else:
  113. nodefilter = set()
  114.  
  115. return nodefilter
  116.  
  117. def getNodes(self, nodefilter=[]):
  118. """
  119. Returns a list of node information (dict).
  120. :param nodefilter: list of nodes or nodesets to include [str]
  121. :return list of node information [{}]
  122. """
  123. nodes = []
  124. nodefilter = self.processNodefilter(nodefilter)
  125. for section in self.config.sections():
  126. if section.startswith('NODE'):
  127. node = {key: value for key, value in self.config.items(section)}
  128. node['key'] = section.replace('NODE', '')
  129. nodeIds = set([node['host'], node['key']])
  130. if not nodefilter or nodeIds & nodefilter:
  131. nodes.append(node)
  132.  
  133. return nodes
  134.  
  135. def doYieldCmd(self, key, critical, cmdfilter=''):
  136. """
  137. :param key: command key to be tested str
  138. :param critical: flag for the inclusion of critical commands
  139. :param cmdfilter: command key str
  140. :return boolean
  141. """
  142. return key.startswith('cmd.{}'.format(cmdfilter)) \
  143. and (critical or not key.endswith('.critical'))
  144.  
  145.  
  146. def getCmds(self, node, cmdfilter=None, customcmd=None, critical=False):
  147. """
  148. Returns a list of commands for the given node.
  149. :param node: node on which the commands should be run
  150. :param cmdfilter: list of command-keys [str]
  151. :param customcmd: custom command str
  152. :param critical: flag for the inclusion of critical commands
  153. :return list of commands [str]
  154. """
  155. cmds = []
  156. items = node.items()
  157. if cmdfilter:
  158. for filtr in cmdfilter:
  159. for key, value in items:
  160. if self.doYieldCmd(key, critical, cmdfilter=filtr):
  161. cmds.append(value)
  162. elif not customcmd:
  163. # no filter or custom command given -> yield all cmds and filter
  164. # by critical or not
  165. cmds = [x[1] for x in filter(
  166. lambda x: self.doYieldCmd(x[0], critical),
  167. items
  168. )
  169. ]
  170.  
  171. if customcmd:
  172. cmds.append(customcmd)
  173.  
  174. return cmds
  175.  
  176. def listConfig(self):
  177. """
  178. Prints a list of available commands for each node.
  179. """
  180. for node in self.getNodes():
  181. print('\n{}: {}'.format(node['key'], node['host'].upper()))
  182. for key, value in node.items():
  183. if key.startswith('cmd.'):
  184. print('{}{}'.format(
  185. key.replace('cmd.', '').ljust(45, '.'), value)
  186. )
  187.  
  188.  
  189. if __name__ == '__main__':
  190.  
  191. argParser = ArgumentParser(description='NodeMonitor - run commands on \
  192. remote hosts')
  193. argParser.add_argument('keyfile', type=str, metavar='KEYFILE',
  194. help='keyfile for decrypting passwords')
  195. argParser.add_argument('-c', '--cmds', nargs='+', type=str, metavar='CMD',
  196. help='run given configured commands')
  197. argParser.add_argument('-C', '--custom', type=str, metavar='CMD',
  198. help='run given custom command')
  199. argParser.add_argument('-n', '--nodes', nargs='+', type=str, metavar='NODE',
  200. help='run commands on given nodes only')
  201. argParser.add_argument('-k', '--critical', action='store_true',
  202. help='allow critical commands')
  203. argParser.add_argument('-l', '--list', action='store_true',
  204. help='list available nodes and commands')
  205. args = vars(argParser.parse_args())
  206.  
  207. config = ConfigParser()
  208. configpath = path.join(path.dirname(__file__), 'nodemonitor.cfg')
  209. config.read(configpath)
  210.  
  211. crypt = Crypt(args['keyfile'])
  212. nodeMonitor = NodeMonitor(config, crypt)
  213.  
  214. if args['list']:
  215. nodeMonitor.listConfig()
  216. else:
  217. nodeMonitor.monitor(args['nodes'], args['cmds'], args['custom'], args['critical'])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement