mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2015.5' into '2015.8'
Conflicts: - salt/modules/win_update.py - salt/states/win_update.py
This commit is contained in:
commit
023ad4635c
3 changed files with 135 additions and 86 deletions
|
@ -9,6 +9,49 @@ Module for running windows updates.
|
|||
|
||||
.. versionadded:: 2014.7.0
|
||||
|
||||
Set windows updates to run by category. Default behavior is to install
|
||||
all updates that do not require user interaction to complete.
|
||||
Optionally set ``categories`` to a category of your choice to only
|
||||
install certain updates. Default is to set to install all available but driver updates.
|
||||
The following example will install all Security and Critical Updates,
|
||||
and download but not install standard updates.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' win_update.install_updates categories="['Critical Updates', 'Security Updates']"
|
||||
|
||||
You can also specify a number of features about the update to have a
|
||||
fine grain approach to specific types of updates. These are the following
|
||||
features/states of updates available for configuring:
|
||||
.. code-block:: text
|
||||
'UI' - User interaction required, skipped by default
|
||||
'downloaded' - Already downloaded, included by default
|
||||
'present' - Present on computer, included by default
|
||||
'installed' - Already installed, skipped by default
|
||||
'reboot' - Reboot required, included by default
|
||||
'hidden' - Skip hidden updates, skipped by default
|
||||
'software' - Software updates, included by default
|
||||
'driver' - Driver updates, included by default
|
||||
|
||||
The following example installs all updates that don't require a reboot:
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' win_update.install_updates skips="[{'reboot':True}]"
|
||||
|
||||
|
||||
Once installed Salt will return a similar output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
2 : Windows Server 2012 Update (KB123456)
|
||||
4 : Internet Explorer Security Update (KB098765)
|
||||
2 : Malware Definition Update (KB321456)
|
||||
...
|
||||
|
||||
The number at the beginning of the line is an OperationResultCode from the Windows Update Agent,
|
||||
it's enumeration is described here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387095(v=vs.85).aspx.
|
||||
The result code is then followed by the update name and its KB identifier.
|
||||
|
||||
'''
|
||||
# pylint: disable=invalid-name,missing-docstring
|
||||
|
||||
|
@ -68,7 +111,7 @@ def _gather_update_categories(updateCollection):
|
|||
class PyWinUpdater(object):
|
||||
def __init__(self, categories=None, skipUI=True, skipDownloaded=False,
|
||||
skipInstalled=True, skipReboot=False, skipPresent=False,
|
||||
softwareUpdates=True, driverUpdates=False, skipHidden=True):
|
||||
skipSoftwareUpdates=False, skipDriverUpdates=False, skipHidden=True):
|
||||
log.debug('CoInitializing the pycom system')
|
||||
pythoncom.CoInitialize()
|
||||
|
||||
|
@ -79,8 +122,8 @@ class PyWinUpdater(object):
|
|||
self.skipPresent = skipPresent
|
||||
self.skipHidden = skipHidden
|
||||
|
||||
self.softwareUpdates = softwareUpdates
|
||||
self.driverUpdates = driverUpdates
|
||||
self.skipSoftwareUpdates = skipSoftwareUpdates
|
||||
self.skipDriverUpdates = skipDriverUpdates
|
||||
|
||||
# the list of categories that the user wants to be searched for.
|
||||
self.categories = categories
|
||||
|
@ -177,24 +220,32 @@ class PyWinUpdater(object):
|
|||
|
||||
if self.skipInstalled:
|
||||
searchParams.append('IsInstalled=0')
|
||||
else:
|
||||
searchParams.append('IsInstalled=1')
|
||||
|
||||
if self.skipHidden:
|
||||
searchParams.append('IsHidden=0')
|
||||
else:
|
||||
searchParams.append('IsHidden=1')
|
||||
|
||||
if self.skipReboot:
|
||||
searchParams.append('RebootRequired=0')
|
||||
else:
|
||||
searchParams.append('RebootRequired=1')
|
||||
|
||||
if self.skipPresent:
|
||||
searchParams.append('IsPresent=0')
|
||||
else:
|
||||
searchParams.append('IsPresent=1')
|
||||
|
||||
for i in searchParams:
|
||||
search_string += '{0} and '.format(i)
|
||||
|
||||
if self.softwareUpdates and self.driverUpdates:
|
||||
if not self.skipSoftwareUpdates and not self.skipDriverUpdates:
|
||||
search_string += 'Type=\'Software\' or Type=\'Driver\''
|
||||
elif self.softwareUpdates:
|
||||
elif not self.skipSoftwareUpdates:
|
||||
search_string += 'Type=\'Software\''
|
||||
elif self.driverUpdates:
|
||||
elif not self.skipDriverUpdates:
|
||||
search_string += 'Type=\'Driver\''
|
||||
else:
|
||||
return False
|
||||
|
@ -322,43 +373,34 @@ class PyWinUpdater(object):
|
|||
def GetAvailableCategories(self):
|
||||
return self.foundCategories
|
||||
|
||||
def SetIncludes(self, includes):
|
||||
if includes:
|
||||
for inc in includes:
|
||||
value = inc[next(six.iterkeys(inc))]
|
||||
include = next(six.iterkeys(inc))
|
||||
self.SetInclude(include, value)
|
||||
log.debug('was asked to set {0} to {1}'.format(include, value))
|
||||
def SetSkips(self, skips):
|
||||
if skips:
|
||||
for i in skips:
|
||||
value = i[next(i.iterkeys())]
|
||||
skip = next(i.iterkeys())
|
||||
self.SetSkip(skip, value)
|
||||
log.debug('was asked to set {0} to {1}'.format(skip, value))
|
||||
|
||||
def SetInclude(self, include, state):
|
||||
if include == 'UI':
|
||||
def SetSkip(self, skip, state):
|
||||
if skip == 'UI':
|
||||
self.skipUI = state
|
||||
elif include == 'downloaded':
|
||||
elif skip == 'downloaded':
|
||||
self.skipDownloaded = state
|
||||
elif include == 'installed':
|
||||
elif skip == 'installed':
|
||||
self.skipInstalled = state
|
||||
elif include == 'reboot':
|
||||
elif skip == 'reboot':
|
||||
self.skipReboot = state
|
||||
elif include == 'present':
|
||||
elif skip == 'present':
|
||||
self.skipPresent = state
|
||||
elif include == 'software':
|
||||
self.softwareUpdates = state
|
||||
elif include == 'driver':
|
||||
self.driverUpdates = state
|
||||
log.debug('new search state: \n\t'
|
||||
'UI: {0}\n\t'
|
||||
'Download: {1}\n\t'
|
||||
'Installed: {2}\n\t'
|
||||
'reboot :{3}\n\t'
|
||||
'Present: {4}\n\t'
|
||||
'software: {5}\n\t'
|
||||
'driver: {6}'.format(self.skipUI,
|
||||
self.skipDownloaded,
|
||||
self.skipInstalled,
|
||||
self.skipReboot,
|
||||
self.skipPresent,
|
||||
self.softwareUpdates,
|
||||
self.driverUpdates))
|
||||
elif skip == 'hidden':
|
||||
self.skipHidden = state
|
||||
elif skip == 'software':
|
||||
self.skipSoftwareUpdates = state
|
||||
elif skip == 'driver':
|
||||
self.skipDriverUpdates = state
|
||||
log.debug('new search state: \n\tUI: {0}\n\tDownload: {1}\n\tInstalled: {2}\n\treboot :{3}\n\tPresent: {4}\n\thidden: {5}\n\tsoftware: {6}\n\tdriver: {7}'.format(
|
||||
self.skipUI, self.skipDownloaded, self.skipInstalled, self.skipReboot,
|
||||
self.skipPresent, self.skipHidden, self.skipSoftwareUpdates, self.skipDriverUpdates))
|
||||
|
||||
def __str__(self):
|
||||
results = 'There are {0} updates, by category there are:\n'.format(
|
||||
|
@ -458,7 +500,7 @@ def _install(quidditch, retries=5):
|
|||
|
||||
# this is where the actual functions available to salt begin.
|
||||
|
||||
def list_updates(verbose=False, includes=None, retries=5, categories=None):
|
||||
def list_updates(verbose=False, skips=None, retries=5, categories=None):
|
||||
'''
|
||||
Returns a summary of available updates, grouped into their non-mutually
|
||||
exclusive categories.
|
||||
|
@ -501,7 +543,7 @@ def list_updates(verbose=False, includes=None, retries=5, categories=None):
|
|||
quidditch = PyWinUpdater()
|
||||
if categories:
|
||||
quidditch.SetCategories(categories)
|
||||
quidditch.SetIncludes(includes)
|
||||
quidditch.SetSkips(skips)
|
||||
|
||||
# this is where we be seeking the things! yar!
|
||||
comment, passed, retries = _search(quidditch, retries)
|
||||
|
@ -513,7 +555,7 @@ def list_updates(verbose=False, includes=None, retries=5, categories=None):
|
|||
return str(quidditch)
|
||||
|
||||
|
||||
def download_updates(includes=None, retries=5, categories=None):
|
||||
def download_updates(skips=None, retries=5, categories=None):
|
||||
'''
|
||||
Downloads all available updates, skipping those that require user
|
||||
interaction.
|
||||
|
@ -555,7 +597,7 @@ def download_updates(includes=None, retries=5, categories=None):
|
|||
log.debug('categories to search for are: {0}'.format(str(categories)))
|
||||
quidditch = PyWinUpdater(skipDownloaded=True)
|
||||
quidditch.SetCategories(categories)
|
||||
quidditch.SetIncludes(includes)
|
||||
quidditch.SetSkips(skips)
|
||||
|
||||
# this is where we be seeking the things! yar!
|
||||
comment, passed, retries = _search(quidditch, retries)
|
||||
|
@ -574,7 +616,7 @@ def download_updates(includes=None, retries=5, categories=None):
|
|||
return 'Windows is up to date. \n{0}'.format(comment)
|
||||
|
||||
|
||||
def install_updates(includes=None, retries=5, categories=None):
|
||||
def install_updates(skips=None, retries=5, categories=None):
|
||||
'''
|
||||
Downloads and installs all available updates, skipping those that require
|
||||
user interaction.
|
||||
|
@ -621,7 +663,7 @@ def install_updates(includes=None, retries=5, categories=None):
|
|||
log.debug('categories to search for are: {0}'.format(str(categories)))
|
||||
quidditch = PyWinUpdater()
|
||||
quidditch.SetCategories(categories)
|
||||
quidditch.SetIncludes(includes)
|
||||
quidditch.SetSkips(skips)
|
||||
|
||||
# this is where we be seeking the things! yar!
|
||||
comment, passed, retries = _search(quidditch, retries)
|
||||
|
|
|
@ -21,9 +21,13 @@ and download but not install standard updates.
|
|||
- categories:
|
||||
- 'Critical Updates'
|
||||
- 'Security Updates'
|
||||
- skips:
|
||||
- downloaded
|
||||
win_update.downloaded:
|
||||
- categories:
|
||||
- 'Updates'
|
||||
- skips:
|
||||
- downloaded
|
||||
|
||||
You can also specify a number of features about the update to have a
|
||||
fine grain approach to specific types of updates. These are the following
|
||||
|
@ -32,21 +36,19 @@ features/states of updates available for configuring:
|
|||
.. code-block:: text
|
||||
|
||||
'UI' - User interaction required, skipped by default
|
||||
'downloaded' - Already downloaded, skipped by default (downloading)
|
||||
'present' - Present on computer, included by default (installing)
|
||||
'downloaded' - Already downloaded, included by default
|
||||
'present' - Present on computer, skipped by default
|
||||
'installed' - Already installed, skipped by default
|
||||
'reboot' - Reboot required, included by default
|
||||
'hidden' - skip those updates that have been hidden.
|
||||
'hidden' - Skip updates that have been hidden, skipped by default
|
||||
'software' - Software updates, included by default
|
||||
'driver' - driver updates, skipped by default
|
||||
'driver' - driver updates, included by default
|
||||
|
||||
The following example installs all driver updates that don't require a reboot:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
gryffindor:
|
||||
win_update.installed:
|
||||
- includes:
|
||||
- skips:
|
||||
- driver: True
|
||||
- software: False
|
||||
- reboot: False
|
||||
|
@ -54,7 +56,6 @@ The following example installs all driver updates that don't require a reboot:
|
|||
To just update your windows machine, add this your sls:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
updates:
|
||||
win_update.installed
|
||||
'''
|
||||
|
@ -113,9 +114,9 @@ def _gather_update_categories(updateCollection):
|
|||
|
||||
|
||||
class PyWinUpdater(object):
|
||||
def __init__(self, categories=None, skipUI=True, skipDownloaded=True,
|
||||
skipInstalled=True, skipReboot=False, skipPresent=True,
|
||||
softwareUpdates=True, driverUpdates=False, skipHidden=True):
|
||||
def __init__(self, categories=None, skipUI=True, skipDownloaded=False,
|
||||
skipInstalled=True, skipReboot=False, skipPresent=False,
|
||||
skipSoftwareUpdates=False, skipDriverUpdates=False, skipHidden=True):
|
||||
log.debug('CoInitializing the pycom system')
|
||||
pythoncom.CoInitialize()
|
||||
|
||||
|
@ -127,8 +128,8 @@ class PyWinUpdater(object):
|
|||
self.skipPresent = skipPresent
|
||||
self.skipHidden = skipHidden
|
||||
|
||||
self.softwareUpdates = softwareUpdates
|
||||
self.driverUpdates = driverUpdates
|
||||
self.skipSoftwareUpdates = skipSoftwareUpdates
|
||||
self.skipDriverUpdates = skipDriverUpdates
|
||||
self.categories = categories
|
||||
self.foundCategories = None
|
||||
# pylint: enable=invalid-name
|
||||
|
@ -201,9 +202,9 @@ class PyWinUpdater(object):
|
|||
searchParams.append('IsHidden=1')
|
||||
|
||||
if self.skipReboot:
|
||||
searchParams.append('RebootRequired=1')
|
||||
else:
|
||||
searchParams.append('RebootRequired=0')
|
||||
else:
|
||||
searchParams.append('RebootRequired=1')
|
||||
|
||||
if self.skipPresent:
|
||||
searchParams.append('IsPresent=0')
|
||||
|
@ -216,11 +217,11 @@ class PyWinUpdater(object):
|
|||
else:
|
||||
search_string += '{0} and '.format(searchParams[1])
|
||||
|
||||
if self.softwareUpdates and self.driverUpdates:
|
||||
if not self.skipSoftwareUpdates and not self.skipDriverUpdates:
|
||||
search_string += 'Type=\'Software\' or Type=\'Driver\''
|
||||
elif self.softwareUpdates:
|
||||
elif not self.skipSoftwareUpdates:
|
||||
search_string += 'Type=\'Software\''
|
||||
elif self.driverUpdates:
|
||||
elif not self.skipDriverUpdates:
|
||||
search_string += 'Type=\'Driver\''
|
||||
else:
|
||||
return False
|
||||
|
@ -301,32 +302,34 @@ class PyWinUpdater(object):
|
|||
def GetAvailableCategories(self):
|
||||
return self.foundCategories
|
||||
|
||||
def SetIncludes(self, includes):
|
||||
if includes:
|
||||
for i in includes:
|
||||
value = i[next(six.iterkeys(i))]
|
||||
include = next(six.iterkeys(i))
|
||||
self.SetInclude(include, value)
|
||||
log.debug('was asked to set {0} to {1}'.format(include, value))
|
||||
def SetSkips(self, skips):
|
||||
if skips:
|
||||
for i in skips:
|
||||
value = i[next(i.iterkeys())]
|
||||
skip = next(i.iterkeys())
|
||||
self.SetSkip(skip, value)
|
||||
log.debug('was asked to set {0} to {1}'.format(skip, value))
|
||||
|
||||
def SetInclude(self, include, state):
|
||||
if include == 'UI':
|
||||
def SetSkip(self, skip, state):
|
||||
if skip == 'UI':
|
||||
self.skipUI = state
|
||||
elif include == 'downloaded':
|
||||
elif skip == 'downloaded':
|
||||
self.skipDownloaded = state
|
||||
elif include == 'installed':
|
||||
elif skip == 'installed':
|
||||
self.skipInstalled = state
|
||||
elif include == 'reboot':
|
||||
elif skip == 'reboot':
|
||||
self.skipReboot = state
|
||||
elif include == 'present':
|
||||
elif skip == 'present':
|
||||
self.skipPresent = state
|
||||
elif include == 'software':
|
||||
self.softwareUpdates = state
|
||||
elif include == 'driver':
|
||||
self.driverUpdates = state
|
||||
log.debug('new search state: \n\tUI: {0}\n\tDownload: {1}\n\tInstalled: {2}\n\treboot :{3}\n\tPresent: {4}\n\tsoftware: {5}\n\tdriver: {6}'.format(
|
||||
elif skip == 'hidden':
|
||||
self.skipHidden = state
|
||||
elif skip == 'software':
|
||||
self.skipSoftwareUpdates = state
|
||||
elif skip == 'driver':
|
||||
self.skipDriverUpdates = state
|
||||
log.debug('new search state: \n\tUI: {0}\n\tDownload: {1}\n\tInstalled: {2}\n\treboot :{3}\n\tPresent: {4}\n\thidden: {5}\n\tsoftware: {6}\n\tdriver: {7}'.format(
|
||||
self.skipUI, self.skipDownloaded, self.skipInstalled, self.skipReboot,
|
||||
self.skipPresent, self.softwareUpdates, self.driverUpdates))
|
||||
self.skipPresent, self.skipHidden, self.skipSoftwareUpdates, self.skipDriverUpdates))
|
||||
|
||||
|
||||
def _search(win_updater, retries=5):
|
||||
|
@ -400,7 +403,7 @@ def _install(win_updater, retries=5):
|
|||
return (comment, True, retries)
|
||||
|
||||
|
||||
def installed(name, categories=None, includes=None, retries=10):
|
||||
def installed(name, categories=None, skips=None, retries=10):
|
||||
'''
|
||||
Install specified windows updates.
|
||||
|
||||
|
@ -421,7 +424,7 @@ def installed(name, categories=None, includes=None, retries=10):
|
|||
Security Updates
|
||||
Update Rollups
|
||||
|
||||
includes:
|
||||
skips:
|
||||
a list of features of the updates to cull by. Available features:
|
||||
|
||||
.. code-block:: text
|
||||
|
@ -448,7 +451,7 @@ def installed(name, categories=None, includes=None, retries=10):
|
|||
log.debug('categories to search for are: {0}'.format(categories))
|
||||
win_updater = PyWinUpdater()
|
||||
win_updater.SetCategories(categories)
|
||||
win_updater.SetIncludes(includes)
|
||||
win_updater.SetSkips(skips)
|
||||
|
||||
# this is where we be seeking the things! yar!
|
||||
comment, passed, retries = _search(win_updater, retries)
|
||||
|
@ -478,7 +481,7 @@ def installed(name, categories=None, includes=None, retries=10):
|
|||
return ret
|
||||
|
||||
|
||||
def downloaded(name, categories=None, includes=None, retries=10):
|
||||
def downloaded(name, categories=None, skips=None, retries=10):
|
||||
'''
|
||||
Cache updates for later install.
|
||||
|
||||
|
@ -499,7 +502,7 @@ def downloaded(name, categories=None, includes=None, retries=10):
|
|||
Security Updates
|
||||
Update Rollups
|
||||
|
||||
includes:
|
||||
skips:
|
||||
a list of features of the updates to cull by. Available features:
|
||||
|
||||
.. code-block:: text
|
||||
|
@ -526,7 +529,7 @@ def downloaded(name, categories=None, includes=None, retries=10):
|
|||
log.debug('categories to search for are: {0}'.format(categories))
|
||||
win_updater = PyWinUpdater()
|
||||
win_updater.SetCategories(categories)
|
||||
win_updater.SetIncludes(includes)
|
||||
win_updater.SetSkips(skips)
|
||||
|
||||
# this is where we be seeking the things! yar!
|
||||
comment, passed, retries = _search(win_updater, retries)
|
||||
|
|
|
@ -57,6 +57,10 @@ class MockPyWinUpdater(object):
|
|||
'''
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def SetSkips(arg):
|
||||
return True
|
||||
|
||||
|
||||
@patch('salt.states.win_update.PyWinUpdater', MockPyWinUpdater)
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
|
|
Loading…
Add table
Reference in a new issue