Merge remote-tracking branch 'upstream/2014.7' into develop

This commit is contained in:
Seth House 2014-07-25 19:55:43 -06:00
commit d7d8beabb8
9 changed files with 288 additions and 14 deletions

View File

@ -2121,4 +2121,4 @@ def api_config(path):
# Let's override them with salt-api's required defaults
defaults.update(DEFAULT_API_OPTS)
return master_config(path, defaults=defaults)
return client_config(path, defaults=defaults)

131
salt/modules/hashutil.py Normal file
View File

@ -0,0 +1,131 @@
# encoding: utf-8
'''
A collection of hashing and encoding functions
'''
import base64
import hashlib
import hmac
def base64_encode(infile, outfile):
'''
Encode a file as base64 and write the result to a new file
.. versionadded:: Helium
CLI Example:
.. code-block::
salt '*' hashutil.base64_encode /path/to/file1 /path/to/encoded_file1
'''
return base64.encode(infile, outfile)
def base64_decode(infile, outfile):
'''
Decode a base64-encoded file and write the result to a new file
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.base64_decode /path/to/encoded_file1 /path/to/file1
'''
return base64.decode(infile, outfile)
def base64_encodestring(instr):
'''
Encode a string as base64
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.base64_encodestring 'get salted'
'''
return base64.encodestring(instr)
def base64_decodestring(instr):
'''
Decode a base64-encoded string
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.base64_decodestring 'Z2V0IHNhbHRlZA==\n'
'''
return base64.decodestring(instr)
def md5_digest(instr):
'''
Generate an md5 hash of a given string
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.md5_digest 'get salted'
'''
return hashlib.md5(instr).hexdigest()
def sha256_digest(instr):
'''
Generate an sha256 hash of a given string
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.sha256_digest 'get salted'
'''
return hashlib.sha256(instr).hexdigest()
def sha512_digest(instr):
'''
Generate an sha512 hash of a given string
.. versionadded:: Helium
CLI Example:
.. code-block:: bash
salt '*' hashutil.sha512_digest 'get salted'
'''
return hashlib.sha512(instr).hexdigest()
def hmac_signature(string, shared_secret, challenge_hmac):
'''
Verify a challenging hmac signature against a string / shared-secret
.. versionadded:: Helium
Returns a boolean if the verification succeeded or failed.
CLI Example:
.. code-block:: bash
salt '*' hashutil.hmac_signature 'get salted' 'shared secret' 'NS2BvKxFRk+rndAlFbCYIFNVkPtI/3KiIYQw4okNKU8='
'''
hmac_hash = hmac.new(string, shared_secret, hashlib.sha256)
valid_hmac = base64.b64encode(hmac_hash.digest())
return valid_hmac == challenge_hmac

View File

@ -12,6 +12,7 @@ import socket
# Import salt libs
import salt.utils
import salt.utils.network
from salt.exceptions import CommandExecutionError
import salt.utils.validate.net
@ -704,3 +705,29 @@ def connect(host, port=None, **kwargs):
ret['result'] = True
ret['comment'] = 'Successfully connected to {0} ({1}) on {2} port {3}'.format(host, _address[0], proto, port)
return ret
def is_private(ip_addr):
'''
Check if the given IP address is a private address
.. versionadded:: Helium
CLI Example::
salt '*' network.is_private 10.0.0.3
'''
return salt.utils.network.IPv4Address(ip_addr).is_private
def is_loopback(ip_addr):
'''
Check if the given IP address is a loopback address
.. versionadded:: Helium
CLI Example::
salt '*' network.is_loopback 127.0.0.1
'''
return salt.utils.network.IPv4Address(ip_addr).is_loopback

View File

@ -22,16 +22,12 @@ class NetapiClient(object):
Provide a uniform method of accessing the various client interfaces in Salt
in the form of low-data data structures. For example:
>>> client = NetapiClient()
>>> client = NetapiClient(__opts__)
>>> lowstate = {'client': 'local', 'tgt': '*', 'fun': 'test.ping', 'arg': ''}
>>> client.run(lowstate)
:param mopts: A copy of the client_config dictionary if already loaded into memory.
:param opts: Ignored; preserved for backward-compat
'''
def __init__(self, opts=None, mopts=None):
self.opts = mopts or salt.config.client_config(os.path.join(
salt.syspaths.CONFIG_DIR, 'master'))
def __init__(self, opts):
self.opts = opts
def run(self, low):
'''

View File

@ -221,6 +221,12 @@ import salt.utils.templates
log = logging.getLogger(__name__)
class SaltDotLookup(dict):
def __init__(self, *args, **kwargs):
dict.__init__(self, *args, **kwargs)
self.__dict__ = self
def _split_module_dicts(__salt__):
'''
Create a dictionary from module.function as module[function]
@ -231,10 +237,11 @@ def _split_module_dicts(__salt__):
{{ salt.cmd.run('uptime') }}
'''
mod_dict = {}
mod_dict = SaltDotLookup()
for module_func_name in __salt__.keys():
mod, _, fun = module_func_name.partition('.')
mod_dict.setdefault(mod, {})[fun] = __salt__[module_func_name]
mod_dict.setdefault(mod,
SaltDotLookup())[fun] = __salt__[module_func_name]
return mod_dict
@ -252,9 +259,8 @@ def render(template_file, saltenv='base', sls='', argline='',
'Unknown renderer option: {opt}'.format(opt=argline)
)
salt_dict = {}
salt_dict.update(_split_module_dicts(__salt__))
salt_dict.update(__salt__)
salt_dict = SaltDotLookup(**__salt__)
salt_dict.__dict__.update(_split_module_dicts(__salt__))
tmp_data = salt.utils.templates.JINJA(template_file,
to_str=True,

View File

@ -24,7 +24,7 @@ class NetapiClientTest(TestCase):
Set up a NetapiClient instance
'''
opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, 'master'))
self.netapi = salt.netapi.NetapiClient(mopts=opts)
self.netapi = salt.netapi.NetapiClient(opts)
def test_local(self):
low = {'client': 'local', 'tgt': '*', 'fun': 'test.ping'}

View File

@ -0,0 +1,49 @@
# coding: utf-8
import salt.loader
from tests.integration import ModuleCase
class HashutilTestCase(ModuleCase):
the_string = 'get salted'
the_string_base64 = 'Z2V0IHNhbHRlZA==\n'
the_string_md5 = '2aacf29e92feaf528fb738bcf9d647ac'
the_string_sha256 = 'd49859ccbc854fa68d800b5734efc70d72383e6479d545468bc300263164ff33'
the_string_sha512 = 'a8c174a7941c64a068e686812a2fafd7624c840fde800f5965fbeca675f2f6e37061ffe41e17728c919bdea290eab7a21e13c04ae71661955a87f2e0e04bb045'
the_string_hmac = 'NS2BvKxFRk+rndAlFbCYIFNVkPtI/3KiIYQw4okNKU8='
def setUp(self):
self.hashutil = salt.loader.raw_mod(self.minion_opts, 'hashutil', None)
def test_base64_encodestring(self):
ret = self.hashutil['hashutil.base64_encodestring'](self.the_string)
self.assertEqual(ret, self.the_string_base64)
def test_base64_decodestring(self):
ret = self.hashutil['hashutil.base64_decodestring'](self.the_string_base64)
self.assertEqual(ret, self.the_string)
def test_md5_digest(self):
ret = self.hashutil['hashutil.md5_digest'](self.the_string)
self.assertEqual(ret, self.the_string_md5)
def test_sha256_digest(self):
ret = self.hashutil['hashutil.sha256_digest'](self.the_string)
self.assertEqual(ret, self.the_string_sha256)
def test_sha512_digest(self):
ret = self.hashutil['hashutil.sha512_digest'](self.the_string)
self.assertEqual(ret, self.the_string_sha512)
def test_hmac_signature(self):
ret = self.hashutil['hashutil.hmac_signature'](
self.the_string,
'shared secret',
self.the_string_hmac)
self.assertTrue(ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(HashutilTestCase,
needs_daemon=False)

View File

@ -0,0 +1,19 @@
# coding: utf-8
import salt.loader
from tests.integration import ModuleCase
class NetworkUtilsTestCase(ModuleCase):
def test_is_private(self):
__salt__ = salt.loader.raw_mod(self.minion_opts, 'network', None)
self.assertTrue(__salt__['network.is_private']('10.0.0.1'), True)
def test_is_loopback(self):
__salt__ = salt.loader.raw_mod(self.minion_opts, 'network', None)
self.assertTrue(__salt__['network.is_loopback']('127.0.0.1'), True)
if __name__ == '__main__':
from integration import run_tests
run_tests(NetworkUtilsTestCase,
needs_daemon=False)

View File

@ -8,11 +8,13 @@ import datetime
import pprint
# Import Salt Testing libs
from tests.integration import ModuleCase
from salttesting import skipIf, TestCase
from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
# Import salt libs
import salt.loader
import salt.utils
from salt.exceptions import SaltRenderError
from salt.utils import get_context
@ -631,7 +633,51 @@ class TestCustomExtensions(TestCase):
# return
class TestDotNotationLookup(ModuleCase):
'''
Tests to call Salt functions via Jinja with various lookup syntaxes
'''
def setUp(self, *args, **kwargs):
functions = {
'mocktest.ping': lambda: True,
'mockgrains.get': lambda x: 'jerry',
}
render = salt.loader.render(self.minion_opts, functions)
self.jinja = render.get('jinja')
def render(self, tmpl_str, context=None):
return self.jinja(tmpl_str, context=context or {}, from_str=True).read()
def test_normlookup(self):
'''
Sanity-check the normal dictionary-lookup syntax for our stub function
'''
tmpl_str = '''Hello, {{ salt['mocktest.ping']() }}.'''
ret = self.render(tmpl_str)
self.assertEqual(ret, 'Hello, True.')
def test_dotlookup(self):
'''
Check calling a stub function using awesome dot-notation
'''
tmpl_str = '''Hello, {{ salt.mocktest.ping() }}.'''
ret = self.render(tmpl_str)
self.assertEqual(ret, 'Hello, True.')
def test_shadowed_dict_method(self):
'''
Check calling a stub function with a name that shadows a ``dict``
method name
'''
tmpl_str = '''Hello, {{ salt.mockgrains.get('id') }}.'''
ret = self.render(tmpl_str)
self.assertEqual(ret, 'Hello, jerry.')
if __name__ == '__main__':
from integration import run_tests
run_tests(TestSaltCacheLoader, TestGetTemplate, TestCustomExtensions,
TestDotNotationLookup,
needs_daemon=False)