mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #18957 from thatch45/basepi-salt-ssh-publish.publish
Merge #18944
This commit is contained in:
commit
c154936b5d
@ -169,14 +169,26 @@ class SSH(object):
|
||||
self.targets = self.roster.targets(
|
||||
self.opts['tgt'],
|
||||
self.tgt_type)
|
||||
priv = self.opts.get(
|
||||
'ssh_priv',
|
||||
os.path.join(
|
||||
self.opts['pki_dir'],
|
||||
'ssh',
|
||||
'salt-ssh.rsa'
|
||||
# If we're in a wfunc, we need to get the ssh key location from the
|
||||
# top level opts, stored in __master_opts__
|
||||
if '__master_opts__' in self.opts:
|
||||
priv = self.opts['__master_opts__'].get(
|
||||
'ssh_priv',
|
||||
os.path.join(
|
||||
self.opts['__master_opts__']['pki_dir'],
|
||||
'ssh',
|
||||
'salt-ssh.rsa'
|
||||
)
|
||||
)
|
||||
else:
|
||||
priv = self.opts.get(
|
||||
'ssh_priv',
|
||||
os.path.join(
|
||||
self.opts['pki_dir'],
|
||||
'ssh',
|
||||
'salt-ssh.rsa'
|
||||
)
|
||||
)
|
||||
)
|
||||
if not os.path.isfile(priv):
|
||||
try:
|
||||
salt.client.ssh.shell.gen_key(priv)
|
||||
@ -399,7 +411,40 @@ class SSH(object):
|
||||
'''
|
||||
Execute and yield returns as they come in, do not print to the display
|
||||
'''
|
||||
fstr = '{0}.prep_jid'.format(self.opts['master_job_cache'])
|
||||
jid = self.returners[fstr]()
|
||||
|
||||
# Save the invocation information
|
||||
argv = self.opts['argv']
|
||||
|
||||
if self.opts['raw_shell']:
|
||||
fun = 'ssh._raw'
|
||||
args = argv
|
||||
else:
|
||||
fun = argv[0] if argv else ''
|
||||
args = argv[1:]
|
||||
|
||||
job_load = {
|
||||
'jid': jid,
|
||||
'tgt_type': self.tgt_type,
|
||||
'tgt': self.opts['tgt'],
|
||||
'user': self.opts['user'],
|
||||
'fun': fun,
|
||||
'arg': args,
|
||||
}
|
||||
|
||||
# save load to the master job cache
|
||||
self.returners['{0}.save_load'.format(self.opts['master_job_cache'])](jid, job_load)
|
||||
|
||||
for ret in self.handle_ssh():
|
||||
host = next(ret.iterkeys())
|
||||
self.cache_job(jid, host, ret[host])
|
||||
if self.event:
|
||||
self.event.fire_event(
|
||||
ret,
|
||||
salt.utils.event.tagify(
|
||||
[jid, 'ret', host],
|
||||
'job'))
|
||||
yield ret
|
||||
|
||||
def cache_job(self, jid, id_, ret):
|
||||
@ -412,7 +457,7 @@ class SSH(object):
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
Execute the overall routine
|
||||
Execute the overall routine, print results via outputters
|
||||
'''
|
||||
fstr = '{0}.prep_jid'.format(self.opts['master_job_cache'])
|
||||
jid = self.returners[fstr]()
|
||||
@ -681,6 +726,7 @@ class Single(object):
|
||||
opts_pkg['ext_pillar'] = self.opts['ext_pillar']
|
||||
opts_pkg['extension_modules'] = self.opts['extension_modules']
|
||||
opts_pkg['_ssh_version'] = self.opts['_ssh_version']
|
||||
opts_pkg['__master_opts__'] = self.context['master_opts']
|
||||
if '_caller_cachedir' in self.opts:
|
||||
opts_pkg['_caller_cachedir'] = self.opts['_caller_cachedir']
|
||||
else:
|
||||
|
208
salt/client/ssh/wrapper/publish.py
Normal file
208
salt/client/ssh/wrapper/publish.py
Normal file
@ -0,0 +1,208 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
.. versionadded:: Lithium
|
||||
|
||||
Salt-ssh wrapper functions for the publish module.
|
||||
|
||||
Publish will never actually execute on the minions, so we just create new
|
||||
salt-ssh calls and return the data from them.
|
||||
|
||||
No access control is needed because calls cannot originate from the minions.
|
||||
'''
|
||||
# Import python libs
|
||||
import copy
|
||||
import logging
|
||||
# Import salt libs
|
||||
import salt.client.ssh
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _publish(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
expr_form='glob',
|
||||
returner='',
|
||||
timeout=None,
|
||||
form='clean',
|
||||
roster=None):
|
||||
'''
|
||||
Publish a command "from the minion out to other minions". In reality, the
|
||||
minion does not execute this function, it is executed by the master. Thus,
|
||||
no access control is enabled, as minions cannot initiate publishes
|
||||
themselves.
|
||||
|
||||
Salt-ssh publishes will default to whichever roster was used for the
|
||||
initiating salt-ssh call, and can be overridden using the ``roster``
|
||||
argument
|
||||
|
||||
Returners are not currently supported
|
||||
|
||||
The arguments sent to the minion publish function are separated with
|
||||
commas. This means that for a minion executing a command with multiple
|
||||
args it will look like this::
|
||||
|
||||
salt-ssh system.example.com publish.publish '*' user.add 'foo,1020,1020'
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh system.example.com publish.publish '*' cmd.run 'ls -la /tmp'
|
||||
'''
|
||||
if fun.startswith('publish.'):
|
||||
log.info('Cannot publish publish calls. Returning {}')
|
||||
return {}
|
||||
|
||||
# TODO: implement returners? Do they make sense for salt-ssh calls?
|
||||
if returner:
|
||||
log.warning('Returners currently not supported in salt-ssh publish')
|
||||
|
||||
# Make sure args have been processed
|
||||
if arg is None:
|
||||
arg = []
|
||||
elif not isinstance(arg, list):
|
||||
arg = [salt.utils.args.yamlify_arg(arg)]
|
||||
else:
|
||||
arg = [salt.utils.args.yamlify_arg(x) for x in arg]
|
||||
if len(arg) == 1 and arg[0] is None:
|
||||
arg = []
|
||||
|
||||
# Set up opts for the SSH object
|
||||
opts = copy.deepcopy(__opts__)
|
||||
if roster:
|
||||
opts['roster'] = roster
|
||||
if timeout:
|
||||
opts['timeout'] = timeout
|
||||
opts['argv'] = [fun] + arg
|
||||
opts['selected_target_option'] = expr_form
|
||||
opts['tgt'] = tgt
|
||||
opts['arg'] = arg
|
||||
|
||||
# Create the SSH object to handle the actual call
|
||||
ssh = salt.client.ssh.SSH(opts)
|
||||
|
||||
# Run salt-ssh to get the minion returns
|
||||
rets = {}
|
||||
for ret in ssh.run_iter():
|
||||
rets.update(ret)
|
||||
|
||||
if form == 'clean':
|
||||
cret = {}
|
||||
for host in rets:
|
||||
if 'return' in rets[host]:
|
||||
cret[host] = rets[host]['return']
|
||||
else:
|
||||
cret[host] = rets[host]
|
||||
return cret
|
||||
else:
|
||||
return rets
|
||||
|
||||
|
||||
def publish(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
expr_form='glob',
|
||||
returner='',
|
||||
timeout=5,
|
||||
roster=None):
|
||||
'''
|
||||
Publish a command "from the minion out to other minions". In reality, the
|
||||
minion does not execute this function, it is executed by the master. Thus,
|
||||
no access control is enabled, as minions cannot initiate publishes
|
||||
themselves.
|
||||
|
||||
|
||||
Salt-ssh publishes will default to whichever roster was used for the
|
||||
initiating salt-ssh call, and can be overridden using the ``roster``
|
||||
argument
|
||||
|
||||
Returners are not currently supported
|
||||
|
||||
The expr_form argument is used to pass a target other than a glob into
|
||||
the execution, the available options are:
|
||||
|
||||
- glob
|
||||
- pcre
|
||||
|
||||
The arguments sent to the minion publish function are separated with
|
||||
commas. This means that for a minion executing a command with multiple
|
||||
args it will look like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh system.example.com publish.publish '*' user.add 'foo,1020,1020'
|
||||
salt-ssh system.example.com publish.publish '127.0.0.1' network.interfaces '' roster=scan
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh system.example.com publish.publish '*' cmd.run 'ls -la /tmp'
|
||||
|
||||
|
||||
.. admonition:: Attention
|
||||
|
||||
If you need to pass a value to a function argument and that value
|
||||
contains an equal sign, you **must** include the argument name.
|
||||
For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh '*' publish.publish test.kwarg arg='cheese=spam'
|
||||
|
||||
Multiple keyword arguments should be passed as a list.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh '*' publish.publish test.kwarg arg="['cheese=spam','spam=cheese']"
|
||||
|
||||
|
||||
|
||||
'''
|
||||
return _publish(tgt,
|
||||
fun,
|
||||
arg=arg,
|
||||
expr_form=expr_form,
|
||||
returner=returner,
|
||||
timeout=timeout,
|
||||
form='clean',
|
||||
roster=roster)
|
||||
|
||||
|
||||
def full_data(tgt,
|
||||
fun,
|
||||
arg=None,
|
||||
expr_form='glob',
|
||||
returner='',
|
||||
timeout=5,
|
||||
roster=None):
|
||||
'''
|
||||
Return the full data about the publication, this is invoked in the same
|
||||
way as the publish function
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh system.example.com publish.full_data '*' cmd.run 'ls -la /tmp'
|
||||
|
||||
.. admonition:: Attention
|
||||
|
||||
If you need to pass a value to a function argument and that value
|
||||
contains an equal sign, you **must** include the argument name.
|
||||
For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-ssh '*' publish.full_data test.kwarg arg='cheese=spam'
|
||||
|
||||
'''
|
||||
return _publish(tgt,
|
||||
fun,
|
||||
arg=arg,
|
||||
expr_form=expr_form,
|
||||
returner=returner,
|
||||
timeout=timeout,
|
||||
form='full',
|
||||
roster=roster)
|
@ -21,6 +21,9 @@ log = logging.getLogger(__name__)
|
||||
def get_roster_file(options):
|
||||
if options.get('roster_file'):
|
||||
template = options.get('roster_file')
|
||||
elif 'config_dir' in options.get('__master_opts__', {}):
|
||||
template = os.path.join(options['__master_opts__']['config_dir'],
|
||||
'roster')
|
||||
elif 'config_dir' in options:
|
||||
template = os.path.join(options['config_dir'], 'roster')
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user