mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +00:00
Windows Registry Unicode Support and PY2 character encoding (module.reg) (#32835)
* reg.py * Start at PY3 support, however not tested against PY3 * Change to Unicode including from __future__ import unicode_literals * If PY2 converts all parameter input unicode to local encoding i.e. Unicode to String * If PY3 stays as Unicode as PY3 uses Windows Wide Char * Supports non-asiic characters i.e. > 126 * All output is Unicode, before most of it was Unicode output * Added a safty check to recursive delete to try and prevent a mistake like removing all of SOFTWARE * Fixed all the pylint errors * add _ prefix to internal functions * Provided unit test see reg_win_test.py reg_win_test.py * All tests currently make real changes to the registry * All changes are performed under SOFTWARE\SaltStackTest under HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER * Their is still room for more tests to be developed * Test target the new Unicode features of reg.py e.g. Copyright, Tradmark and Register characters * General the values set in the registy contain date/time and then checked that they are the current date/time to make sure they are not left over from old tests * Update test unit to only run the tests on windows. Removed some code which was commented out which is not required * chmod 644 tests/unit/modules/reg_win_test.py
This commit is contained in:
parent
acb0c373be
commit
cf4826aad4
@ -26,11 +26,16 @@ Values/Entries are name/data pairs. There can be many values in a key. The
|
|||||||
|
|
||||||
:depends: - winreg Python module
|
:depends: - winreg Python module
|
||||||
'''
|
'''
|
||||||
# Import python libs
|
# When production windows installer is using Python 3, Python 2 code can be removed
|
||||||
from __future__ import absolute_import
|
|
||||||
import logging
|
|
||||||
from salt.ext.six.moves import range
|
|
||||||
|
|
||||||
|
# Import _future_ python libs first & before any other code
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# Import python libs
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from salt.ext.six.moves import range # pylint: disable=W0622
|
||||||
|
import salt.ext.six as six
|
||||||
# Import third party libs
|
# Import third party libs
|
||||||
try:
|
try:
|
||||||
from salt.ext.six.moves import winreg as _winreg # pylint: disable=import-error,no-name-in-module
|
from salt.ext.six.moves import winreg as _winreg # pylint: disable=import-error,no-name-in-module
|
||||||
@ -44,6 +49,7 @@ except ImportError:
|
|||||||
import salt.utils
|
import salt.utils
|
||||||
from salt.exceptions import CommandExecutionError
|
from salt.exceptions import CommandExecutionError
|
||||||
|
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Define the module's virtual name
|
# Define the module's virtual name
|
||||||
@ -65,41 +71,74 @@ def __virtual__():
|
|||||||
return __virtualname__
|
return __virtualname__
|
||||||
|
|
||||||
|
|
||||||
class Registry(object):
|
# winreg in python 2 is hard coded to use codex 'mbcs', which uses
|
||||||
|
# encoding that the user has assign. The function _unicode_to_mbcs
|
||||||
|
# and _unicode_to_mbcs help with this.
|
||||||
|
|
||||||
|
|
||||||
|
def _unicode_to_mbcs(instr):
|
||||||
|
'''
|
||||||
|
Converts unicode to to current users character encoding
|
||||||
|
'''
|
||||||
|
if isinstance(instr, six.text_type):
|
||||||
|
# unicode to windows utf8
|
||||||
|
return instr.encode('mbcs')
|
||||||
|
else:
|
||||||
|
# Assume its byte str or not a str/unicode
|
||||||
|
return instr
|
||||||
|
|
||||||
|
|
||||||
|
def _mbcs_to_unicode(instr):
|
||||||
|
'''
|
||||||
|
Converts from current users character encoding to unicode
|
||||||
|
'''
|
||||||
|
if isinstance(instr, six.text_type):
|
||||||
|
return instr
|
||||||
|
else:
|
||||||
|
return unicode(instr, 'mbcs')
|
||||||
|
|
||||||
|
|
||||||
|
class Registry(object): # pylint: disable=R0903
|
||||||
'''
|
'''
|
||||||
Delay '_winreg' usage until this module is used
|
Delay '_winreg' usage until this module is used
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.hkeys = {
|
self.hkeys = {
|
||||||
"HKEY_CURRENT_USER": _winreg.HKEY_CURRENT_USER,
|
'HKEY_CURRENT_USER': _winreg.HKEY_CURRENT_USER,
|
||||||
"HKEY_LOCAL_MACHINE": _winreg.HKEY_LOCAL_MACHINE,
|
'HKEY_LOCAL_MACHINE': _winreg.HKEY_LOCAL_MACHINE,
|
||||||
"HKEY_USERS": _winreg.HKEY_USERS,
|
'HKEY_USERS': _winreg.HKEY_USERS,
|
||||||
"HKCU": _winreg.HKEY_CURRENT_USER,
|
'HKCU': _winreg.HKEY_CURRENT_USER,
|
||||||
"HKLM": _winreg.HKEY_LOCAL_MACHINE,
|
'HKLM': _winreg.HKEY_LOCAL_MACHINE,
|
||||||
"HKU": _winreg.HKEY_USERS,
|
'HKU': _winreg.HKEY_USERS,
|
||||||
}
|
}
|
||||||
|
self.vtype = {
|
||||||
|
'REG_BINARY': _winreg.REG_BINARY,
|
||||||
|
'REG_DWORD': _winreg.REG_DWORD,
|
||||||
|
'REG_EXPAND_SZ': _winreg.REG_EXPAND_SZ,
|
||||||
|
'REG_MULTI_SZ': _winreg.REG_MULTI_SZ,
|
||||||
|
'REG_SZ': _winreg.REG_SZ
|
||||||
|
}
|
||||||
|
# Return Unicode due to from __future__ import unicode_literals
|
||||||
|
self.vtype_reverse = {
|
||||||
|
_winreg.REG_BINARY: 'REG_BINARY',
|
||||||
|
_winreg.REG_DWORD: 'REG_DWORD',
|
||||||
|
_winreg.REG_EXPAND_SZ: 'REG_EXPAND_SZ',
|
||||||
|
_winreg.REG_MULTI_SZ: 'REG_MULTI_SZ',
|
||||||
|
_winreg.REG_SZ: 'REG_SZ'
|
||||||
|
}
|
||||||
|
# delete_key_recursive uses this to check the subkey contains enough \
|
||||||
|
# as we do not want to remove all or most of the registry
|
||||||
|
self.subkey_slash_check = {
|
||||||
|
_winreg.HKEY_CURRENT_USER: 0,
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE: 1,
|
||||||
|
_winreg.HKEY_USERS: 1
|
||||||
|
}
|
||||||
|
|
||||||
self.registry_32 = {
|
self.registry_32 = {
|
||||||
True: _winreg.KEY_ALL_ACCESS | _winreg.KEY_WOW64_32KEY,
|
True: _winreg.KEY_ALL_ACCESS | _winreg.KEY_WOW64_32KEY,
|
||||||
False: _winreg.KEY_ALL_ACCESS,
|
False: _winreg.KEY_ALL_ACCESS,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.vtype = {
|
|
||||||
"REG_BINARY": _winreg.REG_BINARY,
|
|
||||||
"REG_DWORD": _winreg.REG_DWORD,
|
|
||||||
"REG_EXPAND_SZ": _winreg.REG_EXPAND_SZ,
|
|
||||||
"REG_MULTI_SZ": _winreg.REG_MULTI_SZ,
|
|
||||||
"REG_SZ": _winreg.REG_SZ
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vtype_reverse = {
|
|
||||||
_winreg.REG_BINARY: "REG_BINARY",
|
|
||||||
_winreg.REG_DWORD: "REG_DWORD",
|
|
||||||
_winreg.REG_EXPAND_SZ: "REG_EXPAND_SZ",
|
|
||||||
_winreg.REG_MULTI_SZ: "REG_MULTI_SZ",
|
|
||||||
_winreg.REG_SZ: "REG_SZ"
|
|
||||||
}
|
|
||||||
|
|
||||||
def __getattr__(self, k):
|
def __getattr__(self, k):
|
||||||
try:
|
try:
|
||||||
return self.hkeys[k]
|
return self.hkeys[k]
|
||||||
@ -120,12 +159,20 @@ def _key_exists(hive, key, use_32bit_registry=False):
|
|||||||
:return: Returns True if found, False if not found
|
:return: Returns True if found, False if not found
|
||||||
:rtype: bool
|
:rtype: bool
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
else:
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
hkey = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handle = _winreg.OpenKey(hkey, key, 0, access_mask)
|
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||||
_winreg.CloseKey(handle)
|
_winreg.CloseKey(handle)
|
||||||
return True
|
return True
|
||||||
except WindowsError: # pylint: disable=E0602
|
except WindowsError: # pylint: disable=E0602
|
||||||
@ -167,17 +214,28 @@ def list_keys(hive, key=None, use_32bit_registry=False):
|
|||||||
|
|
||||||
salt '*' reg.list_keys HKLM 'SOFTWARE'
|
salt '*' reg.list_keys HKLM 'SOFTWARE'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
else:
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
hkey = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
subkeys = []
|
subkeys = []
|
||||||
try:
|
try:
|
||||||
handle = _winreg.OpenKey(hkey, key, 0, access_mask)
|
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||||
|
|
||||||
for i in range(_winreg.QueryInfoKey(handle)[0]):
|
for i in range(_winreg.QueryInfoKey(handle)[0]):
|
||||||
subkey = _winreg.EnumKey(handle, i)
|
subkey = _winreg.EnumKey(handle, i)
|
||||||
subkeys.append(subkey)
|
if PY2:
|
||||||
|
subkeys.append(_mbcs_to_unicode(subkey))
|
||||||
|
else:
|
||||||
|
subkeys.append(subkey)
|
||||||
|
|
||||||
handle.Close()
|
handle.Close()
|
||||||
|
|
||||||
@ -218,15 +276,12 @@ def read_key(hkey, path, key=None, use_32bit_registry=False):
|
|||||||
salt '*' reg.read_key HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version'
|
salt '*' reg.read_key HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
ret = {'hive': hkey,
|
|
||||||
'key': path,
|
|
||||||
'vdata': None,
|
|
||||||
'success': True}
|
|
||||||
|
|
||||||
if key: # This if statement will be removed in Carbon
|
if key: # This if statement will be removed in Carbon
|
||||||
salt.utils.warn_until('Carbon', 'Use reg.read_value to read a registry '
|
salt.utils.warn_until(
|
||||||
'value. This functionality will be '
|
'Carbon',
|
||||||
'removed in Salt Carbon')
|
'Use reg.read_value to read a registry value. This functionality '
|
||||||
|
'will be removed in Salt Carbon'
|
||||||
|
)
|
||||||
return read_value(hive=hkey,
|
return read_value(hive=hkey,
|
||||||
key=path,
|
key=path,
|
||||||
vname=key,
|
vname=key,
|
||||||
@ -272,26 +327,42 @@ def read_value(hive, key, vname=None, use_32bit_registry=False):
|
|||||||
salt '*' reg.read_value HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'
|
salt '*' reg.read_value HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# Setup the return array
|
|
||||||
ret = {'hive': hive,
|
|
||||||
'key': key,
|
|
||||||
'vname': vname,
|
|
||||||
'vdata': None,
|
|
||||||
'success': True}
|
|
||||||
|
|
||||||
# If no name is passed, the default value of the key will be returned
|
# If no name is passed, the default value of the key will be returned
|
||||||
# The value name is Default
|
# The value name is Default
|
||||||
|
|
||||||
|
# Setup the return array
|
||||||
|
if PY2:
|
||||||
|
ret = {'hive': _mbcs_to_unicode(hive),
|
||||||
|
'key': _mbcs_to_unicode(key),
|
||||||
|
'vname': _mbcs_to_unicode(vname),
|
||||||
|
'vdata': None,
|
||||||
|
'success': True}
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
local_vname = _unicode_to_mbcs(vname)
|
||||||
|
|
||||||
|
else:
|
||||||
|
ret = {'hive': hive,
|
||||||
|
'key': key,
|
||||||
|
'vname': vname,
|
||||||
|
'vdata': None,
|
||||||
|
'success': True}
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
local_vname = vname
|
||||||
|
|
||||||
if not vname:
|
if not vname:
|
||||||
ret['vname'] = '(Default)'
|
ret['vname'] = '(Default)'
|
||||||
|
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
hkey = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handle = _winreg.OpenKey(hkey, key, 0, access_mask)
|
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||||
try:
|
try:
|
||||||
vdata, vtype = _winreg.QueryValueEx(handle, vname)
|
# QueryValueEx returns unicode data
|
||||||
|
vdata, vtype = _winreg.QueryValueEx(handle, local_vname)
|
||||||
if vdata or vdata in [0, '']:
|
if vdata or vdata in [0, '']:
|
||||||
ret['vtype'] = registry.vtype_reverse[vtype]
|
ret['vtype'] = registry.vtype_reverse[vtype]
|
||||||
ret['vdata'] = vdata
|
ret['vdata'] = vdata
|
||||||
@ -302,8 +373,8 @@ def read_value(hive, key, vname=None, use_32bit_registry=False):
|
|||||||
ret['vtype'] = 'REG_SZ'
|
ret['vtype'] = 'REG_SZ'
|
||||||
except WindowsError as exc: # pylint: disable=E0602
|
except WindowsError as exc: # pylint: disable=E0602
|
||||||
log.debug(exc)
|
log.debug(exc)
|
||||||
log.debug('Cannot find key: {0}\\{1}'.format(hive, key))
|
log.debug('Cannot find key: {0}\\{1}'.format(local_hive, local_key))
|
||||||
ret['comment'] = 'Cannot find key: {0}\\{1}'.format(hive, key)
|
ret['comment'] = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key)
|
||||||
ret['success'] = False
|
ret['success'] = False
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
@ -351,17 +422,31 @@ def set_value(hive,
|
|||||||
|
|
||||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2'
|
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
local_vname = _unicode_to_mbcs(vname)
|
||||||
|
local_vdata = _unicode_to_mbcs(vdata)
|
||||||
|
local_vtype = _mbcs_to_unicode(vtype)
|
||||||
|
else:
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
local_vname = vname
|
||||||
|
local_vdata = vdata
|
||||||
|
local_vtype = vtype
|
||||||
|
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
hkey = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
vtype = registry.vtype[vtype]
|
vtype_value = registry.vtype[local_vtype]
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handle = _winreg.CreateKeyEx(hkey, key, 0, access_mask)
|
handle = _winreg.CreateKeyEx(hkey, local_key, 0, access_mask)
|
||||||
if vtype == registry.vtype['REG_SZ']\
|
if vtype_value == registry.vtype['REG_SZ']\
|
||||||
or vtype == registry.vtype['REG_BINARY']:
|
or vtype_value == registry.vtype['REG_BINARY']:
|
||||||
vdata = str(vdata)
|
local_vdata = str(local_vdata) # Not sure about this line
|
||||||
_winreg.SetValueEx(handle, vname, 0, vtype, vdata)
|
_winreg.SetValueEx(handle, local_vname, 0, vtype_value, local_vdata)
|
||||||
_winreg.FlushKey(handle)
|
_winreg.FlushKey(handle)
|
||||||
_winreg.CloseKey(handle)
|
_winreg.CloseKey(handle)
|
||||||
broadcast_change()
|
broadcast_change()
|
||||||
@ -401,17 +486,32 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||||||
|
|
||||||
salt '*' reg.delete_key_recursive HKLM SOFTWARE\\salt
|
salt '*' reg.delete_key_recursive HKLM SOFTWARE\\salt
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
else:
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
|
||||||
# Instantiate the registry object
|
# Instantiate the registry object
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
hkey = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
key_path = key
|
key_path = local_key
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
if not _key_exists(hive, key, use_32bit_registry):
|
if not _key_exists(local_hive, local_key, use_32bit_registry):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (len(key) > 1) and (key.count('\\', 1) < registry.subkey_slash_check[hkey]):
|
||||||
|
log.error('Hive:{0} Key:{1}; key is too close to root, not safe to remove'.format(hive, key))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Functions for traversing the registry tree
|
# Functions for traversing the registry tree
|
||||||
def subkeys(_key):
|
def _subkeys(_key):
|
||||||
|
'''
|
||||||
|
Enumerate keys
|
||||||
|
'''
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -421,17 +521,20 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||||||
except WindowsError: # pylint: disable=E0602
|
except WindowsError: # pylint: disable=E0602
|
||||||
break
|
break
|
||||||
|
|
||||||
def traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
|
def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
|
||||||
|
'''
|
||||||
|
Traverse the registry tree i.e. dive into the tree
|
||||||
|
'''
|
||||||
_key = _winreg.OpenKey(_hkey, _keypath, 0, _access_mask)
|
_key = _winreg.OpenKey(_hkey, _keypath, 0, _access_mask)
|
||||||
for subkeyname in subkeys(_key):
|
for subkeyname in _subkeys(_key):
|
||||||
subkeypath = r'{0}\{1}'.format(_keypath, subkeyname)
|
subkeypath = r'{0}\{1}'.format(_keypath, subkeyname)
|
||||||
_ret = traverse_registry_tree(_hkey, subkeypath, _ret, access_mask)
|
_ret = _traverse_registry_tree(_hkey, subkeypath, _ret, access_mask)
|
||||||
_ret.append('{0}'.format(subkeypath))
|
_ret.append('{0}'.format(subkeypath))
|
||||||
return _ret
|
return _ret
|
||||||
|
|
||||||
# Get a reverse list of registry keys to be deleted
|
# Get a reverse list of registry keys to be deleted
|
||||||
key_list = []
|
key_list = []
|
||||||
key_list = traverse_registry_tree(hkey, key_path, key_list, access_mask)
|
key_list = _traverse_registry_tree(hkey, key_path, key_list, access_mask)
|
||||||
# Add the top level key last, all subkeys must be deleted first
|
# Add the top level key last, all subkeys must be deleted first
|
||||||
key_list.append(r'{0}'.format(key_path))
|
key_list.append(r'{0}'.format(key_path))
|
||||||
|
|
||||||
@ -480,20 +583,30 @@ def delete_value(hive, key, vname=None, use_32bit_registry=False):
|
|||||||
|
|
||||||
salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version'
|
salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
local_hive = _mbcs_to_unicode(hive)
|
||||||
|
local_key = _unicode_to_mbcs(key)
|
||||||
|
local_vname = _unicode_to_mbcs(vname)
|
||||||
|
else:
|
||||||
|
local_hive = hive
|
||||||
|
local_key = key
|
||||||
|
local_vname = vname
|
||||||
|
|
||||||
registry = Registry()
|
registry = Registry()
|
||||||
h_hive = registry.hkeys[hive]
|
hkey = registry.hkeys[local_hive]
|
||||||
access_mask = registry.registry_32[use_32bit_registry]
|
access_mask = registry.registry_32[use_32bit_registry]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handle = _winreg.OpenKey(h_hive, key, 0, access_mask)
|
handle = _winreg.OpenKey(hkey, local_key, 0, access_mask)
|
||||||
_winreg.DeleteValue(handle, vname)
|
_winreg.DeleteValue(handle, local_vname)
|
||||||
_winreg.CloseKey(handle)
|
_winreg.CloseKey(handle)
|
||||||
broadcast_change()
|
broadcast_change()
|
||||||
return True
|
return True
|
||||||
except WindowsError as exc: # pylint: disable=E0602
|
except WindowsError as exc: # pylint: disable=E0602
|
||||||
log.error(exc, exc_info=True)
|
log.error(exc, exc_info=True)
|
||||||
log.error('Hive: {0}'.format(hive))
|
log.error('Hive: {0}'.format(local_hive))
|
||||||
log.error('Key: {0}'.format(key))
|
log.error('Key: {0}'.format(local_key))
|
||||||
log.error('ValueName: {0}'.format(vname))
|
log.error('ValueName: {0}'.format(local_vname))
|
||||||
log.error('32bit Reg: {0}'.format(use_32bit_registry))
|
log.error('32bit Reg: {0}'.format(use_32bit_registry))
|
||||||
return False
|
return False
|
||||||
|
284
tests/unit/modules/reg_win_test.py
Normal file
284
tests/unit/modules/reg_win_test.py
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:synopsis: Unit Tests for Windows Registry Module 'module.reg'
|
||||||
|
:platform: Windows
|
||||||
|
:maturity: develop
|
||||||
|
:codeauthor: Damon Atkins <https://github.com/damon-atkins>
|
||||||
|
versionadded:: Carbon
|
||||||
|
'''
|
||||||
|
# Import Python future libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# Import Python Libs
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import TestCase, skipIf
|
||||||
|
from salttesting.helpers import destructiveTest
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.modules import reg as win_mod_reg
|
||||||
|
try:
|
||||||
|
from salt.ext.six.moves import winreg as _winreg # pylint: disable=import-error,no-name-in-module
|
||||||
|
NO_WINDOWS_MODULES = False
|
||||||
|
except ImportError:
|
||||||
|
NO_WINDOWS_MODULES = True
|
||||||
|
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
|
# The following used to make sure we are not
|
||||||
|
# testing already existing data
|
||||||
|
# Note strftime retunrns a str, so we need to make it unicode
|
||||||
|
TIMEINT = int(time.time())
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
TIME_INT_UNICODE = unicode(TIMEINT)
|
||||||
|
TIMESTR = time.strftime('%X %x %Z').decode('utf-8')
|
||||||
|
else:
|
||||||
|
TIMESTR = time.strftime('%X %x %Z')
|
||||||
|
TIME_INT_UNICODE = str(TIMEINT) # pylint: disable=R0204
|
||||||
|
|
||||||
|
|
||||||
|
# we do not need to prefix this with u, as we are
|
||||||
|
# using from __future__ import unicode_literals
|
||||||
|
UNICODETEST_WITH_SIGNS = 'Testing Unicode \N{COPYRIGHT SIGN},\N{TRADE MARK SIGN},\N{REGISTERED SIGN} '+TIMESTR
|
||||||
|
UNICODETEST_WITHOUT_SIGNS = 'Testing Unicode'+TIMESTR
|
||||||
|
UNICODE_TEST_KEY = 'UnicodeKey \N{TRADE MARK SIGN} '+TIME_INT_UNICODE
|
||||||
|
UNICODE_TEST_KEY_DEL = 'Delete Me \N{TRADE MARK SIGN} '+TIME_INT_UNICODE
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_WINDOWS_MODULES, 'requires Windows OS to test Windows registry')
|
||||||
|
class RegWinTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.modules.reg
|
||||||
|
'''
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_read_reg_plain(self):
|
||||||
|
'''
|
||||||
|
Test - Read a registry value from a subkey using Pythen 2 Strings or
|
||||||
|
Pythen 3 Bytes
|
||||||
|
'''
|
||||||
|
if not PY2:
|
||||||
|
self.skipTest('Invalid for Python Version 2')
|
||||||
|
|
||||||
|
subkey = b'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||||
|
vname = b'PathName'
|
||||||
|
handle = _winreg.OpenKey(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
|
||||||
|
test_vdata = win_mod_reg.read_value(b'HKEY_LOCAL_MACHINE', subkey, vname)[b'vdata']
|
||||||
|
self.assertEqual(
|
||||||
|
test_vdata, current_vdata)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_read_reg_unicode(self):
|
||||||
|
'''
|
||||||
|
Test - Read a registry value from a subkey using Pythen 2 Unicode
|
||||||
|
or Pythen 3 Str i.e. Unicode
|
||||||
|
'''
|
||||||
|
subkey = 'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||||
|
vname = 'PathName'
|
||||||
|
handle = _winreg.OpenKey(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
|
||||||
|
test_vdata = win_mod_reg.read_value(
|
||||||
|
'HKEY_LOCAL_MACHINE',
|
||||||
|
subkey,
|
||||||
|
vname)['vdata']
|
||||||
|
self.assertEqual(test_vdata, current_vdata)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_list_keys_fail(self):
|
||||||
|
'''
|
||||||
|
Test - Read list the keys under a subkey which does not exist.
|
||||||
|
'''
|
||||||
|
subkey = 'ThisIsJunkItDoesNotExistIhope'
|
||||||
|
test_list = win_mod_reg.list_keys('HKEY_LOCAL_MACHINE', subkey)
|
||||||
|
# returns a tuple with first item false, and second item a reason
|
||||||
|
test = isinstance(test_list, tuple) and (not test_list[0])
|
||||||
|
self.assertTrue(test)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_list_keys(self):
|
||||||
|
'''
|
||||||
|
Test - Read list the keys under a subkey
|
||||||
|
'''
|
||||||
|
subkey = 'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||||
|
test_list = win_mod_reg.list_keys('HKEY_LOCAL_MACHINE', subkey)
|
||||||
|
test = len(test_list) > 5 # Their should be a lot more than 5 items
|
||||||
|
self.assertTrue(test)
|
||||||
|
|
||||||
|
# Not considering this destructive as its writing to a private space
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_set_value_unicode(self):
|
||||||
|
'''
|
||||||
|
Test - set a registry plain text subkey name to a unicode string value
|
||||||
|
'''
|
||||||
|
vname = 'TestUniccodeString'
|
||||||
|
subkey = 'Software\\SaltStackTest'
|
||||||
|
test1_success = False
|
||||||
|
test2_success = False
|
||||||
|
test1_success = win_mod_reg.set_value(
|
||||||
|
'HKEY_LOCAL_MACHINE',
|
||||||
|
subkey,
|
||||||
|
vname,
|
||||||
|
UNICODETEST_WITH_SIGNS
|
||||||
|
)
|
||||||
|
# Now use _winreg direct to see if it worked as expected
|
||||||
|
if test1_success:
|
||||||
|
handle = _winreg.OpenKey(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
test2_success = (current_vdata == UNICODETEST_WITH_SIGNS)
|
||||||
|
self.assertTrue(test1_success and test2_success)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_set_value_unicode_key(self):
|
||||||
|
'''
|
||||||
|
Test - set a registry Unicode subkey name with unicode characters within
|
||||||
|
to a integer
|
||||||
|
'''
|
||||||
|
test_success = win_mod_reg.set_value(
|
||||||
|
'HKEY_LOCAL_MACHINE',
|
||||||
|
'Software\\SaltStackTest',
|
||||||
|
UNICODE_TEST_KEY,
|
||||||
|
TIMEINT,
|
||||||
|
'REG_DWORD'
|
||||||
|
)
|
||||||
|
self.assertTrue(test_success)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_del_value(self):
|
||||||
|
'''
|
||||||
|
Test - Create Directly and Delete with salt a registry value
|
||||||
|
'''
|
||||||
|
subkey = 'Software\\SaltStackTest'
|
||||||
|
vname = UNICODE_TEST_KEY_DEL
|
||||||
|
vdata = 'I will be deleted'
|
||||||
|
if PY2:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(
|
||||||
|
handle,
|
||||||
|
vname.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.REG_SZ,
|
||||||
|
vdata.encode('mbcs')
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
# time.sleep(15) # delays for 15 seconds
|
||||||
|
test_success = win_mod_reg.delete_value(
|
||||||
|
'HKEY_LOCAL_MACHINE',
|
||||||
|
subkey,
|
||||||
|
vname
|
||||||
|
)
|
||||||
|
self.assertTrue(test_success)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
def test_del_key_recursive_user(self):
|
||||||
|
'''
|
||||||
|
Test - Create directly key/value pair and Delete recusivly with salt
|
||||||
|
'''
|
||||||
|
subkey = 'Software\\SaltStackTest'
|
||||||
|
vname = UNICODE_TEST_KEY_DEL
|
||||||
|
vdata = 'I will be deleted recursive'
|
||||||
|
if PY2:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_CURRENT_USER,
|
||||||
|
subkey.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(
|
||||||
|
handle,
|
||||||
|
vname.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.REG_SZ,
|
||||||
|
vdata.encode('mbcs')
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_CURRENT_USER,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
# time.sleep(15) # delays for 15 seconds so you can run regedit & watch it happen
|
||||||
|
test_success = win_mod_reg.delete_key_recursive('HKEY_CURRENT_USER', subkey)
|
||||||
|
self.assertTrue(test_success)
|
||||||
|
|
||||||
|
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||||
|
@destructiveTest
|
||||||
|
def test_del_key_recursive_machine(self):
|
||||||
|
'''
|
||||||
|
This is a DESTRUCTIVE TEST it creates a new registry entry.
|
||||||
|
And then destroys the registry entry recusively , however it is completed in its own space
|
||||||
|
within the registry. We mark this as destructiveTest as it has the potential
|
||||||
|
to detroy a machine if salt reg code has a large error in it.
|
||||||
|
'''
|
||||||
|
subkey = 'Software\\SaltStackTest'
|
||||||
|
vname = UNICODE_TEST_KEY_DEL
|
||||||
|
vdata = 'I will be deleted recursive'
|
||||||
|
if PY2:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(
|
||||||
|
handle,
|
||||||
|
vname.encode('mbcs'),
|
||||||
|
0,
|
||||||
|
_winreg.REG_SZ,
|
||||||
|
vdata.encode('mbcs')
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
handle = _winreg.CreateKeyEx(
|
||||||
|
_winreg.HKEY_LOCAL_MACHINE,
|
||||||
|
subkey,
|
||||||
|
0,
|
||||||
|
_winreg.KEY_ALL_ACCESS
|
||||||
|
)
|
||||||
|
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||||
|
_winreg.CloseKey(handle)
|
||||||
|
# time.sleep(15) # delays for 15 seconds so you can run regedit and watch it happen
|
||||||
|
test_success = win_mod_reg.delete_key_recursive('HKEY_LOCAL_MACHINE', subkey)
|
||||||
|
self.assertTrue(test_success)
|
||||||
|
|
||||||
|
# pylint: disable=W0511
|
||||||
|
# TODO: Test other hives, other than HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests # pylint: disable=C0413
|
||||||
|
run_tests(RegWinTestCase, needs_daemon=False)
|
Loading…
Reference in New Issue
Block a user