123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- #!/usr/bin/env python
- '''
- A CLI interface to a remote salt-api instance
- '''
- from __future__ import print_function
- import sys
- import json
- import logging
- from pepper.cli import PepperCli
- from pepper.retcode import PepperRetcode
- from pepper.exceptions import (
- PepperException,
- PepperAuthException,
- PepperArgumentsException,
- )
- try:
- import salt.loader
- import salt.config
- import salt.output
- HAS_SALT = True
- except ImportError:
- HAS_SALT = False
- logger = logging.getLogger(__name__)
- class Pepper(object):
- def __init__(self):
- self.cli = PepperCli()
- if HAS_SALT:
- self.opts = salt.config.client_config(self.cli.options.master)
- else:
- self.opts = {}
- if self.cli.options.output_file is not None:
- self.opts['output_file'] = self.cli.options.output_file
- @property
- def output(self):
- if not hasattr(self, 'modules'):
- self.modules = salt.loader.minion_mods(self.opts)
- try:
- oput = self.modules[self.cli.args[1]].__outputter__
- except (KeyError, AttributeError, TypeError):
- oput = 'nested'
- return oput
- def __call__(self):
- try:
- for exit_code, result in self.cli.run():
- if HAS_SALT and self.opts:
- logger.debug('Use Salt outputters')
- result = json.loads(result)
- # unwrap ret in some cases
- if 'return' in result:
- result = result['return']
- for ret in result:
- if isinstance(ret, dict):
- if self.cli.options.client.startswith('local'):
- for minionid, minionret in ret.items():
- # rest_tornado doesnt return full_return directly
- # it will always be from get_event, so the output differs slightly
- if isinstance(minionret, dict) and 'return' in minionret:
- # version >= 2017.7
- salt.output.display_output(
- {minionid: minionret['return']},
- self.cli.options.output or minionret.get('out', None) or 'nested',
- opts=self.opts
- )
- # cherrypy returns with ret via full_return
- elif isinstance(minionret, dict) and 'ret' in minionret:
- # version >= 2017.7
- salt.output.display_output(
- {minionid: minionret['ret']},
- self.cli.options.output or minionret.get('out', None) or 'nested',
- opts=self.opts
- )
- else:
- salt.output.display_output(
- {minionid: minionret},
- self.cli.options.output or self.output,
- opts=self.opts
- )
- elif 'data' in ret:
- # unfold runners
- outputter = ret.get('outputter', 'nested')
- if isinstance(ret['data'], dict) and 'return' in ret['data']:
- ret = ret['data']['return']
- salt.output.display_output(
- ret,
- self.cli.options.output or outputter,
- opts=self.opts
- )
- else:
- salt.output.display_output(
- {self.cli.options.client: ret},
- self.cli.options.output or ret.get('outputter', 'nested'),
- opts=self.opts
- )
- else:
- salt.output.display_output(
- {self.cli.options.client: ret},
- self.cli.options.output or 'nested',
- opts=self.opts,
- )
- else:
- if self.cli.options.output_file is not None:
- with open(self.cli.options.output_file, 'a') as ofile:
- print(result, file=ofile)
- else:
- print(result)
- if exit_code is not None:
- if exit_code == 0:
- return PepperRetcode().validate(self.cli.options, result)
- return exit_code
- except (PepperException, PepperAuthException, PepperArgumentsException) as exc:
- print('Pepper error: {0}'.format(exc), file=sys.stderr)
- return 1
- except KeyboardInterrupt:
- # TODO: mimic CLI and output JID on ctrl-c
- return 0
- except Exception as e:
- print(e)
- print('Uncaught Pepper error (increase verbosity for the full traceback).', file=sys.stderr)
- logger.debug('Uncaught traceback:', exc_info=True)
- return 1
|