Windows Software Repository
Note
In 2015.8.0 and later, the Windows Software Repository cache is compiled on
the Salt Minion, which enables pillar, grains and other things to be
available during compilation time. To support this new functionality,
a next-generation (ng) package repository was created. See the
Changes in Version 2015.8.0 for details.
The SaltStack Windows Software Repository provides a package manager and software
repository similar to what is provided by yum and apt on Linux. This repository
enables the installation of software using the installers on remote Windows
systems.
In many senses, the operation is similar to that of
the other package managers salt is aware of:
High level differences to yum and apt are:
The repository metadata (SLS files) is hosted through either salt or
git.
Packages can be downloaded from within the salt repository, a git
repository or from HTTP(S) or FTP URLs.
No dependencies are managed. Dependencies between packages needs to
be managed manually.
Requirements:
Configuration
Populate the Repository
The SLS files used to install Windows packages are not distributed by default with
Salt. Run the following command to initialize the repository on your Salt
master:
salt-run winrepo.update_git_repos
Sync Repo to Windows Minions
Run pkg.refresh_db
on each of your Windows minions to synchronize
the package repository.
salt -G 'os:windows' pkg.refresh_db
Note
Use pkg.refresh_db
from 2016.11 when developing new Windows package
definitions to check for errors in the definitions against one or more
Windows minions.
Install Windows Software
After completing the configuration steps, you are ready to manage software on your
Windows minions.
Show Installed Packages
salt -G 'os:windows' pkg.list_pkgs
Install a Package
You can query the available version of a package using the Salt pkg module.
salt winminion pkg.list_available firefox
winminion:
- 15.0.1
- 16.0.2
- 17.0.1
As you can see, there are three versions of Firefox available for installation.
You can refer a software package by its name
or its full_name
surround
by single quotes.
salt winminion pkg.install 'firefox'
The above line will install the latest version of Firefox.
salt winminion pkg.install 'firefox' version=16.0.2
The above line will install version 16.0.2 of Firefox.
If a different version of the package is already installed it will be replaced
with the version in the winrepo (only if the package itself supports live
updating).
You can also specify the full name:
salt winminion pkg.install 'Mozilla Firefox 17.0.1 (x86 en-US)'
Uninstall Windows Software
Uninstall software using the pkg module:
salt winminion pkg.remove firefox
salt winminion pkg.purge firefox
Note
pkg.purge
just executes pkg.remove
on Windows. At some point in the
future pkg.purge
may direct the installer to remove all configs and
settings for software packages that support that option.
Repository Location
Salt maintains a repository of SLS files to install a large number of Windows
packages:
By default, these repositories are mirrored to /srv/salt/win/repo-ng
and /srv/salt/win/repo
.
This location can be changed in the master config file by setting the
winrepo_dir_ng
and winrepo_dir
options.
Maintaining Windows Repo Definitions in Git Repositories
Windows software package definitions can be hosted in one or more Git
repositories. The default repositories are hosted on GitHub by SaltStack. These
include software definition files for various open source software projects.
These software definition files are .sls
files. There are two default
repositories: salt-winrepo
and salt-winrepo-ng
. salt-winrepo
contains software definition files for older minions (older than 2015.8.0).
salt-winrepo-ng
is for newer minions (2015.8.0 and newer).
Each software definition file contains all the information salt needs to install
that software on a minion including the HTTP or FTP locations of the installer
files, required command-line switches for silent install, etc. Anyone is welcome
to send a pull request to this repo to add new package definitions. The repos
can be browsed here:
salt-winrepo
salt-winrepo-ng
Note
The newer software definition files are run through the salt's parser which
allows for the use of jinja.
Configure which git repositories the master can search for package definitions
by modifying or extending the winrepo_remotes
and
winrepo_remotes_ng
options.
Important
winrepo_remotes
was called win_gitrepos
in Salt versions earlier
than 2015.8.0
Package definitions are pulled down from the online git repository by running the
winrepo.update_git_repos
runner.
This command is run on the master:
salt-run winrepo.update_git_repos
This will pull down the software definition files for older minions
(salt-winrepo
) and new minions (salt-winrepo-ng
). They are stored in the
file_roots
under win/repo/salt-winrepo
and
win/repo-ng/salt-winrepo-ng
respectively.
Important
If you have customized software definition files that aren't maintained in a
repository, those should be stored under win/repo
for older minions and
win/repo-ng
for newer minions. The reason for this is that the contents
of win/repo/salt-winrepo
and win/repo-ng/salt-winrepo-ng
are wiped
out every time you run a winrepo.update_git_repos
.
Additionally, when you run winrepo.genrepo
and pkg.refresh_db
the
entire contents under win/repo
and win/repo-ng
, to include all
subdirectories, are used to create the meta database file.
The next step (if you have older minions) is to create the meta database file for the
repo (winrepo.p
). This is done by running the
winrepo.genrepo
runner. This is also run
on the master:
Note
If you have only 2015.8.0 and newer minions, you no longer need to run
salt-run winrepo.genrepo
on the master.
Finally, you need to refresh the minion database by running the
pkg.refresh_db
command. This is run
on the master as well:
On older minions (older than 2015.8.0) this will copy the winrepo.p file down to
the minion. On newer minions (2015.8.0 and newer) this will copy all the
software definition files (.sls) down to the minion and then create the meta
database file (winrepo.p
) locally. The reason this is done locally is because the
jinja needs to be parsed using the minion's grains.
Important
Every time you modify the software definition files on the master, either by
running salt-run winrepo.update_git_repos
, modifying existing files, or
by creating your own, you need to refresh the database on your minions. For
older minions, that means running salt-run winrepo.genrepo
and then
salt '*' pkg.refresh_db
. For newer minions (2015.8.0 and newer) it is
just salt '*' pkg.refresh_db
.
Note
If the winrepo.genrepo
or the pkg.refresh_db
fails, it is likely a
problem with the jinja in one of the software definition files. This will
cause the operations to stop. You'll need to fix the syntax in order for the
meta database file to be created successfully.
To disable one of the repos, set it to an empty list []
in the master
config. For example, to disable winrepo_remotes
set the following
in the master config file:
Creating a Package Definition SLS File
The package definition file is a YAML file that contains all the information
needed to install a piece of software using salt. It defines information about
the package to include version, full name, flags required for the installer and
uninstaller, whether or not to use the Windows task scheduler to install the
package, where to find the installation package, etc.
Take a look at this example for Firefox:
firefox:
'17.0.1':
installer: 'salt://win/repo/firefox/English/Firefox Setup 17.0.1.exe'
full_name: Mozilla Firefox 17.0.1 (x86 en-US)
locale: en_US
reboot: False
install_flags: '-ms'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'16.0.2':
installer: 'salt://win/repo/firefox/English/Firefox Setup 16.0.2.exe'
full_name: Mozilla Firefox 16.0.2 (x86 en-US)
locale: en_US
reboot: False
install_flags: '-ms'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
'15.0.1':
installer: 'salt://win/repo/firefox/English/Firefox Setup 15.0.1.exe'
full_name: Mozilla Firefox 15.0.1 (x86 en-US)
locale: en_US
reboot: False
install_flags: '-ms'
uninstaller: '%ProgramFiles(x86)%/Mozilla Firefox/uninstall/helper.exe'
uninstall_flags: '/S'
Each software definition file begins with a package name for the software. As in
the example above firefox
. The next line is indented two spaces and contains
the version to be defined. As in the example above, a software definition file
can define multiple versions for the same piece of software. The lines following
the version are indented two more spaces and contain all the information needed
to install that package.
Warning
The package name and the full_name
must be unique to all other packages
in the software repository.
The version line is the version for the package to be installed. It is used when
you need to install a specific version of a piece of software.
Warning
The version must be enclosed in quotes, otherwise the YAML parser will
remove trailing zeros.
Note
There are unique situations where previous versions are unavailable. Take
Google Chrome for example. There is only one URL provided for a standalone
installation of Google Chrome.
(https://dl.google.com/edgedl/chrome/install/GoogleChromeStandaloneEnterprise.msi)
When a new version is released, the URL just points to the new version. To
handle situations such as these, set the version to latest. Salt will
install the version of Chrome at the URL and report that version. Here's an
example:
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
locale: en_US
reboot: False
Available parameters are as follows:
- param str full_name
The Full Name for the software as shown in "Programs and Features" in the
control panel. You can also get this information 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
Microsoft .NET Framework 4 Client Profile:
4.0.30319,4.0.30319
Microsoft .NET Framework 4 Extended:
4.0.30319,4.0.30319
Microsoft Visual C++ 2008 Redistributable - x64 9.0.21022:
9.0.21022
Mozilla Firefox 17.0.1 (x86 en-US):
17.0.1
Mozilla Maintenance Service:
17.0.1
NSClient++ (x64):
0.3.8.76
Notepad++:
6.4.2
Salt Minion 0.16.0:
0.16.0
Notice the Full Name for Firefox: Mozilla Firefox 17.0.0 (x86 en-US)
.
That's exactly what's in the full_name
parameter in the software
definition file.
If any of the software installed on the machine matches one of the software
definition files in the repository, the full_name will be automatically
renamed to the package name. The example below shows the pkg.list_pkgs
for a machine that already has Mozilla Firefox 17.0.1 installed.
test-2008:
----------
7zip:
9.20.00.0
Microsoft .NET Framework 4 Client Profile:
4.0.30319,4.0.30319
Microsoft .NET Framework 4 Extended:
4.0.30319,4.0.30319
Microsoft Visual C++ 2008 Redistributable - x64 9.0.21022:
9.0.21022
Mozilla Maintenance Service:
17.0.1
Notepad++:
6.4.2
Salt Minion 0.16.0:
0.16.0
firefox:
17.0.1
nsclient:
0.3.9.328
Important
The version number and full_name
need to match the output from
pkg.list_pkgs
so that the status can be verified when running a
highstate.
Note
It is still possible to successfully install packages using
pkg.install
, even if the full_name
or the version number don't
match. However, this can make troubleshooting issues difficult, so be
careful.
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
- param str installer
The path to the .exe
or .msi
to use to install the package. This can
be a path or a URL. If it is a URL or a salt path (salt://
), the package
will be cached locally and then executed. If it is a path to a file on disk
or a file share, it will be executed directly.
Note
If storing software in the same location as the winrepo it is best
practice to place each installer in its own directory rather than the
root of winrepo. Then you can place your package definition file in the
same directory. It is best practice to name the file init.sls
. This
will be picked up by pkg.refresh_db
and processed properly.
- param str install_flags
Any flags that need to be passed to the installer to make it perform a
silent install. These can often be found by adding /?
or /h
when
running the installer from the command-line. A great resource for finding
these silent install flags can be found on the WPKG project's wiki:
Warning
Salt will not return if the installer is waiting for user input so it is
imperative that the software package being installed has the ability to
install silently.
- param str uninstaller
The path to the program used to uninstall this software. This can be the
path to the same exe or msi used to install the software. It can also be
a GUID. You can find this value in the registry under the following keys:
- param str uninstall_flags
Any flags that need to be passed to the uninstaller to make it perform a
silent uninstall. These can often be found by adding /?
or /h
when
running the uninstaller from the command-line. A great resource for finding
these silent install flags can be found on the WPKG project's wiki:
Warning
Salt will not return if the uninstaller is waiting for user input so it
is imperative that the software package being uninstalled has the
ability to uninstall silently.
Here are some examples of installer and uninstaller settings:
7zip:
'9.20.00.0':
installer: salt://win/repo/7zip/7z920-x64.msi
full_name: 7-Zip 9.20 (x64 edition)
reboot: False
install_flags: '/qn /norestart'
msiexec: True
uninstaller: '{23170F69-40C1-2702-0920-000001000000}'
uninstall_flags: '/qn /norestart'
Alternatively the uninstaller
can also simply repeat the URL of an msi
file:
7zip:
'9.20.00.0':
installer: salt://win/repo/7zip/7z920-x64.msi
full_name: 7-Zip 9.20 (x64 edition)
reboot: False
install_flags: '/qn /norestart'
msiexec: True
uninstaller: salt://win/repo/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
- param msiexec
This tells salt to use msiexec /i
to install the package and
msiexec /x
to uninstall. This is for .msi
installations. Possible
options are: True, False or the path to msiexec.exe
on your system
7zip:
'9.20.00.0':
installer: salt://win/repo/7zip/7z920-x64.msi
full_name: 7-Zip 9.20 (x64 edition)
reboot: False
install_flags: '/qn /norestart'
msiexec: 'C:\Windows\System32\msiexec.exe'
uninstaller: salt://win/repo/7zip/7z920-x64.msi
uninstall_flags: '/qn /norestart'
- param bool allusers
This parameter is specific to .msi
installations. It tells msiexec
to install the software for all users. The default is True
.
- param bool cache_dir
If True
and the installer URL begins with salt://
, the entire
directory where the installer resides will be recursively cached. This is
useful for installers that depend on other files in the same directory for
installation.
Warning
Be aware that all files and directories in the same location as the
installer file will be copied down to the minion. If you place your
installer file in the root of winrepo (/srv/salt/win/repo-ng
) and
cache_dir: True
the entire contents of winrepo will be cached to
the minion. Therefore, it is best practice to place your installer files
in a subdirectory if they are to be stored in winrepo.
- param str cache_file
When the installer URL begins with salt://
, this indicates a single file
to copy down for use with the installer. It is copied to the same location
as the installer. Use this over cache_dir
if there are many files in the
directory and you only need a specific file and don't want to cache
additional files that may reside in the installer directory.
Here's an example for a software package that has dependent files:
sqlexpress:
'12.0.2000.8':
installer: 'salt://win/repo/sqlexpress/setup.exe'
full_name: Microsoft SQL Server 2014 Setup (English)
reboot: False
install_flags: '/ACTION=install /IACCEPTSQLSERVERLICENSETERMS /Q'
cache_dir: True
- param bool use_scheduler
If True
, Windows will use the task scheduler to run the installation.
This is useful for running the Salt installation itself as the installation
process kills any currently running instances of Salt.
- param str source_hash
This tells 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 of source_hash usage:
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'
- param bool reboot
Not implemented
- param str locale
Not implemented
Examples can be found at https://github.com/saltstack/salt-winrepo-ng
Managing Windows Software on a Standalone Windows Minion
The Windows Package Repository functions similar in a standalone environment,
with a few differences in the configuration.
To replace the winrepo runner that is used on the Salt master, an execution module
exists to provide the same functionality to standalone
minions. The functions are named the same as the ones in the runner, and are
used in the same way; the only difference is that salt-call
is used instead
of salt-run
:
salt-call winrepo.update_git_repos
salt-call winrepo.genrepo
salt-call pkg.refresh_db
After executing the previous commands the repository on the standalone system
is ready to use.
Custom Location for Repository SLS Files
If file_roots
has not been modified in the minion
configuration, then no additional configuration needs to be added to the
minion configuration. The winrepo.genrepo
function from the winrepo
execution module will by default look for the
filename specified by winrepo_cachefile
within
C:\salt\srv\salt\win\repo
.
If the file_roots
parameter has been modified, then
winrepo_dir
must be modified to fall within that path, at the
proper relative path. For example, if the base
environment in
file_roots
points to D:\foo
, and
winrepo_source_dir
is salt://win/repo
, then
winrepo_dir
must be set to D:\foo\win\repo
to ensure that
winrepo.genrepo
puts the cachefile
into right location.
Configuration options for Minions 2015.8.0 and later
On newer minions (2015.8.0 and later), the winrepo_source_dir
config parameter (default: salt://win/repo-ng
) controls where
pkg.refresh_db
looks for the software
definition files that will be downloaded to the minion and used to generate the
local database file (winrepo.p
).
Software package definitions are automatically refreshed if stale after
winrepo_cache_expire_max
. Running a highstate normal forces the
refresh of the package definition and generation of the meta database, unless
the meta database is younger than winrepo_cache_expire_max
.
Refreshing the package definitions can take some time, these options were
introduced to allow more control of when it occurs.
It's important use pkg.refresh_db
to check for errors and ensure the latest package definition is on any minion
your testing new definitions on.
Configuration options for Minions before 2015.8.0
On older minions (before 2015.8.0), the winrepo_source_dir
config parameter (default: salt://win/repo
) controls where
pkg.refresh_db
looks for the cachefile
(default: winrepo.p
). This means that the default location for the winrepo
cachefile would be salt://win/repo/winrepo.p
. Both :conf_minion:
winrepo_source_dir` and winrepo_cachefile
can be adjusted to
match the actual location of this file on the Salt fileserver.
If connected to a master, the minion will by default look for the winrepo
cachefile (the file generated by the winrepo.genrepo runner
) at salt://win/repo/winrepo.p
. If the
cachefile is in a different path on the salt fileserver, then
win_repo_cachefile
will need to be updated to reflect the proper
location.
Changes in Version 2015.8.0
Git repository management for the Windows Software Repository has changed
in version 2015.8.0, and several master/minion config parameters have been
renamed to make their naming more consistent with each other.
For a list of the winrepo config options, see here for master config options, and here for configuration options for masterless Windows
minions.
On the master, the winrepo.update_git_repos
runner has been updated to use either
pygit2 or GitPython to checkout the git repositories containing repo data. If
pygit2 or GitPython is installed, existing winrepo git checkouts should be
removed after upgrading to 2015.8.0, to allow them to be checked out again by
running winrepo.update_git_repos
.
If neither GitPython nor pygit2 are installed, then Salt will fall back to
the pre-existing behavior for winrepo.update_git_repos
, and a warning will be logged in the
master log.
Note
Standalone Windows minions do not support the new GitPython/pygit2
functionality, and will instead use the git.latest
state to keep repositories up-to-date. More
information on how to use the Windows Software Repo on a standalone minion
can be found here.
Config Parameters Renamed
Many of the legacy winrepo configuration parameters have changed in version 2015.8.0
to make the naming more consistent. The old parameter names will still work,
but a warning will be logged indicating that the old name is deprecated.
Below are the parameters which have changed for version 2015.8.0:
Master Config
Note
winrepo_cachefile
is no longer used by 2015.8.0 and later minions, and
the winrepo_dir
setting is replaced by winrepo_dir_ng
for 2015.8.0
and later minions.
See here for detailed information on all
master config options for the Windows Repo.
Minion Config
See here for detailed information on all
minion config options for the Windows Repo.
pygit2/GitPython Support for Maintaining Git Repos
The winrepo.update_git_repos
runner (and the corresponding remote execution function
for standalone minions) now makes use
of the same underlying code used by the Git Fileserver Backend and Git External Pillar
to
maintain and update its local clones of git repositories. If a compatible
version of either pygit2 (0.20.3 and later) or GitPython (0.3.0 or later) is
installed, then Salt will use it instead of the old method (which invokes the
git.latest
state).
To minimize potential issues, it is a good idea to remove any winrepo git
repositories that were checked out by the old (pre-2015.8.0) winrepo code when
upgrading the master to 2015.8.0 or later, and run
winrepo.update_git_repos
to
clone them anew after the master is started.
Additional added features include the ability to access authenticated git
repositories (NOTE: pygit2 only), and to set per-remote config settings.
An example of this would be the following:
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
Per-remote configuration settings work in the same fashion as they do in
gitfs, with global parameters being overridden by their per-remote
counterparts (for instance, setting winrepo_passphrase
would
set a global passphrase for winrepo that would apply to all SSH-based
remotes, unless overridden by a passphrase
per-remote parameter).
See here for more a more in-depth
explanation of how per-remote configuration works in gitfs, the same
principles apply to winrepo.
There are a couple other changes in how Salt manages git repos using
pygit2/GitPython. First of all, a clean
argument has been added to the
winrepo.update_git_repos
runner, which (if set to True
) will tell the runner to dispose of
directories under the winrepo_dir
which are not explicitly
configured. This prevents the need to manually remove these directories when a
repo is removed from the config file. To clean these old directories, just pass
clean=True
, like so:
salt-run winrepo.update_git_repos clean=True
However, if a mix of git and non-git Windows Repo definition files are being
used, then this should not be used, as it will remove the directories
containing non-git definitions.
The other major change is that collisions between repo names are now detected,
and the winrepo.update_git_repos
runner will not proceed if any are
detected. Consider the following configuration:
winrepo_remotes:
- https://foo.com/bar/baz.git
- https://mydomain.tld/baz.git
- https://github.com/foobar/baz
The winrepo.update_git_repos
runner will refuse to update repos here, as all three of these repos would be
checked out to the same directory. To work around this, a per-remote parameter
called name
can be used to resolve these conflicts:
winrepo_remotes:
- https://foo.com/bar/baz.git
- https://mydomain.tld/baz.git:
- name: baz_junior
- https://github.com/foobar/baz:
- name: baz_the_third
Troubleshooting
Incorrect name/version
If the package seems to install properly, but salt reports a failure then it is
likely you have a version or full_name
mismatch.
Check the exact full_name
and version used by the package. Use
pkg.list_pkgs
to check that the names and version exactly match what is
installed.
Changes to sls files not being picked up
Ensure you have (re)generated the repository cache file (for older minions) and
then updated the repository cache on the relevant minions:
salt-run winrepo.genrepo
salt winminion pkg.refresh_db
Packages management under Windows 2003
On Windows server 2003, you need to install optional Windows component "wmi
Windows installer provider" to have full list of installed packages. If you
don't have this, salt-minion can't report some installed software.
How Success and Failure are Reported
The install state/module function of the Windows package manager works roughly
as follows:
Execute pkg.list_pkgs
and store the result
Check if any action needs to be taken. (i.e. compare required package
and version against pkg.list_pkgs
results)
If so, run the installer command.
Execute pkg.list_pkgs
and compare to the result stored from
before installation.
Success/Failure/Changes will be reported based on the differences
between the original and final pkg.list_pkgs
results.
If there are any problems in using the package manager it is likely due to the
data in your sls files not matching the difference between the pre and post
pkg.list_pkgs
results.