mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #33771 from twangboy/win_dism
Additional functionality to win_dism.py
This commit is contained in:
commit
01aaf3e2a9
5 changed files with 1476 additions and 220 deletions
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Install features/packages for Windows using DISM, which
|
||||
is useful for minions not running server versions of
|
||||
windows
|
||||
Install features/packages for Windows using DISM, which is useful for minions
|
||||
not running server versions of Windows. Some functions are only available on
|
||||
Windows 10.
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
@ -22,132 +22,368 @@ def __virtual__():
|
|||
'''
|
||||
Only work on Windows
|
||||
'''
|
||||
if salt.utils.is_windows():
|
||||
return __virtualname__
|
||||
return False
|
||||
if not salt.utils.is_windows():
|
||||
return False, "Only available on Windows systems"
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def _install_component(name, component_type, install_name, source=None, limit_access=False):
|
||||
cmd = 'DISM /Online /{0}-{1} /{1}Name:{2}'.format(install_name, component_type, name)
|
||||
if source:
|
||||
cmd += ' /Source:{0}'.format(source)
|
||||
if limit_access:
|
||||
cmd += ' /LimitAccess'
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def _uninstall_component(name, component_type, uninstall_name):
|
||||
cmd = 'DISM /Online /{0}-{1} /{1}Name:{2}'.format(uninstall_name, component_type, name)
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def _get_components(type_regex, plural_type, install_value):
|
||||
cmd = 'DISM /Online /Get-{0}'.format(plural_type)
|
||||
def _get_components(type_regex, plural_type, install_value, image=None):
|
||||
cmd = ['DISM',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Get-{0}'.format(plural_type)]
|
||||
out = __salt__['cmd.run'](cmd)
|
||||
pattern = r'{0} : (.*)\r\n.*State : {1}\r\n'.format(type_regex, install_value)
|
||||
pattern = r'{0} : (.*)\r\n.*State : {1}\r\n'\
|
||||
.format(type_regex, install_value)
|
||||
capabilities = re.findall(pattern, out, re.MULTILINE)
|
||||
capabilities.sort()
|
||||
return capabilities
|
||||
|
||||
|
||||
def install_capability(capability, source=None, limit_access=False):
|
||||
def add_capability(capability,
|
||||
source=None,
|
||||
limit_access=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a capability
|
||||
|
||||
Args:
|
||||
capability (str): The capability to install
|
||||
source (Optional[str]): The optional source of the capability. Default
|
||||
is set by group policy and can be Windows Update.
|
||||
limit_access (Optional[bool]): Prevent DISM from contacting Windows
|
||||
Update for the source package
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Raises:
|
||||
NotImplementedError: For all versions of Windows that are not Windows 10
|
||||
and later. Server editions of Windows use ServerManager instead.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.install_capability Tools.Graphics.DirectX~~~~0.0.1.0
|
||||
|
||||
capability
|
||||
The capability in which to install
|
||||
|
||||
source
|
||||
The optional source of the capability
|
||||
|
||||
limit_access
|
||||
Prevent DISM from contacting Windows Update for online images
|
||||
|
||||
salt '*' dism.add_capability Tools.Graphics.DirectX~~~~0.0.1.0
|
||||
'''
|
||||
return _install_component(capability, "Capability", "Add", source, limit_access)
|
||||
if salt.utils.version_cmp(__grains__['osversion'], '10') == -1:
|
||||
raise NotImplementedError(
|
||||
'`install_capability` is not available on this version of Windows: '
|
||||
'{0}'.format(__grains__['osversion']))
|
||||
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Add-Capability',
|
||||
'/CapabilityName:{0}'.format(capability)]
|
||||
|
||||
if source:
|
||||
cmd.append('/Source:{0}'.format(source))
|
||||
if limit_access:
|
||||
cmd.append('/LimitAccess')
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def uninstall_capability(capability):
|
||||
def remove_capability(capability, image=None, restart=False):
|
||||
'''
|
||||
Uninstall a capability
|
||||
|
||||
Args:
|
||||
capability(str): The capability to be removed
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Raises:
|
||||
NotImplementedError: For all versions of Windows that are not Windows 10
|
||||
and later. Server editions of Windows use ServerManager instead.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.uninstall_capability Tools.Graphics.DirectX~~~~0.0.1.0
|
||||
|
||||
capability
|
||||
The capability in which to uninstall
|
||||
|
||||
salt '*' dism.remove_capability Tools.Graphics.DirectX~~~~0.0.1.0
|
||||
'''
|
||||
return _uninstall_component(capability, "Capability", "Remove")
|
||||
if salt.utils.version_cmp(__grains__['osversion'], '10') == -1:
|
||||
raise NotImplementedError(
|
||||
'`uninstall_capability` is not available on this version of '
|
||||
'Windows: {0}'.format(__grains__['osversion']))
|
||||
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Remove-Capability',
|
||||
'/CapabilityName:{0}'.format(capability)]
|
||||
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def installed_capabilities():
|
||||
def get_capabilities(image=None):
|
||||
'''
|
||||
List all capabilities on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: For all versions of Windows that are not Windows 10
|
||||
and later. Server editions of Windows use ServerManager instead.
|
||||
|
||||
Returns:
|
||||
list: A list of capabilities
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.get_capabilities
|
||||
'''
|
||||
if salt.utils.version_cmp(__grains__['osversion'], '10') == -1:
|
||||
raise NotImplementedError(
|
||||
'`installed_capabilities` is not available on this version of '
|
||||
'Windows: {0}'.format(__grains__['osversion']))
|
||||
|
||||
cmd = ['DISM',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Get-Capabilities']
|
||||
out = __salt__['cmd.run'](cmd)
|
||||
|
||||
pattern = r'Capability Identity : (.*)\r\n'
|
||||
capabilities = re.findall(pattern, out, re.MULTILINE)
|
||||
capabilities.sort()
|
||||
|
||||
return capabilities
|
||||
|
||||
|
||||
def installed_capabilities(image=None):
|
||||
'''
|
||||
List the capabilities installed on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: For all versions of Windows that are not Windows 10
|
||||
and later. Server editions of Windows use ServerManager instead.
|
||||
|
||||
Returns:
|
||||
list: A list of installed capabilities
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.installed_capabilities
|
||||
'''
|
||||
if salt.utils.version_cmp(__grains__['osversion'], '10') == -1:
|
||||
raise NotImplementedError(
|
||||
'`installed_capabilities` is not available on this version of '
|
||||
'Windows: {0}'.format(__grains__['osversion']))
|
||||
return _get_components("Capability Identity", "Capabilities", "Installed")
|
||||
|
||||
|
||||
def install_feature(capability, source=None, limit_access=False):
|
||||
def available_capabilities(image=None):
|
||||
'''
|
||||
List the capabilities available on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: For all versions of Windows that are not Windows 10
|
||||
and later. Server editions of Windows use ServerManager instead.
|
||||
|
||||
Returns:
|
||||
list: A list of available capabilities
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.installed_capabilities
|
||||
'''
|
||||
if salt.utils.version_cmp(__grains__['osversion'], '10') == -1:
|
||||
raise NotImplementedError(
|
||||
'`installed_capabilities` is not available on this version of '
|
||||
'Windows: {0}'.format(__grains__['osversion']))
|
||||
return _get_components("Capability Identity", "Capabilities", "Not Present")
|
||||
|
||||
|
||||
def add_feature(feature,
|
||||
package=None,
|
||||
source=None,
|
||||
limit_access=False,
|
||||
enable_parent=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a feature using DISM
|
||||
|
||||
CLI Example:
|
||||
Args:
|
||||
feature (str): The feature to install
|
||||
package (Optional[str]): The parent package for the feature. You do not
|
||||
have to specify the package if it is the Windows Foundation Package.
|
||||
Otherwise, use package to specify the parent package of the feature
|
||||
source (Optional[str]): The optional source of the capability. Default
|
||||
is set by group policy and can be Windows Update
|
||||
limit_access (Optional[bool]): Prevent DISM from contacting Windows
|
||||
Update for the source package
|
||||
enable_parent (Optional[bool]): True will enable all parent features of
|
||||
the specified feature
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.install_feature NetFx3
|
||||
|
||||
feature
|
||||
The feature in which to install
|
||||
|
||||
source
|
||||
The optional source of the feature
|
||||
|
||||
limit_access
|
||||
Prevent DISM from contacting Windows Update for online images
|
||||
|
||||
'''
|
||||
return _install_component(capability, "Feature", "Enable", source, limit_access)
|
||||
|
||||
|
||||
def uninstall_feature(capability):
|
||||
'''
|
||||
Uninstall a feature
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.uninstall_feature NetFx3
|
||||
|
||||
feature
|
||||
The feature in which to uninstall
|
||||
|
||||
salt '*' dism.add_feature NetFx3
|
||||
'''
|
||||
return _uninstall_component(capability, "Feature", "Disable")
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Enable-Feature',
|
||||
'/FeatureName:{0}'.format(feature)]
|
||||
if package:
|
||||
cmd.append('/PackageName:{0}'.format(package))
|
||||
if source:
|
||||
cmd.append('/Source:{0}'.format(source))
|
||||
if limit_access:
|
||||
cmd.append('/LimitAccess')
|
||||
if enable_parent:
|
||||
cmd.append('/All')
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def installed_features():
|
||||
def remove_feature(feature, remove_payload=False, image=None, restart=False):
|
||||
'''
|
||||
Disables the feature.
|
||||
|
||||
Args:
|
||||
feature (str): The feature to uninstall
|
||||
remove_payload (Optional[bool]): Remove the feature's payload. Must
|
||||
supply source when enabling in the future.
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.remove_feature NetFx3
|
||||
'''
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Disable-Feature',
|
||||
'/FeatureName:{0}'.format(feature)]
|
||||
|
||||
if remove_payload:
|
||||
cmd.append('/Remove')
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def get_features(package=None, image=None):
|
||||
'''
|
||||
List features on the system or in a package
|
||||
|
||||
Args:
|
||||
package (Optional[str]): The full path to the package. Can be either a
|
||||
.cab file or a folder. Should point to the original source of the
|
||||
package, not to where the file is installed. You cannot use this
|
||||
command to get package information for .msu files
|
||||
|
||||
This can also be the name of a package as listed in
|
||||
``dism.installed_packages``
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Returns:
|
||||
list: A list of features
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Return all features on the system
|
||||
salt '*' dism.get_features
|
||||
|
||||
# Return all features in package.cab
|
||||
salt '*' dism.get_features C:\\packages\\package.cab
|
||||
|
||||
# Return all features in the calc package
|
||||
salt '*' dism.get_features Microsoft.Windows.Calc.Demo~6595b6144ccf1df~x86~en~1.0.0.0
|
||||
'''
|
||||
cmd = ['DISM',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Get-Features']
|
||||
|
||||
if package:
|
||||
if '~' in package:
|
||||
cmd.append('/PackageName:{0}'.format(package))
|
||||
else:
|
||||
cmd.append('/PackagePath:{0}'.format(package))
|
||||
|
||||
out = __salt__['cmd.run'](cmd)
|
||||
|
||||
pattern = r'Feature Name : (.*)\r\n'
|
||||
features = re.findall(pattern, out, re.MULTILINE)
|
||||
features.sort()
|
||||
|
||||
return features
|
||||
|
||||
|
||||
def installed_features(image=None):
|
||||
'''
|
||||
List the features installed on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Returns:
|
||||
list: A list of installed features
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -155,3 +391,180 @@ def installed_features():
|
|||
salt '*' dism.installed_features
|
||||
'''
|
||||
return _get_components("Feature Name", "Features", "Enabled")
|
||||
|
||||
|
||||
def available_features(image=None):
|
||||
'''
|
||||
List the features available on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Returns:
|
||||
list: A list of available features
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.available_features
|
||||
'''
|
||||
return _get_components("Feature Name", "Features", "Disabled")
|
||||
|
||||
|
||||
def add_package(package,
|
||||
ignore_check=False,
|
||||
prevent_pending=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a package using DISM
|
||||
|
||||
Args:
|
||||
package (str): The package to install. Can be a .cab file, a .msu file,
|
||||
or a folder
|
||||
ignore_check (Optional[bool]): Skip installation of the package if the
|
||||
applicability checks fail
|
||||
prevent_pending (Optional[bool]): Skip the installation of the package
|
||||
if there are pending online actions
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.add_package C:\\Packages\\package.cab
|
||||
'''
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Add-Package',
|
||||
'/PackagePath:{0}'.format(package)]
|
||||
|
||||
if ignore_check:
|
||||
cmd.append('/IgnoreCheck')
|
||||
if prevent_pending:
|
||||
cmd.append('/PreventPending')
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def remove_package(package, image=None, restart=False):
|
||||
'''
|
||||
Uninstall a package
|
||||
|
||||
Args:
|
||||
package (str): The full path to the package. Can be either a .cab file
|
||||
or a folder. Should point to the original source of the package, not
|
||||
to where the file is installed. This can also be the name of a package as listed in
|
||||
``dism.installed_packages``
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Remove the Calc Package
|
||||
salt '*' dism.remove_package Microsoft.Windows.Calc.Demo~6595b6144ccf1df~x86~en~1.0.0.0
|
||||
|
||||
# Remove the package.cab (does not remove C:\\packages\\package.cab)
|
||||
salt '*' dism.remove_package C:\\packages\\package.cab
|
||||
'''
|
||||
cmd = ['DISM',
|
||||
'/Quiet',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Remove-Package']
|
||||
|
||||
if not restart:
|
||||
cmd.append('/NoRestart')
|
||||
|
||||
if '~' in package:
|
||||
cmd.append('/PackageName:{0}'.format(package))
|
||||
else:
|
||||
cmd.append('/PackagePath:{0}'.format(package))
|
||||
|
||||
return __salt__['cmd.run_all'](cmd)
|
||||
|
||||
|
||||
def installed_packages(image=None):
|
||||
'''
|
||||
List the packages installed on the system
|
||||
|
||||
Args:
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Returns:
|
||||
list: A list of installed packages
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism.installed_packages
|
||||
'''
|
||||
return _get_components("Package Identity", "Packages", "Installed")
|
||||
|
||||
|
||||
def package_info(package, image=None):
|
||||
'''
|
||||
Display information about a package
|
||||
|
||||
Args:
|
||||
package (str): The full path to the package. Can be either a .cab file
|
||||
or a folder. Should point to the original source of the package, not
|
||||
to where the file is installed. You cannot use this command to get
|
||||
package information for .msu files
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the results of the command
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' dism. package_info C:\\packages\\package.cab
|
||||
'''
|
||||
cmd = ['DISM',
|
||||
'/Image:{0}'.format(image) if image else '/Online',
|
||||
'/Get-PackageInfo']
|
||||
|
||||
if '~' in package:
|
||||
cmd.append('/PackageName:{0}'.format(package))
|
||||
else:
|
||||
cmd.append('/PackagePath:{0}'.format(package))
|
||||
|
||||
out = __salt__['cmd.run_all'](cmd)
|
||||
|
||||
if out['retcode'] == 0:
|
||||
ret = dict()
|
||||
for line in str(out['stdout']).splitlines():
|
||||
if ' : ' in line:
|
||||
info = line.split(' : ')
|
||||
if len(info) < 2:
|
||||
continue
|
||||
ret[info[0]] = info[1]
|
||||
else:
|
||||
ret = out
|
||||
|
||||
return ret
|
||||
|
|
|
@ -27,84 +27,397 @@ __virtualname__ = "dism"
|
|||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only work on Windows
|
||||
Only work on Windows where the DISM module is available
|
||||
'''
|
||||
if salt.utils.is_windows() and 'dism.install_capability' in __salt__:
|
||||
return __virtualname__
|
||||
return False
|
||||
if not salt.utils.is_windows():
|
||||
return False, 'Module only available on Windows'
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def capability_installed(name, source=None, limit_access=False):
|
||||
def capability_installed(name,
|
||||
source=None,
|
||||
limit_access=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a DISM capability
|
||||
|
||||
name
|
||||
The capability in which to install
|
||||
Args:
|
||||
name (str): The capability to install
|
||||
source (str): The optional source of the capability
|
||||
limit_access (bool): Prevent DISM from contacting Windows Update for
|
||||
online images
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
source
|
||||
The optional source of the capability
|
||||
Example:
|
||||
Run ``dism.available_capabilities`` to get a list of available
|
||||
capabilities. This will help you get the proper name to use.
|
||||
|
||||
limit_access
|
||||
Prevent DISM from contacting Windows Update for online images
|
||||
.. code-block:: yaml
|
||||
|
||||
install_dotnet35:
|
||||
dism.capability_installed:
|
||||
- name: NetFX3~~~~
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
comment = []
|
||||
old = __salt__['dism.installed_capabilities']()
|
||||
|
||||
installed_capabilities = __salt__['dism.installed_capabilities']()
|
||||
if name in old:
|
||||
ret['comment'] = 'The capability {0} is already installed'.format(name)
|
||||
return ret
|
||||
|
||||
if name in installed_capabilities:
|
||||
comment.append("{0} was already installed.\n".format(name))
|
||||
else:
|
||||
out = __salt__['dism.install_capability'](name, source, limit_access)
|
||||
if out['retcode'] == 0:
|
||||
comment.append("{0} was installed.\n".format(name))
|
||||
ret['changes']['installed'] = name
|
||||
else:
|
||||
comment.append("{0} was unable to be installed. {1}\n".format(name, out['stdout']))
|
||||
ret['result'] = False
|
||||
if __opts__['test']:
|
||||
ret['changes']['capability'] = '{0} will be installed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Install the capability
|
||||
status = __salt__['dism.add_capability'](
|
||||
name, source, limit_access, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to install {0}: {1}'\
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_capabilities']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Installed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['capability'] = changes
|
||||
|
||||
ret['comment'] = ' '.join(comment)
|
||||
return ret
|
||||
|
||||
|
||||
def feature_installed(name, source=None, limit_access=False):
|
||||
def capability_removed(name, image=None, restart=False):
|
||||
'''
|
||||
Uninstall a DISM capability
|
||||
|
||||
Args:
|
||||
name (str): The capability to uninstall
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Example:
|
||||
Run ``dism.installed_capabilities`` to get a list of installed
|
||||
capabilities. This will help you get the proper name to use.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
remove_dotnet35:
|
||||
dism.capability_removed:
|
||||
- name: NetFX3~~~~
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
old = __salt__['dism.installed_capabilities']()
|
||||
|
||||
if name not in old:
|
||||
ret['comment'] = 'The capability {0} is already removed'.format(name)
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['changes']['capability'] = '{0} will be removed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Remove the capability
|
||||
status = __salt__['dism.remove_capability'](name, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to remove {0}: {1}' \
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_capabilities']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Removed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['capability'] = changes
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def feature_installed(name,
|
||||
package=None,
|
||||
source=None,
|
||||
limit_access=False,
|
||||
enable_parent=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a DISM feature
|
||||
|
||||
name
|
||||
The feature in which to install
|
||||
Args:
|
||||
name (str): The feature in which to install
|
||||
package (Optional[str]): The parent package for the feature. You do not
|
||||
have to specify the package if it is the Windows Foundation Package.
|
||||
Otherwise, use package to specify the parent package of the feature
|
||||
source (str): The optional source of the feature
|
||||
limit_access (bool): Prevent DISM from contacting Windows Update for
|
||||
online images
|
||||
enable_parent (Optional[bool]): True will enable all parent features of
|
||||
the specified feature
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
source
|
||||
The optional source of the feature
|
||||
Example:
|
||||
Run ``dism.available_features`` to get a list of available features.
|
||||
This will help you get the proper name to use.
|
||||
|
||||
limit_access
|
||||
Prevent DISM from contacting Windows Update for online images
|
||||
.. code-block:: yaml
|
||||
|
||||
install_telnet_client:
|
||||
dism.feature_installed:
|
||||
- name: TelnetClient
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
comment = []
|
||||
old = __salt__['dism.installed_features']()
|
||||
|
||||
installed_features = __salt__['dism.installed_features']()
|
||||
if name in old:
|
||||
ret['comment'] = 'The feature {0} is already installed'.format(name)
|
||||
return ret
|
||||
|
||||
if name in installed_features:
|
||||
comment.append("{0} was already installed.\n".format(name))
|
||||
else:
|
||||
out = __salt__['dism.install_feature'](name, source, limit_access)
|
||||
if out['retcode'] == 0:
|
||||
comment.append("{0} was installed.\n".format(name))
|
||||
ret['changes']['installed'] = name
|
||||
else:
|
||||
comment.append("{0} was unable to be installed. {1}\n".format(name, out['stdout']))
|
||||
ret['result'] = False
|
||||
if __opts__['test']:
|
||||
ret['changes']['feature'] = '{0} will be installed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Install the feature
|
||||
status = __salt__['dism.add_feature'](
|
||||
name, package, source, limit_access, enable_parent, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to install {0}: {1}' \
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_features']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Installed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['feature'] = changes
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def feature_removed(name, remove_payload=False, image=None, restart=False):
|
||||
'''
|
||||
Disables a feature.
|
||||
|
||||
Args:
|
||||
name (str): The feature to disable
|
||||
remove_payload (Optional[bool]): Remove the feature's payload. Must
|
||||
supply source when enabling in the future.
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Example:
|
||||
Run ``dism.installed_features`` to get a list of installed features.
|
||||
This will help you get the proper name to use.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
remove_telnet_client:
|
||||
dism.feature_removed:
|
||||
- name: TelnetClient
|
||||
- remove_payload: True
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
old = __salt__['dism.installed_features']()
|
||||
|
||||
if name not in old:
|
||||
ret['comment'] = 'The feature {0} is already removed'.format(name)
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['changes']['feature'] = '{0} will be removed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Remove the feature
|
||||
status = __salt__['dism.remove_feature'](
|
||||
name, remove_payload, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to remove {0}: {1}' \
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_features']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Removed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['feature'] = changes
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def package_installed(name,
|
||||
ignore_check=False,
|
||||
prevent_pending=False,
|
||||
image=None,
|
||||
restart=False):
|
||||
'''
|
||||
Install a package.
|
||||
|
||||
Args:
|
||||
name (str): The package to install. Can be a .cab file, a .msu file,
|
||||
or a folder
|
||||
ignore_check (Optional[bool]): Skip installation of the package if the
|
||||
applicability checks fail
|
||||
prevent_pending (Optional[bool]): Skip the installation of the package
|
||||
if there are pending online actions
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
install_KB123123123:
|
||||
dism.package_installed:
|
||||
- name: C:\\Packages\\KB123123123.cab
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
old = __salt__['dism.installed_packages']()
|
||||
|
||||
# Get package info so we can see if it's already installed
|
||||
package_info = __salt__['dism.package_info'](name)
|
||||
|
||||
if package_info['Package Identity'] in old:
|
||||
ret['comment'] = 'The package {0} is already installed: {1}'\
|
||||
.format(name, package_info['Package Identity'])
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['changes']['package'] = '{0} will be installed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Install the package
|
||||
status = __salt__['dism.add_package'](
|
||||
name, ignore_check, prevent_pending, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to install {0}: {1}' \
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_packages']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Installed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['package'] = changes
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def package_removed(name, image=None, restart=False):
|
||||
'''
|
||||
Uninstall a package
|
||||
|
||||
Args:
|
||||
name (str): The full path to the package. Can be either a .cab file or a
|
||||
folder. Should point to the original source of the package, not to
|
||||
where the file is installed. This can also be the name of a package as listed in
|
||||
``dism.installed_packages``
|
||||
image (Optional[str]): The path to the root directory of an offline
|
||||
Windows image. If `None` is passed, the running operating system is
|
||||
targeted. Default is None.
|
||||
restart (Optional[bool]): Reboot the machine if required by the install
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Example using source
|
||||
remove_KB1231231:
|
||||
dism.package_installed:
|
||||
- name: C:\\Packages\\KB1231231.cab
|
||||
|
||||
# Example using name from ``dism.installed_packages``
|
||||
remove_KB1231231:
|
||||
dism.package_installed:
|
||||
- name: Package_for_KB1231231~31bf3856ad364e35~amd64~~10.0.1.3
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'result': True,
|
||||
'comment': '',
|
||||
'changes': {}}
|
||||
|
||||
old = __salt__['dism.installed_packages']()
|
||||
|
||||
# Get package info so we can see if it's already removed
|
||||
package_info = __salt__['dism.package_info'](name)
|
||||
|
||||
# If `Package Identity` isn't returned or if they passed a cab file, if
|
||||
# `Package Identity` isn't in the list of installed packages
|
||||
if 'Package Identity' not in package_info or \
|
||||
package_info['Package Identity'] not in old:
|
||||
ret['comment'] = 'The package {0} is already removed'.format(name)
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['changes']['package'] = '{0} will be removed'.format(name)
|
||||
ret['result'] = None
|
||||
return ret
|
||||
|
||||
# Remove the package
|
||||
status = __salt__['dism.remove_package'](name, image, restart)
|
||||
|
||||
if status['retcode'] != 0:
|
||||
ret['comment'] = 'Failed to remove {0}: {1}' \
|
||||
.format(name, status['stdout'])
|
||||
ret['result'] = False
|
||||
|
||||
new = __salt__['dism.installed_packages']()
|
||||
changes = salt.utils.compare_lists(old, new)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'Removed {0}'.format(name)
|
||||
ret['changes'] = status
|
||||
ret['changes']['package'] = changes
|
||||
|
||||
ret['comment'] = ' '.join(comment)
|
||||
return ret
|
||||
|
|
|
@ -2363,6 +2363,21 @@ def compare_dicts(old=None, new=None):
|
|||
return ret
|
||||
|
||||
|
||||
def compare_lists(old=None, new=None):
|
||||
'''
|
||||
Compare before and after results from various salt functions, returning a
|
||||
dict describing the changes that were made
|
||||
'''
|
||||
ret = dict()
|
||||
for item in new:
|
||||
if item not in old:
|
||||
ret['new'] = item
|
||||
for item in old:
|
||||
if item not in new:
|
||||
ret['old'] = item
|
||||
return ret
|
||||
|
||||
|
||||
def argspec_report(functions, module=''):
|
||||
'''
|
||||
Pass in a functions dict as it is returned from the loader and return the
|
||||
|
|
|
@ -17,36 +17,62 @@ from salttesting.mock import (
|
|||
ensure_in_syspath('../../')
|
||||
|
||||
dism.__salt__ = {}
|
||||
dism.__grains__ = {}
|
||||
|
||||
|
||||
class DISMTestCase(TestCase):
|
||||
class WinDismTestCase(TestCase):
|
||||
|
||||
def test_install_capability(self):
|
||||
def test_add_capability(self):
|
||||
'''
|
||||
Test installing a capability with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.install_capability("test")
|
||||
mock.assert_called_once_with('DISM /Online /Add-Capability /CapabilityName:test')
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
dism.add_capability("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Add-Capability',
|
||||
'/CapabilityName:test', '/NoRestart'])
|
||||
|
||||
def test_install_capability_with_extras(self):
|
||||
def test_add_capability_with_extras(self):
|
||||
'''
|
||||
Test installing a capability with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.install_capability("test", "life", True)
|
||||
mock.assert_called_once_with('DISM /Online /Add-Capability /CapabilityName:test /Source:life /LimitAccess')
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
dism.add_capability("test", "life", True)
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Add-Capability',
|
||||
'/CapabilityName:test', '/Source:life', '/LimitAccess',
|
||||
'/NoRestart'])
|
||||
|
||||
def test_uninstall_capability(self):
|
||||
def test_remove_capability(self):
|
||||
'''
|
||||
Test uninstalling a capability with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.uninstall_capability("test")
|
||||
mock.assert_called_once_with('DISM /Online /Remove-Capability /CapabilityName:test')
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
dism.remove_capability("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Remove-Capability',
|
||||
'/CapabilityName:test', '/NoRestart'])
|
||||
|
||||
def test_get_capabilities(self):
|
||||
'''
|
||||
Test getting all the capabilities
|
||||
'''
|
||||
capabilties = "Capability Identity : Capa1\r\n State : Installed\r\n" \
|
||||
"Capability Identity : Capa2\r\n State : Disabled\r\n"
|
||||
|
||||
mock = MagicMock(return_value=capabilties)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
out = dism.get_capabilities()
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Online', '/Get-Capabilities'])
|
||||
self.assertEqual(out, ['Capa1', 'Capa2'])
|
||||
|
||||
def test_installed_capabilities(self):
|
||||
'''
|
||||
|
@ -57,41 +83,158 @@ class DISMTestCase(TestCase):
|
|||
|
||||
mock = MagicMock(return_value=capabilties)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
out = dism.installed_capabilities()
|
||||
mock.assert_called_once_with('DISM /Online /Get-Capabilities')
|
||||
self.assertEqual(out, ["Capa1"])
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
out = dism.installed_capabilities()
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Online', '/Get-Capabilities'])
|
||||
self.assertEqual(out, ["Capa1"])
|
||||
|
||||
def test_install_feature(self):
|
||||
def test_available_capabilities(self):
|
||||
'''
|
||||
Test getting all the available capabilities
|
||||
'''
|
||||
capabilties = "Capability Identity : Capa1\r\n State : Installed\r\n" \
|
||||
"Capability Identity : Capa2\r\n State : Not Present\r\n"
|
||||
|
||||
mock = MagicMock(return_value=capabilties)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
with patch.dict(dism.__grains__, {'osversion': 10}):
|
||||
out = dism.available_capabilities()
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Online', '/Get-Capabilities'])
|
||||
self.assertEqual(out, ["Capa2"])
|
||||
|
||||
def test_add_feature(self):
|
||||
'''
|
||||
Test installing a feature with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.install_feature("test")
|
||||
mock.assert_called_once_with('DISM /Online /Enable-Feature /FeatureName:test')
|
||||
dism.add_feature("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Enable-Feature',
|
||||
'/FeatureName:test', '/NoRestart'])
|
||||
|
||||
def test_uninstall_feature(self):
|
||||
def test_add_feature_with_extras(self):
|
||||
'''
|
||||
Test installing a feature with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.add_feature('sponge', 'bob', 'C:\\temp', True, True)
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Enable-Feature',
|
||||
'/FeatureName:sponge', '/PackageName:bob', '/Source:C:\\temp',
|
||||
'/LimitAccess', '/All', '/NoRestart'])
|
||||
|
||||
def test_remove_feature(self):
|
||||
'''
|
||||
Test uninstalling a capability with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.uninstall_feature("test")
|
||||
mock.assert_called_once_with('DISM /Online /Disable-Feature /FeatureName:test')
|
||||
dism.remove_feature("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Disable-Feature',
|
||||
'/FeatureName:test', '/NoRestart'])
|
||||
|
||||
def test_installed_feature(self):
|
||||
def test_remove_feature_with_extras(self):
|
||||
'''
|
||||
Test getting all the installed capabilities
|
||||
Test uninstalling a capability with DISM
|
||||
'''
|
||||
capabilties = "Feature Name : Capa1\r\n State : Enabled\r\n" \
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.remove_feature('sponge', True)
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Disable-Feature',
|
||||
'/FeatureName:sponge', '/Remove', '/NoRestart'])
|
||||
|
||||
def test_get_features(self):
|
||||
'''
|
||||
Test getting all the features
|
||||
'''
|
||||
features = "Feature Name : Capa1\r\n State : Enabled\r\n" \
|
||||
"Feature Name : Capa2\r\n State : Disabled\r\n"
|
||||
|
||||
mock = MagicMock(return_value=capabilties)
|
||||
mock = MagicMock(return_value=features)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
out = dism.get_features()
|
||||
mock.assert_called_once_with(['DISM', '/Online', '/Get-Features'])
|
||||
self.assertEqual(out, ['Capa1', 'Capa2'])
|
||||
|
||||
def test_installed_features(self):
|
||||
'''
|
||||
Test getting all the installed features
|
||||
'''
|
||||
features = "Feature Name : Capa1\r\n State : Enabled\r\n" \
|
||||
"Feature Name : Capa2\r\n State : Disabled\r\n"
|
||||
|
||||
mock = MagicMock(return_value=features)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
out = dism.installed_features()
|
||||
mock.assert_called_once_with('DISM /Online /Get-Features')
|
||||
mock.assert_called_once_with(['DISM', '/Online', '/Get-Features'])
|
||||
self.assertEqual(out, ["Capa1"])
|
||||
|
||||
def test_available_features(self):
|
||||
'''
|
||||
Test getting all the available features
|
||||
'''
|
||||
features = "Feature Name : Capa1\r\n State : Enabled\r\n" \
|
||||
"Feature Name : Capa2\r\n State : Disabled\r\n"
|
||||
|
||||
mock = MagicMock(return_value=features)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
out = dism.available_features()
|
||||
mock.assert_called_once_with(['DISM', '/Online', '/Get-Features'])
|
||||
self.assertEqual(out, ["Capa2"])
|
||||
|
||||
def test_add_package(self):
|
||||
'''
|
||||
Test installing a package with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.add_package("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Add-Package',
|
||||
'/PackagePath:test', '/NoRestart'])
|
||||
|
||||
def test_add_package_with_extras(self):
|
||||
'''
|
||||
Test installing a package with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.add_package('sponge', True, True)
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Add-Package',
|
||||
'/PackagePath:sponge', '/IgnoreCheck', '/PreventPending',
|
||||
'/NoRestart'])
|
||||
|
||||
def test_remove_package(self):
|
||||
'''
|
||||
Test uninstalling a package with DISM
|
||||
'''
|
||||
mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'cmd.run_all': mock}):
|
||||
dism.remove_package("test")
|
||||
mock.assert_called_once_with(
|
||||
['DISM', '/Quiet', '/Online', '/Remove-Package', '/NoRestart',
|
||||
'/PackagePath:test'])
|
||||
|
||||
def test_installed_packages(self):
|
||||
'''
|
||||
Test getting all the installed features
|
||||
'''
|
||||
features = "Package Identity : Capa1\r\n State : Installed\r\n" \
|
||||
"Package Identity : Capa2\r\n State : Installed\r\n"
|
||||
|
||||
mock = MagicMock(return_value=features)
|
||||
with patch.dict(dism.__salt__, {'cmd.run': mock}):
|
||||
out = dism.installed_packages()
|
||||
mock.assert_called_once_with(['DISM', '/Online', '/Get-Packages'])
|
||||
self.assertEqual(out, ['Capa1', 'Capa2'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(DISMTestCase, needs_daemon=False)
|
||||
run_tests(WinDismTestCase, needs_daemon=False)
|
||||
|
|
|
@ -17,131 +17,503 @@ from salttesting.mock import (
|
|||
ensure_in_syspath('../../')
|
||||
|
||||
dism.__salt__ = {}
|
||||
dism.__opts__ = {}
|
||||
|
||||
|
||||
class DISMTestCase(TestCase):
|
||||
class WinDismTestCase(TestCase):
|
||||
|
||||
def test_install_capability(self):
|
||||
def test_capability_installed(self):
|
||||
'''
|
||||
Test installing a capability with DISM
|
||||
Test capability installed state
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Capa2 was installed.\n",
|
||||
'changes': {'installed': 'Capa2'},
|
||||
'comment': "Installed Capa2",
|
||||
'changes': {'capability': {'new': 'Capa2'},
|
||||
'retcode': 0},
|
||||
'name': 'Capa2',
|
||||
'result': True
|
||||
}
|
||||
'result': True}
|
||||
|
||||
installed_mock = MagicMock(return_value=["Capa1"])
|
||||
install_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(dism.__salt__, {'dism.installed_capabilities': installed_mock,
|
||||
'dism.install_capability': install_mock}):
|
||||
out = dism.capability_installed('Capa2', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
install_mock.assert_called_once_with('Capa2', 'somewhere', True)
|
||||
self.assertEqual(out, expected)
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Capa1'], ['Capa1', 'Capa2']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
|
||||
def test_install_capability_failure(self):
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_installed,
|
||||
'dism.add_capability': mock_add}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.capability_installed('Capa2', 'somewhere', True)
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Capa2', 'somewhere', True, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_capability_installed_failure(self):
|
||||
'''
|
||||
Test installing a capability which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Capa2 was unable to be installed. Failed\n",
|
||||
'comment': "Failed to install Capa2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Capa2',
|
||||
'result': False
|
||||
}
|
||||
'result': False}
|
||||
|
||||
installed_mock = MagicMock(return_value=["Capa1"])
|
||||
install_mock = MagicMock(return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
with patch.dict(dism.__salt__, {'dism.installed_capabilities': installed_mock,
|
||||
'dism.install_capability': install_mock}):
|
||||
out = dism.capability_installed('Capa2', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
install_mock.assert_called_once_with('Capa2', 'somewhere', True)
|
||||
self.assertEqual(out, expected)
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Capa1'], ['Capa1']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
|
||||
def test_installed_capability(self):
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_installed,
|
||||
'dism.add_capability': mock_add}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.capability_installed('Capa2', 'somewhere', True)
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Capa2', 'somewhere', True, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_capability_installed_installed(self):
|
||||
'''
|
||||
Test installing a capability already installed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Capa2 was already installed.\n",
|
||||
'comment': "The capability Capa2 is already installed",
|
||||
'changes': {},
|
||||
'name': 'Capa2',
|
||||
'result': True
|
||||
}
|
||||
'result': True}
|
||||
|
||||
mock_installed = MagicMock(
|
||||
return_value=["Capa1", "Capa2"])
|
||||
mock_add = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_installed,
|
||||
'dism.add_capability': mock_add}):
|
||||
|
||||
installed_mock = MagicMock(return_value=["Capa1", "Capa2"])
|
||||
install_mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'dism.installed_capabilities': installed_mock,
|
||||
'dism.install_capability': install_mock}):
|
||||
out = dism.capability_installed('Capa2', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
assert not install_mock.called
|
||||
|
||||
mock_installed.assert_called_once_with()
|
||||
assert not mock_add.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_install_feature(self):
|
||||
def test_capability_removed(self):
|
||||
'''
|
||||
Test capability removed state
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Removed Capa2",
|
||||
'changes': {'capability': {'old': 'Capa2'},
|
||||
'retcode': 0},
|
||||
'name': 'Capa2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Capa1', 'Capa2'], ['Capa1']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_removed,
|
||||
'dism.remove_capability': mock_remove}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.capability_removed('Capa2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with('Capa2', None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_capability_removed_failure(self):
|
||||
'''
|
||||
Test removing a capability which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Failed to remove Capa2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Capa2',
|
||||
'result': False}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Capa1', 'Capa2'], ['Capa1', 'Capa2']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_removed,
|
||||
'dism.remove_capability': mock_remove}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.capability_removed('Capa2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with(
|
||||
'Capa2', None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_capability_removed_removed(self):
|
||||
'''
|
||||
Test removing a capability already removed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "The capability Capa2 is already removed",
|
||||
'changes': {},
|
||||
'name': 'Capa2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
return_value=["Capa1"])
|
||||
mock_remove = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_capabilities': mock_removed,
|
||||
'dism.add_capability': mock_remove}):
|
||||
|
||||
out = dism.capability_removed('Capa2', 'somewhere', True)
|
||||
|
||||
mock_removed.assert_called_once_with()
|
||||
assert not mock_remove.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_installed(self):
|
||||
'''
|
||||
Test installing a feature with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Feat1 was installed.\n",
|
||||
'changes': {'installed': 'Feat1'},
|
||||
'name': 'Feat1',
|
||||
'result': True
|
||||
}
|
||||
'comment': "Installed Feat2",
|
||||
'changes': {'feature': {'new': 'Feat2'},
|
||||
'retcode': 0},
|
||||
'name': 'Feat2',
|
||||
'result': True}
|
||||
|
||||
installed_mock = MagicMock(return_value=["Feat2"])
|
||||
install_mock = MagicMock(return_value={'retcode': 0})
|
||||
with patch.dict(dism.__salt__, {'dism.installed_features': installed_mock,
|
||||
'dism.install_feature': install_mock}):
|
||||
out = dism.feature_installed('Feat1', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
install_mock.assert_called_once_with('Feat1', 'somewhere', True)
|
||||
self.assertEqual(out, expected)
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Feat1'], ['Feat1', 'Feat2']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
|
||||
def test_install_feature_failure(self):
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_installed,
|
||||
'dism.add_feature': mock_add}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.feature_installed('Feat2')
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Feat2', None, None, False, False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_installed_failure(self):
|
||||
'''
|
||||
Test installing a feature which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Feat1 was unable to be installed. Failed\n",
|
||||
'comment': "Failed to install Feat2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Feat1',
|
||||
'result': False
|
||||
}
|
||||
'name': 'Feat2',
|
||||
'result': False}
|
||||
|
||||
installed_mock = MagicMock(return_value=["Feat3"])
|
||||
install_mock = MagicMock(return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
with patch.dict(dism.__salt__, {'dism.installed_features': installed_mock,
|
||||
'dism.install_feature': install_mock}):
|
||||
out = dism.feature_installed('Feat1', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
install_mock.assert_called_once_with('Feat1', 'somewhere', True)
|
||||
self.assertEqual(out, expected)
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Feat1'], ['Feat1']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
|
||||
def test_installed_feature(self):
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_installed,
|
||||
'dism.add_feature': mock_add}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.feature_installed('Feat2')
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Feat2', None, None, False, False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_installed_installed(self):
|
||||
'''
|
||||
Test installing a feature already installed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Feat1 was already installed.\n",
|
||||
'comment': "The feature Feat1 is already installed",
|
||||
'changes': {},
|
||||
'name': 'Feat1',
|
||||
'result': True
|
||||
}
|
||||
'result': True}
|
||||
|
||||
installed_mock = MagicMock(return_value=["Feat1", "Feat2"])
|
||||
install_mock = MagicMock()
|
||||
with patch.dict(dism.__salt__, {'dism.installed_features': installed_mock,
|
||||
'dism.install_feature': install_mock}):
|
||||
out = dism.feature_installed('Feat1', 'somewhere', True)
|
||||
installed_mock.assert_called_once_with()
|
||||
assert not install_mock.called
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Feat1', 'Feat2'], ['Feat1', 'Feat2']])
|
||||
mock_add = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_installed,
|
||||
'dism.add_feature': mock_add}):
|
||||
|
||||
out = dism.feature_installed('Feat1')
|
||||
|
||||
mock_installed.assert_called_once_with()
|
||||
assert not mock_add.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_removed(self):
|
||||
'''
|
||||
Test removing a feature with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Removed Feat2",
|
||||
'changes': {'feature': {'old': 'Feat2'},
|
||||
'retcode': 0},
|
||||
'name': 'Feat2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Feat1', 'Feat2'], ['Feat1']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_removed,
|
||||
'dism.remove_feature': mock_remove}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.feature_removed('Feat2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with(
|
||||
'Feat2', False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_removed_failure(self):
|
||||
'''
|
||||
Test removing a feature which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Failed to remove Feat2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Feat2',
|
||||
'result': False}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Feat1', 'Feat2'], ['Feat1', 'Feat2']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_removed,
|
||||
'dism.remove_feature': mock_remove}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.feature_removed('Feat2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with(
|
||||
'Feat2', False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_feature_removed_removed(self):
|
||||
'''
|
||||
Test removing a feature already removed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "The feature Feat2 is already removed",
|
||||
'changes': {},
|
||||
'name': 'Feat2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Feat1'], ['Feat1']])
|
||||
mock_remove = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_features': mock_removed,
|
||||
'dism.remove_feature': mock_remove}):
|
||||
|
||||
out = dism.feature_removed('Feat2')
|
||||
|
||||
mock_removed.assert_called_once_with()
|
||||
assert not mock_remove.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_installed(self):
|
||||
'''
|
||||
Test installing a package with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Installed Pack2",
|
||||
'changes': {'package': {'new': 'Pack2'},
|
||||
'retcode': 0},
|
||||
'name': 'Pack2',
|
||||
'result': True}
|
||||
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Pack1'], ['Pack1', 'Pack2']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_installed,
|
||||
'dism.add_package': mock_add,
|
||||
'dism.package_info': mock_info}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.package_installed('Pack2')
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Pack2', False, False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_installed_failure(self):
|
||||
'''
|
||||
Test installing a package which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Failed to install Pack2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Pack2',
|
||||
'result': False}
|
||||
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Pack1'], ['Pack1']])
|
||||
mock_add = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_installed,
|
||||
'dism.add_package': mock_add,
|
||||
'dism.package_info': mock_info}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.package_installed('Pack2')
|
||||
|
||||
mock_installed.assert_called_with()
|
||||
mock_add.assert_called_once_with(
|
||||
'Pack2', False, False, None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_installed_installed(self):
|
||||
'''
|
||||
Test installing a package already installed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "The package Pack2 is already installed: Pack2",
|
||||
'changes': {},
|
||||
'name': 'Pack2',
|
||||
'result': True}
|
||||
|
||||
mock_installed = MagicMock(
|
||||
side_effect=[['Pack1', 'Pack2'], ['Pack1', 'Pack2']])
|
||||
mock_add = MagicMock()
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_installed,
|
||||
'dism.add_package': mock_add,
|
||||
'dism.package_info': mock_info}):
|
||||
|
||||
out = dism.package_installed('Pack2')
|
||||
|
||||
mock_installed.assert_called_once_with()
|
||||
assert not mock_add.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_removed(self):
|
||||
'''
|
||||
Test removing a package with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Removed Pack2",
|
||||
'changes': {'package': {'old': 'Pack2'},
|
||||
'retcode': 0},
|
||||
'name': 'Pack2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Pack1', 'Pack2'], ['Pack1']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 0})
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_removed,
|
||||
'dism.remove_package': mock_remove,
|
||||
'dism.package_info': mock_info}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.package_removed('Pack2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with(
|
||||
'Pack2', None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_removed_failure(self):
|
||||
'''
|
||||
Test removing a package which fails with DISM
|
||||
'''
|
||||
expected = {
|
||||
'comment': "Failed to remove Pack2: Failed",
|
||||
'changes': {},
|
||||
'name': 'Pack2',
|
||||
'result': False}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Pack1', 'Pack2'], ['Pack1', 'Pack2']])
|
||||
mock_remove = MagicMock(
|
||||
return_value={'retcode': 67, 'stdout': 'Failed'})
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_removed,
|
||||
'dism.remove_package': mock_remove,
|
||||
'dism.package_info': mock_info}):
|
||||
with patch.dict(dism.__opts__, {'test': False}):
|
||||
|
||||
out = dism.package_removed('Pack2')
|
||||
|
||||
mock_removed.assert_called_with()
|
||||
mock_remove.assert_called_once_with(
|
||||
'Pack2', None, False)
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
def test_package_removed_removed(self):
|
||||
'''
|
||||
Test removing a package already removed
|
||||
'''
|
||||
expected = {
|
||||
'comment': "The package Pack2 is already removed",
|
||||
'changes': {},
|
||||
'name': 'Pack2',
|
||||
'result': True}
|
||||
|
||||
mock_removed = MagicMock(
|
||||
side_effect=[['Pack1'], ['Pack1']])
|
||||
mock_remove = MagicMock()
|
||||
mock_info = MagicMock(
|
||||
return_value={'Package Identity': 'Pack2'})
|
||||
|
||||
with patch.dict(
|
||||
dism.__salt__, {'dism.installed_packages': mock_removed,
|
||||
'dism.remove_package': mock_remove,
|
||||
'dism.package_info': mock_info}):
|
||||
|
||||
out = dism.package_removed('Pack2')
|
||||
|
||||
mock_removed.assert_called_once_with()
|
||||
assert not mock_remove.called
|
||||
self.assertEqual(out, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(DISMTestCase, needs_daemon=False)
|
||||
run_tests(WinDismTestCase, needs_daemon=False)
|
||||
|
|
Loading…
Add table
Reference in a new issue