Merge branch '2018.3' into mysql-module-fix-for-python3

This commit is contained in:
Proskurin Kirill 2019-03-05 13:33:18 +00:00 committed by GitHub
commit dfcfebdcf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 163 additions and 96 deletions

View file

@ -0,0 +1,6 @@
========================================
In Progress: Salt 2018.3.5 Release Notes
========================================
Version 2018.3.5 is an **unreleased** bugfix release for :ref:`2018.3.0 <release-2018-3-0>`.
This release is still in progress and has not been released yet.

View file

@ -97,7 +97,13 @@ def beacon(config):
mount_re = '{0}$'.format(mount)
if salt.utils.platform.is_windows():
mount_re = re.sub('\\$', '\\\\', mount_re)
# mount_re comes in formatted with a $ at the end
# can be `C:\\$` or `C:\\\\$`
# re string must be like `C:\\\\` regardless of \\ or \\\\
# also, psutil returns uppercase
mount_re = re.sub(r':\\\$', r':\\\\', mount_re)
mount_re = re.sub(r':\\\\\$', r':\\\\', mount_re)
mount_re = mount_re.upper()
for part in parts:
if re.match(mount_re, part.mountpoint):

View file

@ -13,11 +13,11 @@ from __future__ import absolute_import, unicode_literals, print_function
# Import Salt libs
import salt.utils.platform
import salt.utils.win_functions
import salt.utils.winapi
try:
import win32com.client
import pythoncom
import pywintypes
HAS_DEPENDENCIES = True
except ImportError:
@ -43,8 +43,8 @@ def _get_computer_object():
Returns:
object: Returns the computer object for the local machine
'''
pythoncom.CoInitialize()
nt = win32com.client.Dispatch('AdsNameSpaces')
with salt.utils.winapi.Com():
nt = win32com.client.Dispatch('AdsNameSpaces')
return nt.GetObject('', 'WinNT://.,computer')
@ -59,8 +59,8 @@ def _get_group_object(name):
Returns:
object: The specified group object
'''
pythoncom.CoInitialize()
nt = win32com.client.Dispatch('AdsNameSpaces')
with salt.utils.winapi.Com():
nt = win32com.client.Dispatch('AdsNameSpaces')
return nt.GetObject('', 'WinNT://./' + name + ',group')
@ -72,8 +72,8 @@ def _get_all_groups():
Returns:
iter: A list of objects for all groups on the machine
'''
pythoncom.CoInitialize()
nt = win32com.client.Dispatch('AdsNameSpaces')
with salt.utils.winapi.Com():
nt = win32com.client.Dispatch('AdsNameSpaces')
results = nt.GetObject('', 'WinNT://.')
results.Filter = ['group']
return results

View file

@ -3,7 +3,6 @@
Module for managing windows systems.
:depends:
- pythoncom
- pywintypes
- win32api
- win32con
@ -24,12 +23,12 @@ from datetime import datetime
import salt.utils.functools
import salt.utils.locales
import salt.utils.platform
import salt.utils.winapi
from salt.exceptions import CommandExecutionError
# Import 3rd-party Libs
from salt.ext import six
try:
import pythoncom
import wmi
import win32net
import win32api
@ -516,8 +515,8 @@ def get_system_info():
os_type = {1: 'Work Station',
2: 'Domain Controller',
3: 'Server'}
pythoncom.CoInitialize()
conn = wmi.WMI()
with salt.utils.winapi.Com():
conn = wmi.WMI()
system = conn.Win32_OperatingSystem()[0]
ret = {'name': get_computer_name(),
'description': system.Description,
@ -756,8 +755,8 @@ def _join_domain(domain,
if not account_exists:
join_options |= NETSETUP_ACCOUNT_CREATE
pythoncom.CoInitialize()
conn = wmi.WMI()
with salt.utils.winapi.Com():
conn = wmi.WMI()
comp = conn.Win32_ComputerSystem()[0]
# Return the results of the command as an error
@ -848,8 +847,8 @@ def unjoin_domain(username=None,
if disable:
unjoin_options |= NETSETUP_ACCT_DELETE
pythoncom.CoInitialize()
conn = wmi.WMI()
with salt.utils.winapi.Com():
conn = wmi.WMI()
comp = conn.Win32_ComputerSystem()[0]
err = comp.UnjoinDomainOrWorkgroup(Password=password,
UserName=username,
@ -892,8 +891,8 @@ def get_domain_workgroup():
salt 'minion-id' system.get_domain_workgroup
'''
pythoncom.CoInitialize()
conn = wmi.WMI()
with salt.utils.winapi.Com():
conn = wmi.WMI()
for computer in conn.Win32_ComputerSystem():
if computer.PartOfDomain:
return {'Domain': computer.Domain}

View file

@ -17,6 +17,7 @@ from datetime import datetime
# Import Salt libs
import salt.utils.platform
import salt.utils.winapi
# Import 3rd-party libraries
try:
@ -333,8 +334,8 @@ def list_tasks(location='\\'):
salt 'minion-id' task.list_tasks
'''
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list tasks from
@ -366,8 +367,8 @@ def list_folders(location='\\'):
salt 'minion-id' task.list_folders
'''
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
@ -401,8 +402,8 @@ def list_triggers(name, location='\\'):
salt 'minion-id' task.list_triggers <task_name>
'''
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
@ -437,8 +438,8 @@ def list_actions(name, location='\\'):
salt 'minion-id' task.list_actions <task_name>
'''
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
@ -499,8 +500,8 @@ def create_task(name,
return '{0} already exists'.format(name)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Create a new task definition
@ -584,8 +585,8 @@ def create_task_from_xml(name,
return 'Must specify either xml_text or xml_path'
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Load xml from file, overrides xml_text
@ -664,8 +665,8 @@ def create_folder(name, location='\\'):
return '{0} already exists'.format(name)
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
@ -879,8 +880,8 @@ def edit_task(name=None,
if name in list_tasks(location):
# Connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to create the task in
@ -1045,8 +1046,8 @@ def delete_task(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the task from
@ -1085,8 +1086,8 @@ def delete_folder(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
@ -1126,8 +1127,8 @@ def run(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
@ -1165,8 +1166,8 @@ def run_wait(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
@ -1222,8 +1223,8 @@ def stop(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
@ -1268,8 +1269,8 @@ def status(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder where the task is defined
@ -1303,8 +1304,8 @@ def info(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
@ -1493,8 +1494,8 @@ def add_action(name=None,
if name in list_tasks(location):
# Connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to create the task in
@ -1600,8 +1601,8 @@ def _clear_actions(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the actions from the task
@ -1992,8 +1993,8 @@ def add_trigger(name=None,
if name in list_tasks(location):
# Connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to create the task in
@ -2169,8 +2170,8 @@ def clear_triggers(name, location='\\'):
return '{0} not found in {1}'.format(name, location)
# Create the task service object
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the triggers from the task

View file

@ -9,7 +9,6 @@ Module for managing Windows Users
<module-provider-override>`.
:depends:
- pythoncom
- pywintypes
- win32api
- win32con
@ -38,6 +37,7 @@ except Exception:
import salt.utils.args
import salt.utils.dateutils
import salt.utils.platform
import salt.utils.winapi
from salt.ext import six
from salt.ext.six import string_types
from salt.exceptions import CommandExecutionError
@ -47,7 +47,6 @@ log = logging.getLogger(__name__)
try:
import pywintypes
import wmi
import pythoncom
import win32api
import win32con
import win32net
@ -989,8 +988,8 @@ def rename(name, new_name):
# Rename the user account
# Connect to WMI
pythoncom.CoInitialize()
c = wmi.WMI(find_classes=0)
with salt.utils.winapi.Com():
c = wmi.WMI(find_classes=0)
# Get the user object
try:

View file

@ -63,12 +63,12 @@ import logging
import salt.utils.platform
import salt.utils.versions
import salt.utils.win_update
import salt.utils.winapi
from salt.exceptions import CommandExecutionError
# Import 3rd-party libs
from salt.ext import six
try:
import pythoncom
import win32com.client
HAS_PYWIN32 = True
except ImportError:
@ -1057,6 +1057,7 @@ def set_wu_settings(level=None,
# work on Windows 10 / Server 2016. It is called in throughout this function
# like this:
#
# with salt.utils.winapi.Com():
# obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate')
# obj_au_settings = obj_au.Settings
# obj_au_settings.Save()
@ -1077,10 +1078,10 @@ def set_wu_settings(level=None,
ret = {'Success': True}
# Initialize the PyCom system
pythoncom.CoInitialize()
with salt.utils.winapi.Com():
# Create an AutoUpdate object
obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate')
# Create an AutoUpdate object
obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate')
# Create an AutoUpdate Settings Object
obj_au_settings = obj_au.Settings
@ -1174,7 +1175,8 @@ def set_wu_settings(level=None,
if msupdate is not None:
# Microsoft Update requires special handling
# First load the MS Update Service Manager
obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager')
with salt.utils.winapi.Com():
obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager')
# Give it a bogus name
obj_sm.ClientApplicationID = "My App"
@ -1275,10 +1277,9 @@ def get_wu_settings():
'Saturday']
# Initialize the PyCom system
pythoncom.CoInitialize()
# Create an AutoUpdate object
obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate')
with salt.utils.winapi.Com():
# Create an AutoUpdate object
obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate')
# Create an AutoUpdate Settings Object
obj_au_settings = obj_au.Settings
@ -1312,8 +1313,10 @@ def _get_msupdate_status():
'''
# To get the status of Microsoft Update we actually have to check the
# Microsoft Update Service Manager
# Create a ServiceManager Object
obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager')
# Initialize the PyCom system
with salt.utils.winapi.Com():
# Create a ServiceManager Object
obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager')
# Return a collection of loaded Services
col_services = obj_sm.Services

View file

@ -298,6 +298,7 @@ from salt.state import get_accumulator_dir as _get_accumulator_dir
if salt.utils.platform.is_windows():
import salt.utils.win_dacl
import salt.utils.win_functions
import salt.utils.winapi
# Import 3rd-party libs
from salt.ext import six
@ -1207,7 +1208,8 @@ def _shortcut_check(name,
), pchanges
if os.path.isfile(name):
shell = win32com.client.Dispatch("WScript.Shell")
with salt.utils.winapi.Com():
shell = win32com.client.Dispatch("WScript.Shell")
scut = shell.CreateShortcut(name)
state_checks = [scut.TargetPath.lower() == target.lower()]
if arguments is not None:
@ -6851,7 +6853,8 @@ def shortcut(
# This will just load the shortcut if it already exists
# It won't create the file until calling scut.Save()
shell = win32com.client.Dispatch("WScript.Shell")
with salt.utils.winapi.Com():
shell = win32com.client.Dispatch("WScript.Shell")
scut = shell.CreateShortcut(name)
# The shortcut target will automatically be created with its

View file

@ -10,6 +10,7 @@ import subprocess
# Import Salt libs
import salt.utils.args
import salt.utils.data
import salt.utils.winapi
from salt.ext import six
from salt.ext.six.moves import range
from salt.exceptions import CommandExecutionError
@ -17,7 +18,6 @@ from salt.exceptions import CommandExecutionError
# Import 3rd-party libs
try:
import win32com.client
import pythoncom
import pywintypes
HAS_PYWIN32 = True
except ImportError:
@ -68,7 +68,8 @@ class Updates(object):
Initialize the updates collection. Can be accessed via
``Updates.updates``
'''
self.updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
with salt.utils.winapi.Com():
self.updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
def count(self):
'''
@ -274,13 +275,13 @@ class WindowsUpdateAgent(object):
Need to look at the possibility of loading this into ``__context__``
'''
# Initialize the PyCom system
pythoncom.CoInitialize()
with salt.utils.winapi.Com():
# Create a session with the Windows Update Agent
self._session = win32com.client.Dispatch('Microsoft.Update.Session')
# Create a session with the Windows Update Agent
self._session = win32com.client.Dispatch('Microsoft.Update.Session')
# Create Collection for Updates
self._updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
# Create Collection for Updates
self._updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
self.refresh()
@ -572,7 +573,8 @@ class WindowsUpdateAgent(object):
# Initialize the downloader object and list collection
downloader = self._session.CreateUpdateDownloader()
self._session.ClientApplicationID = 'Salt: Download Update'
download_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
with salt.utils.winapi.Com():
download_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
ret = {'Updates': {}}
@ -683,7 +685,8 @@ class WindowsUpdateAgent(object):
installer = self._session.CreateUpdateInstaller()
self._session.ClientApplicationID = 'Salt: Install Update'
install_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
with salt.utils.winapi.Com():
install_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
ret = {'Updates': {}}
@ -802,7 +805,8 @@ class WindowsUpdateAgent(object):
installer = self._session.CreateUpdateInstaller()
self._session.ClientApplicationID = 'Salt: Install Update'
uninstall_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
with salt.utils.winapi.Com():
uninstall_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl')
ret = {'Updates': {}}
@ -999,8 +1003,7 @@ def needs_reboot():
'''
# Initialize the PyCom system
pythoncom.CoInitialize()
# Create an AutoUpdate object
obj_sys = win32com.client.Dispatch('Microsoft.Update.SystemInfo')
with salt.utils.winapi.Com():
# Create an AutoUpdate object
obj_sys = win32com.client.Dispatch('Microsoft.Update.SystemInfo')
return salt.utils.data.is_true(obj_sys.RebootRequired)

View file

@ -120,7 +120,10 @@ class DiskUsageBeaconTestCase(TestCase, LoaderModuleMockMixin):
ret = diskusage.beacon(config)
self.assertEqual(ret, [{'diskusage': 50, 'mount': '/'}])
def test_diskusage_windows(self):
def test_diskusage_windows_single_slash(self):
r'''
This tests new behavior (C:\)
'''
disk_usage_mock = Mock(return_value=WINDOWS_STUB_DISK_USAGE)
with patch('salt.utils.platform.is_windows',
MagicMock(return_value=True)):
@ -136,6 +139,44 @@ class DiskUsageBeaconTestCase(TestCase, LoaderModuleMockMixin):
ret = diskusage.beacon(config)
self.assertEqual(ret, [{'diskusage': 50, 'mount': 'C:\\'}])
def test_diskusage_windows_double_slash(self):
'''
This tests original behavior (C:\\)
'''
disk_usage_mock = Mock(return_value=WINDOWS_STUB_DISK_USAGE)
with patch('salt.utils.platform.is_windows',
MagicMock(return_value=True)):
with patch('psutil.disk_partitions',
MagicMock(return_value=WINDOWS_STUB_DISK_PARTITION)), \
patch('psutil.disk_usage', disk_usage_mock):
config = [{'C:\\\\': '50%'}]
ret = diskusage.validate(config)
self.assertEqual(ret, (True, 'Valid beacon configuration'))
ret = diskusage.beacon(config)
self.assertEqual(ret, [{'diskusage': 50, 'mount': 'C:\\'}])
def test_diskusage_windows_lowercase(self):
r'''
This tests lowercase drive letter (c:\)
'''
disk_usage_mock = Mock(return_value=WINDOWS_STUB_DISK_USAGE)
with patch('salt.utils.platform.is_windows',
MagicMock(return_value=True)):
with patch('psutil.disk_partitions',
MagicMock(return_value=WINDOWS_STUB_DISK_PARTITION)), \
patch('psutil.disk_usage', disk_usage_mock):
config = [{'c:\\': '50%'}]
ret = diskusage.validate(config)
self.assertEqual(ret, (True, 'Valid beacon configuration'))
ret = diskusage.beacon(config)
self.assertEqual(ret, [{'diskusage': 50, 'mount': 'C:\\'}])
def test_diskusage_windows_match_regex(self):
disk_usage_mock = Mock(return_value=WINDOWS_STUB_DISK_USAGE)
with patch('salt.utils.platform.is_windows',

View file

@ -38,6 +38,11 @@ class WinSystemTestCase(TestCase, LoaderModuleMockMixin):
now.day, now.hour, now.minute,
now.second, now.microsecond])
modules_globals['win32api'] = win32api
win32net = types.ModuleType(str('win32net')) # future lint: disable=blacklisted-function
win32net.NetServerGetInfo = MagicMock()
win32net.NetServerSetInfo = MagicMock()
modules_globals['win32net'] = win32net
return {win_system: modules_globals}
def test_halt(self):
@ -177,14 +182,15 @@ class WinSystemTestCase(TestCase, LoaderModuleMockMixin):
'''
Test to set the Windows computer description
'''
mock = MagicMock(return_value=True)
with patch.dict(win_system.__salt__, {'cmd.run': mock}):
mock = MagicMock(return_value="Salt's comp")
with patch.object(win_system, 'get_computer_desc', mock):
self.assertDictEqual(win_system.set_computer_desc(
"Salt's comp"
),
{'Computer Description': "Salt's comp"})
mock = MagicMock()
mock_get_info = MagicMock(return_value={'comment': ''})
mock_get_desc = MagicMock(return_value="Salt's comp")
with patch('salt.modules.win_system.win32net.NetServerGetInfo', mock_get_info), \
patch('salt.modules.win_system.win32net.NetServerSetInfo', mock), \
patch.object(win_system, 'get_computer_desc', mock_get_desc):
self.assertDictEqual(
win_system.set_computer_desc("Salt's comp"),
{'Computer Description': "Salt's comp"})
@skipIf(not win_system.HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_get_computer_desc(self):