Advertisement
Guest User

Untitled

a guest
Jan 18th, 2016
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.24 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import base64
  4. import paramiko
  5. from argparse import ArgumentParser
  6. from ConfigParser import ConfigParser
  7. from Crypto.Cipher import AES
  8.  
  9. class NodeMonitor(object):
  10. """
  11. Class for running commands on a remote host using SSH.
  12. """
  13.  
  14. def __init__(self, config, keyfile):
  15. """
  16. Constructor. Sets the configuration object and creates the cipher for
  17. password/user encryption.
  18. :param config: ConfigParser
  19. :param keyfile: path to a file which contains the encryption key
  20. """
  21. self.config = config
  22. with open(keyfile) as KEY:
  23. key = KEY.read()
  24. self.cipher = AES.new(key, AES.MODE_ECB)
  25.  
  26. def monitor(self, nodefilter, commandfilter, customcommand):
  27. """
  28. Runs the configured or custom commands on the given or on all configured
  29. nodes.
  30. :param nodefilter: list of nodes [str]
  31. :param commandfilter: list of command-keys [str]
  32. :param customcommand: custom command str
  33. """
  34. for node in self.getNodes(nodefilter):
  35. try:
  36. connection = self.connect(
  37. node['host'],
  38. node['user'],
  39. node['pwd']
  40. )
  41. for cmd in self.getCommands(node, commandfilter, customcommand):
  42. print('\n{}: {}'.format(node['host'].upper(), cmd))
  43. try:
  44. self.execute(connection, cmd)
  45. except:
  46. print('error. command could not be executed.')
  47. finally:
  48. connection.close()
  49.  
  50. def connect(self, host, username, password):
  51. """
  52. Establishes a SSH connection.
  53. :param host: hostname str
  54. :param username: username str
  55. :param password: password str
  56. :return paramiko ssh connection
  57. """
  58. username = self.decrypt(username)
  59. password = self.decrypt(password)
  60. connection = paramiko.SSHClient()
  61. connection.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  62. connection.connect(host, username=username, password=password)
  63.  
  64. return connection
  65.  
  66. def execute(self, connection, cmd):
  67. """
  68. Executes the given command using the provides paramiko ssh connection.
  69. :param connection: paramiko ssh connection
  70. :param cmd: command str
  71. """
  72. stdin, stdout, stderr = connection.exec_command(cmd)
  73. stdin.close()
  74.  
  75. try:
  76. for line in stdout.readlines():
  77. print(line)
  78. for line in stderr.readlines():
  79. print(line)
  80. finally:
  81. stdout.close()
  82. stderr.close()
  83.  
  84. def getNodes(self, nodefilter=[]):
  85. """
  86. Returns a list of node information (dict).
  87. :param nodefilter: list of nodes to include [str]
  88. :return list of node information [{}]
  89. """
  90. nodes = []
  91. for section in self.config.sections():
  92. if section.startswith('node'):
  93. node = {key: value for key, value in self.config.items(section)}
  94. if not nodefilter or node['host'] in nodefilter:
  95. nodes.append(node)
  96.  
  97. return nodes
  98.  
  99. def getCommands(self, node, cmdfilter=None, customcommand=None):
  100. """
  101. Returns a list of commands for the given node.
  102. :param node: node on which the commands should be run
  103. :param cmdfilter: list of command-keys [str]
  104. :param customcommand: custom command str
  105. :return list of commands [str]
  106. """
  107. cmds = []
  108. items = node.items()
  109. if cmdfilter:
  110. for filtr in cmdfilter:
  111. for key, value in items:
  112. if key.startswith('cmd.{}'.format(filtr)):
  113. cmds.append(value)
  114. elif not customcommand:
  115. cmds = [x[1] for x in filter(lambda x: x[0].startswith('cmd.'), items)]
  116.  
  117. if customcommand:
  118. cmds.append(customcommand)
  119.  
  120. return cmds
  121.  
  122. def listConfig(self):
  123. """
  124. Prints a list of available commands for each node.
  125. """
  126. for node in self.getNodes():
  127. print('\n{}'.format(node['host'].upper()))
  128. for key, value in node.items():
  129. if key.startswith('cmd.'):
  130. print('{}: {}'.format(key.replace('cmd.', ''), value))
  131.  
  132. def encrypt(self, password):
  133. """
  134. Encrypts the given password.
  135. :param password: str
  136. """
  137. print(base64.b64encode(self.cipher.encrypt(password.rjust(32))))
  138.  
  139. def decrypt(self, password):
  140. """
  141. Decrypts the given password.
  142. :param password: str
  143. :return decrypted password str
  144. """
  145. return self.cipher.decrypt(base64.b64decode(password)).strip()
  146.  
  147.  
  148. if __name__ == '__main__':
  149.  
  150. argParser = ArgumentParser(description='NodeMonitor - run commands on \
  151. remote hosts')
  152. argParser.add_argument('key', type=str, metavar='KEY',
  153. help='keyfile for encrypting/decrypting passwords')
  154. argParser.add_argument('-c', '--cmds', nargs='+', type=str, metavar='CMD',
  155. help='run given configured commands')
  156. argParser.add_argument('-C', '--custom', type=str, metavar='CMD',
  157. help='run given custom command')
  158. argParser.add_argument('-e', '--encrypt', type=str, metavar='PWD',
  159. help='encrypt the given password')
  160. argParser.add_argument('-n', '--nodes', nargs='+', type=str, metavar='NODE',
  161. help='run commands on given nodes only')
  162. argParser.add_argument('-l', '--list', action='store_true',
  163. help='list available nodes and commands')
  164. args = vars(argParser.parse_args())
  165.  
  166. config = ConfigParser()
  167. config.read('nodemonitor.cfg')
  168.  
  169. nodeMonitor = NodeMonitor(config, args['key'])
  170.  
  171. if args['list']:
  172. nodeMonitor.listConfig()
  173. elif args['encrypt']:
  174. nodeMonitor.encrypt(args['encrypt'])
  175. else:
  176. nodeMonitor.monitor(args['nodes'], args['cmds'], args['custom'])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement