mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 17:33:54 +00:00
114 lines
3.2 KiB
Python
114 lines
3.2 KiB
Python
'''
|
|
Make api awesomeness
|
|
'''
|
|
# Import Python libs
|
|
import inspect
|
|
|
|
# Import Salt libs
|
|
import salt.client
|
|
import salt.runner
|
|
import salt.utils
|
|
from salt.exceptions import SaltException
|
|
|
|
class APIClient(object):
|
|
'''
|
|
Provide a uniform method of accessing the various *Client interfaces in
|
|
Salt in the form of LowData data structures.
|
|
|
|
>>> client = APIClient(__opts__)
|
|
>>> lowdata = {'client': 'local', 'tgt': '*', 'fun': 'test.ping', 'arg': ''}
|
|
>>> client.run(lowdata)
|
|
'''
|
|
def __init__(self, opts):
|
|
self.opts = opts
|
|
|
|
def run(self, low):
|
|
'''
|
|
Execute the specified function in the specified client by passing the
|
|
LowData
|
|
'''
|
|
# FIXME: the called *Client functions must be consistently
|
|
# asynchronous. this will need to be addressed across the board
|
|
|
|
if not 'client' in low:
|
|
raise SaltException('No client specified')
|
|
|
|
l_fun = getattr(self, low['client'])
|
|
f_call = format_call(l_fun, low)
|
|
|
|
ret = l_fun(*f_call.get('args', ()), **f_call.get('kwargs', {}))
|
|
return ret
|
|
|
|
def local(self, *args, **kwargs):
|
|
'''
|
|
Wrap the LocalClient for running execution modules
|
|
'''
|
|
local = salt.client.LocalClient(self.opts['conf_file'])
|
|
return local.cmd(*args, **kwargs)
|
|
|
|
def runner(self, fun, **kwargs):
|
|
'''
|
|
Wrap the RunnerClient for executing runner modules
|
|
'''
|
|
runner = salt.runner.RunnerClient(self.opts)
|
|
return runner.low(fun, kwargs)
|
|
|
|
### Remove when salt 0.10.5 is released!
|
|
def _getargs(func):
|
|
'''
|
|
A small wrapper around getargspec that also supports callable classes
|
|
'''
|
|
if not callable(func):
|
|
raise TypeError('{0} is not a callable'.format(func))
|
|
|
|
if inspect.isfunction(func):
|
|
aspec = inspect.getargspec(func)
|
|
elif inspect.ismethod(func):
|
|
aspec = inspect.getargspec(func)
|
|
del aspec.args[0] # self
|
|
elif isinstance(func, object):
|
|
aspec = inspect.getargspec(func.__call__)
|
|
del aspec.args[0] # self
|
|
else:
|
|
raise TypeError("Cannot inspect argument list for '{0}'".format(func))
|
|
|
|
return aspec
|
|
|
|
def format_call(fun, data):
|
|
'''
|
|
Pass in a function and a dict containing arguments to the function.
|
|
|
|
A dict with the keys args and kwargs is returned
|
|
'''
|
|
ret = {}
|
|
ret['args'] = []
|
|
aspec = _getargs(fun)
|
|
arglen = 0
|
|
deflen = 0
|
|
if isinstance(aspec.args, list):
|
|
arglen = len(aspec.args)
|
|
if isinstance(aspec.defaults, tuple):
|
|
deflen = len(aspec.defaults)
|
|
if aspec.keywords:
|
|
# This state accepts kwargs
|
|
ret['kwargs'] = {}
|
|
for key in data:
|
|
# Passing kwargs the conflict with args == stack trace
|
|
if key in aspec.args:
|
|
continue
|
|
ret['kwargs'][key] = data[key]
|
|
kwargs = {}
|
|
for ind in range(arglen - 1, 0, -1):
|
|
minus = arglen - ind
|
|
if deflen - minus > -1:
|
|
kwargs[aspec.args[ind]] = aspec.defaults[-minus]
|
|
for arg in kwargs:
|
|
if arg in data:
|
|
kwargs[arg] = data[arg]
|
|
for arg in aspec.args:
|
|
if arg in kwargs:
|
|
ret['args'].append(kwargs[arg])
|
|
else:
|
|
ret['args'].append(data[arg])
|
|
return ret
|