mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
various netapi fixes and tests
This commit is contained in:
parent
bf6c1df4da
commit
f99b6762dd
5 changed files with 171 additions and 1 deletions
|
@ -1299,3 +1299,9 @@
|
|||
# use OS defaults, typically 75 seconds on Linux, see
|
||||
# /proc/sys/net/ipv4/tcp_keepalive_intvl.
|
||||
#tcp_keepalive_intvl: -1
|
||||
|
||||
|
||||
##### NetAPI settings #####
|
||||
############################################
|
||||
# Allow the raw_shell parameter to be used when calling Salt SSH client via API
|
||||
#netapi_allow_raw_shell: True
|
||||
|
|
|
@ -1186,6 +1186,10 @@ VALID_OPTS = immutabletypes.freeze({
|
|||
|
||||
# Thorium top file location
|
||||
'thorium_top': six.string_types,
|
||||
|
||||
# Allow raw_shell option when using the ssh
|
||||
# client via the Salt API
|
||||
'netapi_allow_raw_shell': bool,
|
||||
})
|
||||
|
||||
# default configurations
|
||||
|
@ -1799,6 +1803,7 @@ DEFAULT_MASTER_OPTS = immutabletypes.freeze({
|
|||
'auth_events': True,
|
||||
'minion_data_cache_events': True,
|
||||
'enable_ssh_minions': False,
|
||||
'netapi_allow_raw_shell': False,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -71,10 +71,15 @@ class NetapiClient(object):
|
|||
raise salt.exceptions.SaltInvocationError(
|
||||
'Invalid client specified: \'{0}\''.format(low.get('client')))
|
||||
|
||||
if not ('token' in low or 'eauth' in low) and low['client'] != 'ssh':
|
||||
if not ('token' in low or 'eauth' in low):
|
||||
raise salt.exceptions.EauthAuthenticationError(
|
||||
'No authentication credentials given')
|
||||
|
||||
if low.get('raw_shell') and \
|
||||
not self.opts.get('netapi_allow_raw_shell'):
|
||||
raise salt.exceptions.EauthAuthenticationError(
|
||||
'Raw shell option not allowed.')
|
||||
|
||||
l_fun = getattr(self, low['client'])
|
||||
f_call = salt.utils.args.format_call(l_fun, low)
|
||||
return l_fun(*f_call.get('args', ()), **f_call.get('kwargs', {}))
|
||||
|
|
|
@ -2,17 +2,32 @@
|
|||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.paths import TMP_CONF_DIR, TMP
|
||||
from tests.support.runtests import RUNTIME_VARS
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import patch
|
||||
from tests.support.case import SSHCase
|
||||
from tests.support.helpers import (
|
||||
Webserver,
|
||||
SaveRequestsPostHandler,
|
||||
requires_sshd_server
|
||||
)
|
||||
|
||||
# Import Salt libs
|
||||
import salt.config
|
||||
import salt.netapi
|
||||
|
||||
from salt.exceptions import (
|
||||
EauthAuthenticationError
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NetapiClientTest(TestCase):
|
||||
eauth_creds = {
|
||||
|
@ -74,6 +89,12 @@ class NetapiClientTest(TestCase):
|
|||
pass
|
||||
self.assertEqual(ret, {'minions': sorted(['minion', 'sub_minion'])})
|
||||
|
||||
def test_local_unauthenticated(self):
|
||||
low = {'client': 'local', 'tgt': '*', 'fun': 'test.ping'}
|
||||
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
def test_wheel(self):
|
||||
low = {'client': 'wheel', 'fun': 'key.list_all'}
|
||||
low.update(self.eauth_creds)
|
||||
|
@ -107,6 +128,12 @@ class NetapiClientTest(TestCase):
|
|||
self.assertIn('jid', ret)
|
||||
self.assertIn('tag', ret)
|
||||
|
||||
def test_wheel_unauthenticated(self):
|
||||
low = {'client': 'wheel', 'tgt': '*', 'fun': 'test.ping'}
|
||||
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
@skipIf(True, 'This is not testing anything. Skipping for now.')
|
||||
def test_runner(self):
|
||||
# TODO: fix race condition in init of event-- right now the event class
|
||||
|
@ -125,3 +152,111 @@ class NetapiClientTest(TestCase):
|
|||
low.update(self.eauth_creds)
|
||||
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
def test_runner_unauthenticated(self):
|
||||
low = {'client': 'runner', 'tgt': '*', 'fun': 'test.ping'}
|
||||
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
|
||||
@requires_sshd_server
|
||||
class NetapiSSHClientTest(SSHCase):
|
||||
eauth_creds = {
|
||||
'username': 'saltdev_auto',
|
||||
'password': 'saltdev',
|
||||
'eauth': 'auto',
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
'''
|
||||
Set up a NetapiClient instance
|
||||
'''
|
||||
opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, 'master'))
|
||||
self.netapi = salt.netapi.NetapiClient(opts)
|
||||
|
||||
# Initialize salt-ssh
|
||||
self.run_function('test.ping')
|
||||
|
||||
def tearDown(self):
|
||||
del self.netapi
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
|
||||
cls.post_webserver.start()
|
||||
cls.post_web_root = cls.post_webserver.web_root
|
||||
cls.post_web_handler = cls.post_webserver.handler
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.post_webserver.stop()
|
||||
del cls.post_webserver
|
||||
|
||||
def test_ssh(self):
|
||||
low = {'client': 'ssh', 'tgt': 'localhost', 'fun': 'test.ping'}
|
||||
low.update(self.eauth_creds)
|
||||
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
self.assertIn('localhost', ret)
|
||||
self.assertEqual(ret['localhost']['return'], True)
|
||||
self.assertEqual(ret['localhost']['id'], 'localhost')
|
||||
self.assertEqual(ret['localhost']['fun'], 'test.ping')
|
||||
|
||||
def test_ssh_unauthenticated(self):
|
||||
low = {'client': 'ssh', 'tgt': 'localhost', 'fun': 'test.ping'}
|
||||
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
def test_ssh_unauthenticated_raw_shell_curl(self):
|
||||
|
||||
fun = '-o ProxyCommand curl {0}'.format(self.post_web_root)
|
||||
low = {'client': 'ssh',
|
||||
'tgt': 'localhost',
|
||||
'fun': fun,
|
||||
'raw_shell': True}
|
||||
|
||||
ret = None
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
self.assertEqual(self.post_web_handler.received_requests, [])
|
||||
self.assertEqual(ret, None)
|
||||
|
||||
def test_ssh_unauthenticated_raw_shell_touch(self):
|
||||
|
||||
badfile = os.path.join(TMP, 'badfile.txt')
|
||||
fun = '-o ProxyCommand touch {0}'.format(badfile)
|
||||
low = {'client': 'ssh',
|
||||
'tgt': 'localhost',
|
||||
'fun': fun,
|
||||
'raw_shell': True}
|
||||
|
||||
ret = None
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
self.assertEqual(ret, None)
|
||||
self.assertFalse(os.path.exists('badfile.txt'))
|
||||
|
||||
def test_ssh_authenticated_raw_shell_disabled(self):
|
||||
|
||||
badfile = os.path.join(TMP, 'badfile.txt')
|
||||
fun = '-o ProxyCommand touch {0}'.format(badfile)
|
||||
low = {'client': 'ssh',
|
||||
'tgt': 'localhost',
|
||||
'fun': fun,
|
||||
'raw_shell': True}
|
||||
|
||||
low.update(self.eauth_creds)
|
||||
|
||||
ret = None
|
||||
with patch.dict(self.netapi.opts,
|
||||
{'netapi_allow_raw_shell': False}):
|
||||
with self.assertRaises(EauthAuthenticationError) as excinfo:
|
||||
ret = self.netapi.run(low)
|
||||
|
||||
self.assertEqual(ret, None)
|
||||
self.assertFalse(os.path.exists('badfile.txt'))
|
||||
|
|
|
@ -1526,6 +1526,25 @@ class Webserver(object):
|
|||
self.server_thread.join()
|
||||
|
||||
|
||||
class SaveRequestsPostHandler(tornado.web.RequestHandler):
|
||||
'''
|
||||
Save all requests sent to the server.
|
||||
'''
|
||||
received_requests = []
|
||||
|
||||
def post(self, *args): # pylint: disable=arguments-differ
|
||||
'''
|
||||
Handle the post
|
||||
'''
|
||||
self.received_requests.append(self.request)
|
||||
|
||||
def data_received(self): # pylint: disable=arguments-differ
|
||||
'''
|
||||
Streaming not used for testing
|
||||
'''
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class MirrorPostHandler(tornado.web.RequestHandler):
|
||||
'''
|
||||
Mirror a POST body back to the client
|
||||
|
|
Loading…
Add table
Reference in a new issue