Windows Package Manager#
Introduction#
Salt provides a Windows package management tool for installing, updating,
removing, and managing software packages on remote Windows systems. This tool
provides a software repository and a package manager similar to what is provided
by yum and apt on Linux. The repository contains a collection of package
definition files.
What are package definition files?#
A package definition file is a YAML/JINJA2 file with a .sls file extension
that contains all the information needed to install software using Salt. It
defines:
Full name of the software package
The version of the software package
Download location of the software package
Command-line switches for silent install and uninstall
Whether or not to use the Windows task scheduler to install the package
Package definition files can be hosted in one or more Git repositories. The
.sls files used to install Windows packages are not distributed by default
with Salt. You have to initialize and clone the default repository
salt-winrepo-ng
which is hosted on GitHub by SaltStack. The repository contains package
definition files for many common Windows packages and is maintained by SaltStack
and the Salt community. Anyone can submit a pull request to this repo to add
new package definitions.
You can manage the package definition file through either Salt or Git. You can download software packages from either a git repository or from HTTP(S) or FTP URLs. You can store the installer defined in the package definition file anywhere as long as it is accessible from the host running Salt.
You can use the Salt Windows package manager like yum on Linux. You do not
have to know the underlying command to install the software.
Use
pkg.installto install a package using a package manager based on the OS the system runs on.Use
pkg.installedto check if a particular package is installed in the minion.
Note
The Salt Windows package manager does not automatically resolve dependencies while installing, updating, or removing packages. You have to manage the dependencies between packages manually.
Quickstart#
This quickstart guides you through using the Windows Salt package manager (winrepo) to install software packages in four steps:
Install libraries#
(Optional) If you are using the Salt Windows package manager with package
definition files hosted on a Salt Git repo, install the libraries GitPython
or pygit2.
Populate the local Git repository#
The SLS files used to install Windows packages are not distributed by default
with Salt. Assuming no changes to the default configuration (file_roots),
initialize and clone salt-winrepo-ng
repository.
salt-run winrepo.update_git_repos
On successful execution of winrepo.update_git_repos,
the winrepo repository is cloned on the master in the location specified in
winrepo_dir_ng and all package definition files are pulled down from the Git
repository.
On a masterless minion, use salt-call to initialize and clone the
salt-winrepo-ng
salt-call --local winrepo.update_git_repos
On successful execution of the runner, the winrepo repository is cloned on the
minion in the location specified in winrepo_dir_ng and all package
definition files are pulled down from the Git repository.
Update minion database#
Run pkg.refresh_db on all Windows
minions to create a database entry for every package definition file and build
the package database.
# From the master
salt -G 'os:windows' pkg.refresh_db
# From the minion in masterless mode
salt-call --local pkg.refresh_db
The pkg.refresh_db command parses the
YAML/JINJA package definition files and generates the database. The above
command returns the following summary denoting the number of packages that
succeeded or failed to compile:
local:
----------
failed:
0
success:
301
total:
301
Note
This command can take a few minutes to complete as all the package definition files are copied to the minion and the database is generated.
Note
You can use pkg.refresh_db when writing new Windows package definitions
to check for errors in the definitions against one or more Windows minions.
Install software package#
You can now install a software package using
pkg.install:
# From the master
salt * pkg.install 'firefox_x64'
# From the minion in masterless mode
salt-call --local pkg.install "firefox_x64"
The above command installs the latest version of Firefox on the minions.
Configuration#
The Github repository (winrepo) is synced to the file_roots in a location
specified by the winrepo_dir_ng setting in the config. The default value of
winrepo_dir_ng is as follows:
Linux master:
/srv/salt/win/repo-ng(salt://win/repo-ng)Masterless minion:
C:\salt\srv\salt\win\repo-ng(salt://win/repo-ng)
Master Configuration#
The following settings are available for configuring the winrepo on the master:
See here for detailed information on all master config options for winrepo.
winrepo_dir#
winrepo_dir (str)
This setting is maintained for backwards compatibility with legacy minions. It
points to the location in the file_roots where the winrepo files are kept.
The default is: /srv/salt/win/repo
winrepo_dir_ng#
winrepo_dir_ng (str)
The location in the file_roots where the winrepo files are kept. The default
is /srv/salt/win/repo-ng.
Warning
You can change the location of the winrepo directory. However, it must
always be set to a path that is inside the file_roots. Otherwise, the
software definition files will be unreachable by the minion.
Important
A common mistake is to change the file_roots setting and fail to update
the winrepo_dir_ng and winrepo_dir settings so that they are inside
the file_roots
winrepo_remotes#
winrepo_remotes (list)
This setting is maintained for backwards compatibility with legacy minions. It points to the legacy git repo. The default is a list containing a single URL:
https://github.com/saltstack/salt-winrepo
The legacy repo can be disabled by setting it to an empty list in the master config.
winrepo_remotes: []
winrepo_remotes_ng#
winrepo_remotes_ng (list)
This setting tells the winrepo.update_git_repos command where the next
generation winrepo is hosted. This a list of URLs to multiple git repos. The
default is a list containing a single URL:
winrepo_refspecs#
winrepo_refspecs (list)
Specify what references to fetch from remote repositories. The default is
['+refs/heads/*:refs/remotes/origin/*', '+refs/tags/*:refs/tags/*']
winrepo_branch#
winrepo_branch (str)
The branch of the git repo to checkout. The default is master
winrepo_provider#
winrepo_provider (str)
The provider to be used for winrepo. Default is pygit2. Falls back to
gitpython when pygit2 is not available
winrepo_ssl_verify#
winrepo_ssl_verify (bool)
Ignore SSL certificate errors when contacting remote repository. Default is
False
winrepo_proxy#
winrepo_proxy (str)
The proxy server used for connecting to remote repositories. Default is '',
meaning no proxy will be used.
Master Configuration (pygit2)#
The following configuration options only apply when the
winrepo_provider option is set to pygit2.
winrepo_insecure_auth#
winrepo_insecure_auth (bool)
Used only with pygit2 provider. Whether or not to allow insecure auth.
Default is False
winrepo_passphrase#
winrepo_passphrase (str)
Used only with pygit2 provider. Used when the SSH key being used to
authenticate is protected by a passphrase. Default is ''
winrepo_privkey#
winrepo_privkey (str)
Used only with pygit2 provider. Used with winrepo_pubkey to
authenticate to SSH remotes. Default is ''
winrepo_pubkey#
winrepo_pubkey (str)
Used only with pygit2 provider. Used with winrepo_privkey to
authenticate to SSH remotes. Default is ''
winrepo_user#
winrepo_user (str)
Used only with pygit2 provider. Used with winrepo_password to
authenticate to HTTPS remotes. Default is ''
winrepo_password#
winrepo_password (str)
Used only with pygit2 provider. Used with winrepo_user to
authenticate to HTTPS remotes. Default is ''
Minion Configuration#
Refreshing the package definitions can take some time, these options were introduced to allow more control of when it occurs. These settings apply to all minions whether in masterless mode or not.
winrepo_cache_expire_max#
winrepo_cache_expire_max (int)
Sets the maximum age in seconds of the winrepo metadata file to avoid it
becoming stale. If the metadata file is older than this setting, it will trigger
a pkg.refresh_db on the next run of any pkg module function that
requires the metadata file. Default is 604800 (1 week).
Software package definitions are automatically refreshed if stale after
winrepo_cache_expire_max. Running a highstate forces the refresh
of the package definitions and regenerates the metadata, unless the metadata is
younger than winrepo_cache_expire_max.
winrepo_cache_expire_min#
winrepo_cache_expire_min (int)
Sets the minimum age in seconds of the winrepo metadata file to avoid refreshing
too often. If the metadata file is older than this setting, the metadata will be
refreshed unless you pass refresh: False in the state. Default is 1800
(30 min).
winrepo_cachefile#
winrepo_cachefile (str)
The file name of the winrepo cache file. The file is placed at the root of
winrepo_dir_ng. Default is winrepo.p.
winrepo_source_dir#
winrepo_source_dir (str)
The location of the .sls files on the Salt file server. This allows for using
different environments. Default is salt://win/repo-ng/.
Warning
If the default for winrepo_dir_ng is changed, this setting may need to
be changed on each minion. The default setting for winrepo_dir_ng is
/srv/salt/win/repo-ng. If that were changed to
/srv/salt/new/repo-ng, then the winrepo_source_dir would need to be
changed to salt://new/repo-ng
Masterless Minion Configuration#
The following settings are available for configuring the winrepo on a masterless minion:
See here for detailed information on all minion config options for winrepo.
winrepo_dir#
winrepo_dir (str)
This setting is maintained for backwards compatibility with legacy minions. It
points to the location in the file_roots where the winrepo files are kept.
The default is: C:\ProgramData\Salt Project\Salt\srv\salt\win\repo
winrepo_dir_ng#
winrepo_dir_ng (str)
The location in the file_roots where the winrepo files are kept. The default
is C:\ProgramData\Salt Project\Salt\srv\salt\win\repo-ng.
Warning
You can change the location of the winrepo directory. However, it must
always be set to a path that is inside the file_roots. Otherwise, the
software definition files will be unreachable by the minion.
Important
A common mistake is to change the file_roots setting and fail to update
the winrepo_dir_ng and winrepo_dir settings so that they are inside
the file_roots. You might also want to verify winrepo_source_dir on
the minion as well.
winrepo_remotes#
winrepo_remotes (list)
This setting is maintained for backwards compatibility with legacy minions. It points to the legacy git repo. The default is a list containing a single URL:
https://github.com/saltstack/salt-winrepo
The legacy repo can be disabled by setting it to an empty list in the minion config.
winrepo_remotes: []
winrepo_remotes_ng#
winrepo_remotes_ng (list)
This setting tells the winrepo.update_git_repos command where the next
generation winrepo is hosted. This a list of URLs to multiple git repos. The
default is a list containing a single URL:
Sample Configurations#
Masterless#
The configs in this section are for working with winrepo on a Windows minion
using salt-call --local.
Default Configuration#
This is the default configuration if nothing is configured in the minion config. The config is shown here for clarity. These are the defaults:
file_roots:
base:
- C:\ProgramData\Salt Project\Salt\srv\salt
winrepo_source_dir: 'salt://win/repo-ng'
winrepo_dir_ng: C:\ProgramData\Salt Project\Salt\srv\salt\win\repo-ng
The winrepo.update_git_repos
command will clone the repository to win\repo-ng on the file_roots.
Multiple Salt Environments#
This starts to get a little tricky. The winrepo repository doesn't
get cloned to each environment when you run
winrepo.update_git_repos, so to
make this work, all environments share the same winrepo. Applying states using
the saltenv option will find the state files in the appropriate environment,
but the package definition files will always be pulled from the same location.
Therefore, you have to put the same winrepo location in each saltenv. Here's how
this would look:
file_roots:
base:
- C:\ProgramData\Salt Project\Salt\srv\salt\base
- C:\ProgramData\Salt Project\Salt\srv\salt\winrepo
test:
- C:\ProgramData\Salt Project\Salt\srv\salt\test
- C:\ProgramData\Salt Project\Salt\srv\salt\winrepo
winrepo_source_dir: 'salt://salt-winrepo-ng'
winrepo_dir_ng: C:\ProgramData\Salt Project\Salt\srv\salt\winrepo
winrepo_dir: C:\ProgramData\Salt Project\Salt\srv\salt\winrepo
When you run
winrepo.update_git_repos the
Git repository will be cloned to the location specified in the
winrepo_dir_ng setting. I specified the winrepo_dir setting just so
everything gets cloned to the same place. The directory that gets cloned is
named salt-winrepo-ng so you specify that in the winrepo_source_dir
setting.
The winrepo directory should only contain the package definition files. You
wouldn't want to place any states in the winrepo directory as they will be
available to both environments.
Master#
When working in a Master/Minion environment you have to split up some of the config settings between the master and the minion. Here are some sample configs for winrepo in a Master/Minion environment.
Default Configuration#
This is the default configuration if nothing is configured. The config is shown here for clarity. These are the defaults on the master:
file_roots:
base:
- /srv/salt
winrepo_dir_ng: /srv/salt/win/repo-ng
This is the default in the minion config:
winrepo_source_dir: 'salt://win/repo-ng'
The winrepo.update_git_repos
command will clone the repository to win\repo-ng on the file_roots.
Multiple Salt Environments#
To set up multiple saltenvs using a Master/Minion configuration set the following in the master config:
file_roots:
base:
- /srv/salt/base
- /srv/salt/winrepo
test:
- /srv/salt/test
- /srv/salt/winrepo
winrepo_dir_ng: /srv/salt/winrepo
winrepo_dir: /srv/salt/winrepo
Use the winrepo runner to set up the winrepo repository on the master.
salt-run winrepo.update_git_repos
The winrepo will be cloned to /srv/salt/winrepo under a directory named
salt-winrepo-ng.
Set the following on the minion config so the minion knows where to find the package definition files in the file_roots:
winrepo_source_dir: 'salt://salt-winrepo-ng'
The same stipulations apply in a Master/Minion configuration as they do in a Masterless configuration
Usage#
After completing the configuration and initialization, you can use the Salt package manager commands to manage software on Windows minions.
Note
The following example commands can be run from the master using salt or
on a masterless minion using salt-call
Command |
Description |
|
|---|---|---|
1 |
Displays a list of all packages installed in the system. |
|
2 |
Displays the versions available of a particular package to be installed. |
|
3 |
Installs a given package. |
|
4 |
Uninstalls a given package. |
List installed packages#
Use pkg.list_pkgs to display a list of
packages installed on the system.
# From the master
salt -G 'os:windows' pkg.list_pkgs
# From the minion in masterless mode
salt-call --local pkg.list_pkgs
The command displays the software name and the version for every package installed on the system irrespective of whether it was installed by the Salt package manager.
local:
----------
Frhed 1.6.0:
1.6.0
GNU Privacy Guard:
2.2.16
Gpg4win (3.1.9):
3.1.9
git:
2.17.1.2
nsis:
3.03
python3_x64:
3.7.4150.0
salt-minion-py3:
2019.2.3
The software name indicates whether the software is managed by Salt or not.
If Salt finds a match in the winrepo database, then the software name is the short name as defined in the package definition file. It is usually a single-word, lower-case name.
All other software names are displayed as the full name as shown in Add/Remove Programs. In the above example, Git (git), Nullsoft Installer (nsis), Python 3.7 (python3_x64), and Salt (salt-minion-py3) have corresponding package definition files and are managed by Salt, while Frhed 1.6.0, GNU Privacy guard, and GPG4win are not.
List available versions#
Use pkg.list_available to display
a list of versions of a package available for installation. You can pass the
name of the software in the command. You can refer to the software by its
name or its full_name surrounded by quotes.
# From the master
salt winminion pkg.list_available firefox_x64
# From the minion in masterless mode
salt-call --local pkg.list_available firefox_x64
The command lists all versions of Firefox available for installation.
winminion:
- 69.0
- 69.0.1
- 69.0.2
- 69.0.3
- 70.0
- 70.0.1
- 71.0
- 72.0
- 72.0.1
- 72.0.2
- 73.0
- 73.0.1
- 74.0
Note
For a Linux master, you can surround the file name with single quotes.
However, for the cmd shell on Windows, use double quotes when wrapping
strings that may contain spaces. Powershell accepts either single quotes or
double quotes.
Install a package#
Use pkg.install: to install a package.
# From the master
salt winminion pkg.install 'firefox_x64'
# From the minion in masterless mode
salt-call --local pkg.install "firefox_x64"
The command installs the latest version of Firefox.
# From the master
salt winminion pkg.install 'firefox_x64' version=74.0
# From the minion in masterless mode
salt-call --local pkg.install "firefox_x64" version=74.0
The command installs version 74.0 of Firefox.
If a different version of the package is already installed, then the old version is replaced with the version in the winrepo (only if the package supports live updating).
You can also specify the full name of the software while installing:
# From the master
salt winminion pkg.install 'Mozilla Firefox 17.0.1 (x86 en-US)'
# From the minion in masterless mode
salt-call --local pkg.install "Mozilla Firefox 17.0.1 (x86 en-US)"
Remove a package#
Use pkg.remove to remove a package.
# From the master
salt winminion pkg.remove firefox_x64
# From the minion in masterless mode
salt-call --local pkg.remove firefox_x64
Package definition file directory structure and naming#
All package definition files are stored in the location configured in the
winrepo_dir_ng setting. All files in this directory with a .sls file
extension are considered package definition files. These files are evaluated to
create the metadata file on the minion.
You can maintain standalone package definition files that point to software on
other servers or on the internet. In this case the file name is the short name
of the software with the .sls extension, for example,``firefox.sls``.
You can also store the binaries for your software together with their software
definition files in their own directory. In this scenario, the directory name
is the short name for the software and the package definition file stored that
directory is named init.sls.
Look at the following example directory structure on a Linux master assuming default config settings:
srv/
|---salt/
| |---win/
| | |---repo-ng/
| | | |---custom_defs/
| | | | |---ms_office_2013_x64/
| | | | | |---access.en-us/
| | | | | |---excel.en-us/
| | | | | |---outlook.en-us/
| | | | | |---powerpoint.en-us/
| | | | | |---word.en-us/
| | | | | |---init.sls
| | | | | |---setup.dll
| | | | | |---setup.exe
| | | | |---openssl.sls
| | | | |---zoom.sls
| | | |---salt-winrepo-ng/
| | | | |---auditbeat/
| | | | | |---init.sls
| | | | | |---install.cmd
| | | | | |---install.ps1
| | | | | |---remove.cmd
| | | | |---gpg4win/
| | | | | |---init.sls
| | | | | |---silent.ini
| | | | |---7zip.sls
| | | | |---adobereader.sls
| | | | |---audacity.sls
| | | | |---ccleaner.sls
| | | | |---chrome.sls
| | | | |---firefox.sls
In the above directory structure:
The
custom_defsdirectory contains the following custom package definition files.A folder for MS Office 2013 that contains the installer files for all the MS Office software and a package definition file named
init.sls.Two additional standalone package definition files
openssl.slsandzoom.slsto install OpenSSl and Zoom.
The
salt-winrepo-ngdirectory contains the clone of the git repo specified by thewinrepo_remotes_ngconfig setting.
Warning
Do not modify the files in the salt-winrepo-ng directory as it breaks
future runs of winrepo.update_git_repos.
Warning
Do not place any custom software definition files in the salt-winrepo-ng
directory as the winrepo.update_git_repos command wipes out the contents
of the salt-winrepo-ng directory each time it is run and any extra files
stored in the Salt winrepo are lost.
Writing package definition files#
You can write your own software definition file if you know:
The full name of the software as shown in Add/Remove Programs
The exact version number as shown in Add/Remove Programs
How to install your software silently from the command line
Here is a YAML software definition file for Firefox:
firefox_x64:
'74.0':
full_name: Mozilla Firefox 74.0 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en-US/Firefox%20Setup%2074.0.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'73.0.1':
full_name: Mozilla Firefox 73.0.1 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en-US/Firefox%20Setup%2073.0.1.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
The package definition file itself is a data structure written in YAML with three indentation levels:
The first level item is a short name that Salt uses to reference the software. This short name is used to install and remove the software and it must be unique across all package definition files in the repo. Also, there must be only one short name in the file.
The second level item is the version number. There can be multiple version numbers for a package but they must be unique within the file.
Note
When running pkg.list_pkgs, the short name and version number are
displayed when Salt finds a match in the repo. Otherwise, the full package
name is displayed.
The third indentation level contains all parameters that Salt needs to install the software. The parameters are:
full_name: The full name as displayed in Add/Remove Programsinstaller: The location of the installer binaryinstall_flags: The flags required to install silentlyuninstaller: The location of the uninstaller binaryuninstall_flags: The flags required to uninstall silentlymsiexec: Use msiexec to install this packageallusers: If this is an MSI, install to all userscache_dir: Cache the entire directory in the installer URL if it starts withsalt://cache_file: Cache a single file in the installer URL if it starts withsalt://use_scheduler: Launch the installer using the task schedulersource_hash: The hash sum for the installer
Example package definition files#
This section provides some examples of package definition files for different use cases such as:
Writing a simple package definition file
Writing a JINJA templated package definition file
Writing a package definition file to install the latest version of the software
Writing a package definition file to install an MSI patch
These examples enable you to gain a better understanding of the usage of different file parameters. To understand the examples, you need a basic Understanding Jinja. For an exhaustive dive into Jinja, refer to the official Jinja Template Designer documentation.
Example: Simple#
Here is a pure YAML example of a simple package definition file for Firefox:
firefox_x64:
'74.0':
full_name: Mozilla Firefox 74.0 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/74.0/win64/en-US/Firefox%20Setup%2074.0.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'73.0.1':
full_name: Mozilla Firefox 73.0.1 (x64 en-US)
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/73.0.1/win64/en-US/Firefox%20Setup%2073.0.1.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
The first line is the short name of the software which is firefox_x64.
Important
The short name must be unique across all other short names in the software
repository. The full_name combined with the version must also be unique.
The second line is the software version and is indented two spaces.
Important
The version number must be enclosed in quotes or the YAML parser removes the
trailing zeros. For example, if the version number 74.0 is not enclosed
within quotes, then the version number is rendered as 74.
The lines following the version are indented two more spaces and contain all
the information needed to install the Firefox package.
Important
You can specify multiple versions of software by specifying multiple version numbers at the same indentation level as the first with its software definition below it.
Important
The full_name must match exactly what is shown in Add/Remove Programs
(appwiz.cpl)
Example: JINJA templated package definition file#
JINJA is the default templating language used in package definition files. You
can use JINJA to add variables and expressions to package definition files that
get replaced with values when the .sls go through the Salt renderer.
When there are tens or hundreds of versions available for a piece of software, the definition file can become large and cumbersome to maintain. In this scenario, JINJA can be used to add logic, variables, and expressions to automatically create the package definition file for software with multiple versions.
Here is a an example of a package definition file for Firefox that uses JINJA:
{%- set lang = salt['config.get']('firefox:pkg:lang', 'en-US') %}
firefox_x64:
{% for version in ['74.0',
'73.0.1', '73.0',
'72.0.2', '72.0.1', '72.0',
'71.0', '70.0.1', '70.0',
'69.0.3', '69.0.2', '69.0.1'] %}
'{{ version }}':
full_name: 'Mozilla Firefox {{ version }} (x64 {{ lang }})'
installer: 'https://download-installer.cdn.mozilla.net/pub/firefox/releases/{{ version }}/win64/{{ lang }}/Firefox%20Setup%20{{ version }}.exe'
install_flags: '/S'
uninstaller: '%ProgramFiles%\Mozilla Firefox\uninstall\helper.exe'
uninstall_flags: '/S'
{% endfor %}
In this example, JINJA is used to generate a package definition file that
defines how to install 12 versions of Firefox. Jinja is used to create a list of
available versions. The list is iterated through a for loop where each
version is placed in the version variable. The version is inserted
everywhere there is a {{ version }} marker inside the for loop.
The single variable (lang) defined at the top of the package definition
identifies the language of the package. You can access the Salt modules using
the salt keyword. In this case, the config.get function is invoked to
retrieve the language setting. If the lang variable is not defined then the
default value is en-US.
Example: Package definition file to install the latest version#
Some software vendors do not provide access to all versions of their software. Instead, they provide a single URL to what is always the latest version. In some cases, the software keeps itself up to date. One example of this is the Google Chrome web browser.
To handle situations such as these, set the version to latest. Here's an example of a package definition file to install the latest version of Chrome.
chrome:
latest:
full_name: 'Google Chrome'
installer: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi'
install_flags: '/qn /norestart'
uninstaller: 'https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
In the above example:
Versionis set tolatest. Salt then installs the latest version of Chrome at the URL and displays that version.msiexecis set toTrue, hence the software is installed using an MSI.
Example: Package definition file to install an MSI patch#
For MSI installers, when the msiexec parameter is set to true, the /i
option is used for installation, and the /x option is used for
uninstallation. However, when installing an MSI patch, the /i and /x
options cannot be combined.
Here is an example of a package definition file to install an MSI patch:
MyApp:
'1.0':
full_name: MyApp
installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi'
install_flags: '/qn /norestart'
uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}'
uninstall_flags: '/qn /norestart'
msiexec: True
'1.1':
full_name: MyApp
installer: 'salt://win/repo-ng/MyApp/MyApp.1.0.msi'
install_flags: '/qn /norestart /update "%cd%\\MyApp.1.1.msp" '
uninstaller: '{B5B5868F-23BA-297A-917D-0DF345TF5764}'
uninstall_flags: '/qn /norestart'
msiexec: True
cache_file: salt://win/repo-ng/MyApp/MyApp.1.1.msp
In the above example:
Version
1.0of the software installs the application using the1.0MSI defined in theinstallerparameter.There is no file to be cached and the
install_flagsparameter does not include any special values.
Version 1.1 of the software uses the same installer file as Version
1.0. Now, to apply a patch to Version 1.0, make the following changes in
the package definition file:
Place the patch file (MSP file) in the same directory as the installer file (MSI file) on the
file_rootsIn the
cache_fileparameter, specify the path to the single patch file.In the
install_flagsparameter, add the/updateflag and include the path to the MSP file using the%cd%environment variable.%cd%resolves to the current working directory, which is the location in the minion cache where the installer file is cached.
For more information, see issue #32780.
The same approach could be used for applying MST files for MSIs and answer files for other types of .exe-based installers.
Parameters#
This section describes the parameters placed under the version in the
package definition file. Examples can be found on the Salt winrepo repository.
full_name (str)#
The full name of the software as shown in "Add/Remove Programs". You can also
retrieve the full name of the package by installing the package manually and
then running pkg.list_pkgs. Here's an example of the output from
pkg.list_pkgs:
salt 'test-2008' pkg.list_pkgs
test-2008
----------
7-Zip 9.20 (x64 edition):
9.20.00.0
Mozilla Firefox 74.0 (x64 en-US)
74.0
Mozilla Maintenance Service:
74.0
salt-minion-py3:
3001
Notice the full Name for Firefox: Mozilla Firefox 74.0 (x64 en-US). The
full_name parameter in the package definition file must match this name.
The example below shows the pkg.list_pkgs for a machine that has Mozilla
Firefox 74.0 installed with a package definition file for that version of
Firefox.
test-2008:
----------
7zip:
9.20.00.0
Mozilla Maintenance Service:
74.0
firefox_x64:
74.0
salt-minion-py3:
3001
On running pkg.list_pkgs, if any of the software installed on the machine
matches the full name defined in any one of the software definition files in the
repository, then the package name is displayed in the output.
Important
The version number and full_name must match the output of
pkg.list_pkgs so that the installation status can be verified by the
state system.
Note
You can successfully install packages using pkg.install, even if the
full_name or the version number doesn't match. The module will complete
successfully, but continue to display the full name in pkg.list_pkgs.
If this is happening, verify that the full_name and the version
match exactly what is displayed in Add/Remove Programs.
Tip
To force Salt to display the full name when there's already an existing
package definition file on the system, you can pass a bogus saltenv
parameter to the command like so: pkg.list_pkgs saltenv=NotARealEnv
Tip
It's important use pkg.refresh_db
to check for errors and ensure the latest package definition is on any
minion you're testing new definitions on.
installer (str)#
The path to the binary (.exe, .msi) that installs the package.
This can be a local path or a URL. If it is a URL or a Salt path (salt://),
then the package is cached locally and then executed. If it is a path to a file
on disk or a file share, then it is executed directly.
Note
When storing software in the same location as the winrepo:
Create a sub folder named after the package.
Store the package definition file named
init.slsand the binary installer in the same sub folder if you are hosting those files on thefile_roots.
Note
The pkg.refresh_db command processes all .sls files in all sub
directories in the winrepo_dir_ng directory.
install_flags (str)#
The flags passed to the installer for silent installation.
You may be able to find these flags by adding /? or /h when running the
installer from the command line. See WPKG project wiki for information on silent install flags.
Warning
Always ensure that the installer has the ability to install silently, otherwise Salt appears to hang while the installer waits for user input.
uninstaller (str)#
The path to the program to uninstall the software.
This can be the path to the same .exe or .msi used to install the
software. If you use a .msi to install the software, then you can either
use the GUID of the software or the same .msi to uninstall the software.
You can find the uninstall information in the registry:
Software\Microsoft\Windows\CurrentVersion\Uninstall
Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
Here's an example that uses the GUID to uninstall software:
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo-ng/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: '{23170F69-40C1-2702-0920-000001000000}'
uninstall_flags: '/qn /norestart'
msiexec: True
Here's an example that uses the MSI installer to uninstall software:
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo-ng/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: salt://win/repo-ng/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
msiexec: True
uninstall_flags (str)#
The flags passed to the uninstaller for silent uninstallation.
You may be able to find these flags by adding /? or /h when running the
uninstaller from the command-line. See WPKG project wiki for information on silent uninstall flags.
Warning
Always ensure that the installer has the ability to uninstall silently, otherwise Salt appears to hang while the uninstaller waits for user input.
msiexec (bool, str)#
This setting informs Salt to use msiexec /i to install the package and msiexec /x
to uninstall. This setting only applies to .msi installations.
Possible options are:
True
False (default)
the path to
msiexec.exeon your system
7zip:
'9.20.00.0':
full_name: 7-Zip 9.20 (x64 edition)
installer: salt://win/repo/7zip/7z920-x64.msi
install_flags: '/qn /norestart'
uninstaller: salt://win/repo/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
msiexec: 'C:\Windows\System32\msiexec.exe'
allusers (bool)#
This parameter is specific to .msi installations. It tells msiexec to
install the software for all users. The default is True.
cache_dir (bool)#
This setting requires the software to be stored on the file_roots and only
applies to URLs that begin with salt://. If set to True, then the
entire directory where the installer resides is recursively cached. This is
useful for installers that depend on other files in the same directory for
installation.
Warning
If set to True, then all files and directories in the same location as
the installer file are copied down to the minion. For example, if you place
your package definition file with cache_dir: True in the root of winrepo
(/srv/salt/win/repo-ng) then the entire contents of winrepo is cached to
the minion. Therefore, it is best practice to place your package definition
file along with its installer files in a subdirectory if they are stored in
winrepo.
Here's an example using cache_dir:
sqlexpress:
'12.0.2000.8':
full_name: Microsoft SQL Server 2014 Setup (English)
installer: 'salt://win/repo/sqlexpress/setup.exe'
install_flags: '/ACTION=install /IACCEPTSQLSERVERLICENSETERMS /Q'
cache_dir: True
cache_file (str)#
This setting requires the file to be stored on the file_roots and only
applies to URLs that begin with salt://. It indicates that the single file
specified is copied down for use with the installer. It is copied to the same
location as the installer. Use this setting instead of cache_dir when you
only need to cache a single file.
use_scheduler (bool)#
If set to True, Windows uses the task scheduler to run the installation. A
one-time task is created in the task scheduler and launched. The return to the
minion is that the task was launched successfully, not that the software was
installed successfully.
Note
This is used in the package definition for Salt itself. The first thing the Salt installer does is kill the Salt service, which then kills all child processes. If the Salt installer is launched via Salt, then the installer is killed with the salt-minion service, leaving Salt on the machine but not running. Using the task scheduler allows an external process to launch the Salt installer so its processes aren't killed when the Salt service is stopped.
source_hash (str)#
This setting informs Salt to compare a hash sum of the installer to the provided
hash sum before execution. The value can be formatted as <hash_algorithm>=<hash_sum>,
or it can be a URI to a file containing the hash sum.
For a list of supported algorithms, see the hashlib documentation.
Here's an example using source_hash:
messageanalyzer:
'4.0.7551.0':
full_name: 'Microsoft Message Analyzer'
installer: 'salt://win/repo/messageanalyzer/MessageAnalyzer64.msi'
install_flags: '/quiet /norestart'
uninstaller: '{1CC02C23-8FCD-487E-860C-311EC0A0C933}'
uninstall_flags: '/quiet /norestart'
msiexec: True
source_hash: 'sha1=62875ff451f13b10a8ff988f2943e76a4735d3d4'
Not Implemented#
The following parameters are often seen in the software definition files hosted on the Git repo. However, they are not implemented and do not affect the installation process.
- param bool reboot:
Not implemented
- param str locale:
Not implemented
Managing Windows Software on a Standalone Windows Minion#
The Windows Software Repository functions similarly in a standalone environment, with a few differences in the configuration.
To replace the winrepo runner used on the Salt master, an execution module exists to provide the same functionality to standalone
minions. The functions for the module share the same names with functions in the
runner and are used in the same way; the only difference is that salt-call
is used instead of salt-run to run those functions:
salt-call winrepo.update_git_repos
salt-call pkg.refresh_db
After executing the previous commands, the repository on the standalone system is ready for use.
Troubleshooting#
My software installs correctly but pkg.installed says it failed#
If you have a package that seems to install properly but Salt reports a failure
then it is likely you have a version or full_name mismatch.
Check the
full_nameandversionof the package as shown in Add/Remove Programs (appwiz.cpl).Use
pkg.list_pkgsto check that thefull_nameandversionexactly match what is installed.Verify that the
full_nameandversionin the package definition file match the full name and version in Add/Remove programs.Ensure that the
versionis wrapped in single quotes in the package definition file.
Changes to package definition files not being picked up#
Make sure you refresh the database on the minion (pkg.refresh_db) after
updating package definition files in the repo.
salt winminion pkg.refresh_db
Winrepo upgrade issues#
To minimize potential issues, it is a good idea to remove any winrepo git
repositories that were checked out by the legacy (pre-2015.8.0) winrepo code
when upgrading the master to 2015.8.0 or later. Run winrepo.update_git_repos to clone them anew after the master is
started.
pygit2 / GitPython Support for Maintaining Git Repos#
pygit2 and GitPython are the supported python interfaces to Git. The runner
winrepo.update_git_repos uses the
same underlying code as Git Fileserver Backend and
Git External Pillar to maintain and update its
local clones of git repositories.
Note
If compatible versions of both pygit2 and GitPython are installed, then
Salt will prefer pygit2. To override this behavior use the
winrepo_provider configuration parameter, ie:
winrepo_provider: gitpython
Accessing authenticated Git repos (pygit2)#
pygit2 enables you to access authenticated git repositories and set per-remote config settings. An example of this is:
winrepo_remotes:
- https://github.com/saltstack/salt-winrepo.git
- git@github.com:myuser/myrepo.git:
- pubkey: /path/to/key.pub
- privkey: /path/to/key
- passphrase: myaw3s0m3pa$$phr4$3
- https://github.com/myuser/privaterepo.git:
- user: mygithubuser
- password: CorrectHorseBatteryStaple
Note
The per-remote configuration settings work in the same manner as they do in
gitfs, with global parameters being overridden by their per-remote
counterparts. For instance, setting winrepo_passphrase
sets a global passphrase for winrepo that applies to all SSH-based
remotes, unless overridden by a passphrase per-remote parameter.
See here for a detailed explanation of how per-remote configuration works in gitfs. The same principles apply to winrepo.
Maintaining Git repos#
A clean argument is added to the
winrepo.update_git_repos
runner to maintain the Git repos. When clean=True the runner removes
directories under the winrepo_dir_ng/winrepo_dir_ng
that are not explicitly configured. This eliminates the need to manually remove
these directories when a repo is removed from the config file.
salt-run winrepo.update_git_repos clean=True
If a mix of git and non-git Windows Repo definition files are used, then
do not pass clean=True, as it removes the directories containing non-git
definitions.
Name collisions between repos#
Salt detects collisions between repository names. The
winrepo.update_git_repos
runner does not execute successfully if any collisions between repository names
are detected. Consider the following configuration:
winrepo_remotes:
- https://foo.com/bar/baz.git
- https://mydomain.tld/baz.git
- https://github.com/foobar/baz.git
With the above configuration, the winrepo.update_git_repos
runner fails to execute as all three repos would be checked out to the same
directory. To resolve this conflict, use the per-remote parameter called
name.
winrepo_remotes:
- https://foo.com/bar/baz.git
- https://mydomain.tld/baz.git:
- name: baz_junior
- https://github.com/foobar/baz.git:
- name: baz_the_third
Now on running the winrepo.update_git_repos:
https://foo.com/bar/baz.git repo is initialized and cloned under the
win_repo_dir_ngdirectory.https://mydomain.tld/baz.git repo is initialized and cloned under the
win_repo_dir_ng\baz_juniordirectory.https://github.com/foobar/baz.git repo is initialized and cloned under the
win_repo_dir_ng\baz_the_thirddirectory.