Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- import paramiko
- from argparse import ArgumentParser
- from ConfigParser import ConfigParser
- from crypt import Crypt
- from os import path
- class NodeMonitor(object):
- """
- Class for running commands on a remote host using SSH.
- """
- def __init__(self, config, crypt):
- """
- Constructor. Sets the configuration object and the class for encryption.
- :param config: ConfigParser
- :param crypt: class for en/decryption of usernames and passwords.
- """
- self.config = config
- self.crypt = crypt
- def monitor(self, nodefilter, cmdfilter, customcmd, critical):
- """
- Runs the configured or custom commands on the given or on all configured
- nodes.
- :param nodefilter: list of nodes [str]
- :param cmdfilter: list of command-keys [str]
- :param customcmd: custom command str
- :param critical: flag for the inclusion of critical commands
- """
- for node in self.getNodes(nodefilter):
- try:
- connection = self.connect(
- node['host'],
- node['user'],
- node['pwd']
- )
- for cmd in self.getCmds(node, cmdfilter, customcmd, critical):
- print('\n{}: {}\n'.format(node['host'].upper(), cmd))
- try:
- self.execute(connection, cmd)
- except Exception, e:
- print('error. command could not be executed.\n\n{}'
- .format(e))
- except Exception, e:
- print('error.\n\n{}'.format(e))
- finally:
- connection.close()
- def connect(self, host, username, password):
- """
- Establishes a SSH connection.
- :param host: hostname str
- :param username: username str
- :param password: password str
- :return paramiko ssh connection
- """
- username = self.crypt.decrypt(username)
- password = self.crypt.decrypt(password)
- connection = paramiko.SSHClient()
- connection.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- connection.connect(host, username=username, password=password)
- return connection
- def execute(self, connection, cmd):
- """
- Executes the given command using the provides paramiko ssh connection.
- :param connection: paramiko ssh connection
- :param cmd: command str
- """
- stdin, stdout, stderr = connection.exec_command(cmd)
- stdin.close()
- try:
- for line in stdout.readlines():
- print(u'{}'.format(line).strip('\n\r'))
- for line in stderr.readlines():
- print(u'{}'.format(line).strip('\n\r'))
- finally:
- stdout.close()
- stderr.close()
- def getNodesets(self):
- """
- Returns configured nodesets.
- :return {str: [str]}
- """
- nodesets = {}
- for key, value in self.config.items('DEFAULT'):
- if key.startswith('nodeset'):
- nodesets[key.split('.')[1]] = value.split()
- return nodesets
- def processNodefilter(self, nodefilter):
- """
- Extends the nodefilter with configured nodesets and converts the list
- into a set.
- :param nodefilter: list of nodes or nodesets to include [str]
- :return set(str)
- """
- if nodefilter:
- nodesets = self.getNodesets()
- filtrs = nodefilter[0:]
- for filtr in filtrs:
- if filtr in nodesets:
- nodefilter.extend(nodesets[filtr])
- nodefilter = set(nodefilter)
- else:
- nodefilter = set()
- return nodefilter
- def getNodes(self, nodefilter=[]):
- """
- Returns a list of node information (dict).
- :param nodefilter: list of nodes or nodesets to include [str]
- :return list of node information [{}]
- """
- nodes = []
- nodefilter = self.processNodefilter(nodefilter)
- for section in self.config.sections():
- if section.startswith('NODE'):
- node = {key: value for key, value in self.config.items(section)}
- node['key'] = section.replace('NODE', '')
- nodeIds = set([node['host'], node['key']])
- if not nodefilter or nodeIds & nodefilter:
- nodes.append(node)
- return nodes
- def doYieldCmd(self, key, critical, cmdfilter=''):
- """
- :param key: command key to be tested str
- :param critical: flag for the inclusion of critical commands
- :param cmdfilter: command key str
- :return boolean
- """
- return key.startswith('cmd.{}'.format(cmdfilter)) \
- and (critical or not key.endswith('.critical'))
- def getCmds(self, node, cmdfilter=None, customcmd=None, critical=False):
- """
- Returns a list of commands for the given node.
- :param node: node on which the commands should be run
- :param cmdfilter: list of command-keys [str]
- :param customcmd: custom command str
- :param critical: flag for the inclusion of critical commands
- :return list of commands [str]
- """
- cmds = []
- items = node.items()
- if cmdfilter:
- for filtr in cmdfilter:
- for key, value in items:
- if self.doYieldCmd(key, critical, cmdfilter=filtr):
- cmds.append(value)
- elif not customcmd:
- # no filter or custom command given -> yield all cmds and filter
- # by critical or not
- cmds = [x[1] for x in filter(
- lambda x: self.doYieldCmd(x[0], critical),
- items
- )
- ]
- if customcmd:
- cmds.append(customcmd)
- return cmds
- def listConfig(self):
- """
- Prints a list of available commands for each node.
- """
- for node in self.getNodes():
- print('\n{}: {}'.format(node['key'], node['host'].upper()))
- for key, value in node.items():
- if key.startswith('cmd.'):
- print('{}{}'.format(
- key.replace('cmd.', '').ljust(45, '.'), value)
- )
- if __name__ == '__main__':
- argParser = ArgumentParser(description='NodeMonitor - run commands on \
- remote hosts')
- argParser.add_argument('keyfile', type=str, metavar='KEYFILE',
- help='keyfile for decrypting passwords')
- argParser.add_argument('-c', '--cmds', nargs='+', type=str, metavar='CMD',
- help='run given configured commands')
- argParser.add_argument('-C', '--custom', type=str, metavar='CMD',
- help='run given custom command')
- argParser.add_argument('-n', '--nodes', nargs='+', type=str, metavar='NODE',
- help='run commands on given nodes only')
- argParser.add_argument('-k', '--critical', action='store_true',
- help='allow critical commands')
- argParser.add_argument('-l', '--list', action='store_true',
- help='list available nodes and commands')
- args = vars(argParser.parse_args())
- config = ConfigParser()
- configpath = path.join(path.dirname(__file__), 'nodemonitor.cfg')
- config.read(configpath)
- crypt = Crypt(args['keyfile'])
- nodeMonitor = NodeMonitor(config, crypt)
- if args['list']:
- nodeMonitor.listConfig()
- else:
- nodeMonitor.monitor(args['nodes'], args['cmds'], args['custom'], args['critical'])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement