Hello community,

here is the log from the commit of package salt for openSUSE:Factory checked in 
at 2016-02-24 18:43:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/salt (Old)
 and      /work/SRC/openSUSE:Factory/.salt.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "salt"

Changes:
--------
--- /work/SRC/openSUSE:Factory/salt/salt.changes        2016-01-26 
10:14:45.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.salt.new/salt.changes   2016-02-24 
18:43:08.000000000 +0100
@@ -1,0 +2,165 @@
+Tue Feb 23 11:58:00 CET 2016 - [email protected]
+
+- fix argument handling of pkg.download
+  Add: 0022-fix-argument-handling-for-pkg.download.patch
+
+-------------------------------------------------------------------
+Mon Feb 22 16:12:43 CET 2016 - [email protected]
+
+- unify behavior of zypper refresh in salt
+  Add: 0018-unify-behavior-of-refresh.patch
+       0019-add-refresh-option-to-more-functions.patch
+       0020-simplify-checking-the-refresh-paramater.patch
+       0021-do-not-change-kwargs-in-refresh-while-checking-a-val.patch
+
+-------------------------------------------------------------------
+Sat Feb 20 11:41:45 CET 2016 - [email protected]
+
+- Fix crash with scheduler and runners
+  Add: 0017-Fix-crash-with-scheduler-and-runners-31106.patch
+
+-------------------------------------------------------------------
+Fri Feb 19 15:01:38 CET 2016 - [email protected]
+
+- Call zypper always with --non-interactive
+  Add:
+  * 0015-call-zypper-with-option-non-interactive-everywhere.patch
+  * 0016-write-a-zypper-command-builder-function.patch
+
+-------------------------------------------------------------------
+Fri Feb 19 13:00:52 CET 2016 - [email protected]
+
+- require rpm-python on SUSE for zypper support
+
+-------------------------------------------------------------------
+Thu Feb 18 11:01:21 CET 2016 - [email protected]
+
+- fix state return code
+  Add: 0009-The-functions-in-the-state-module-that-return-a-retc.patch
+- add handling of OEM products to pkg.list_products
+  Add: 0010-add-handling-for-OEM-products.patch
+- improve doc for list_pkgs
+  Add: 0011-improve-doc-for-list_pkgs.patch
+- implement pkg.version_cmp in zypper.py
+  Add:
+  * 0012-implement-version_cmp-for-zypper.patch
+  * 0013-pylint-changes.patch
+  * 0014-Check-if-rpm-python-can-be-imported.patch
+
+-------------------------------------------------------------------
+Wed Feb 17 17:57:57 UTC 2016 - [email protected]
+
+- Update to 2015.8.7
+  this is a small update to fix some regressions
+  see https://docs.saltstack.com/en/latest/topics/releases/2015.8.7.html
+
+-------------------------------------------------------------------
+Thu Feb 11 17:42:38 UTC 2016 - [email protected]
+
+- Booleans should not be strings from XML, add Unix ticks time and
+  format result in a list of maps.
+  Add:
+  * 0008-Fix-types-in-the-output-data-and-return-just-a-list-.patch
+
+-------------------------------------------------------------------
+Thu Feb 11 16:27:33 UTC 2016 - [email protected]
+
+- Stop salt-api daemon faster (bsc#963322)
+  Add:
+  * 0007-Force-kill-websocket-s-child-processes-faster-than-d.patch
+
+-------------------------------------------------------------------
+Wed Feb 10 08:30:45 UTC 2016 - [email protected]
+
+- Do not crash on salt-key reject/delete consecutive calls.
+  Add:
+  * 0006-add_key-reject_key-do-not-crash-w-Permission-denied-.patch
+
+-------------------------------------------------------------------
+Mon Feb  8 16:15:56 UTC 2016 - [email protected]
+
+- Update to 2015.8.5
+  See https://docs.saltstack.com/en/latest/topics/releases/2015.8.5.html
+  Dropped patches (all upstream):
+  * 0003-List-products-consistently-across-all-SLES-systems.patch
+  * 0004-Add-missing-return-data-to-scheduled-jobs.patch
+  * 0005-Fix-RPM-issues-with-the-date-time-and-add-package-at.patch
+  * 0006-Bugfix-info_available-does-not-work-correctly-on-SLE.patch
+  Renamed patches:
+  * 0007-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch
+    -> 0003-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch
+  * 0008-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
+    -> 0004-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
+  * 0009-Fix-package-status-filtering-on-latest-version-and-i.patch
+    -> 0005-Fix-package-status-filtering-on-latest-version-and-i.patch
+
+- Update to 2015.8.4
+  See https://docs.saltstack.com/en/latest/topics/releases/2015.8.4.html
+
+-------------------------------------------------------------------
+Wed Jan 27 13:09:53 UTC 2016 - [email protected]
+
+- Fix latest version available comparison and implement epoch
+  support in Zypper module.
+  Add:
+  * 0009-Fix-package-status-filtering-on-latest-version-and-i.patch
+
+-------------------------------------------------------------------
+Wed Jan 27 09:25:15 UTC 2016 - [email protected]
+
+- Update patch from opensuse to upstream version.
+  Update:
+  * 0008-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
+
+-------------------------------------------------------------------
+Tue Jan 26 09:42:57 UTC 2016 - [email protected]
+
+- Fix dependencies to Salt subpackages requiring release along the
+  version.
+
+-------------------------------------------------------------------
+Mon Jan 25 16:24:55 UTC 2016 - [email protected]
+
+- Fix pkg.latest crash.
+- Fix pkg.latest SLS ID bug, when pkgs empty list is passed,
+  but SLS ID still treated as a package name.
+
+  Add:
+  * 0008-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
+
+-------------------------------------------------------------------
+Wed Jan 20 15:10:04 UTC 2016 - [email protected]
+
+- Drop:
+  * -0004-zypper-check-package-header-content-for-valid-utf-8.patch
+- Rename:
+  * -0004-zypper-check-package-header-content-for-valid-utf-8.patch
+    +0004-Add-missing-return-data-to-scheduled-jobs.patch
+  * -0005-Add-missing-return-data-to-scheduled-jobs.patch
+    +0004-Add-missing-return-data-to-scheduled-jobs.patch
+  * -0006-Fix-RPM-issues-with-the-date-time-and-add-package-at.patch
+    +0005-Fix-RPM-issues-with-the-date-time-and-add-package-at.patch
+  * -0007-Bugfix-info_available-does-not-work-correctly-on-SLE.patch
+    +0006-Bugfix-info_available-does-not-work-correctly-on-SLE.patch
+- Add:
+  * 0007-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch
+
+-------------------------------------------------------------------
+Wed Jan 20 10:19:07 UTC 2016 - [email protected]
+
+- Rename use-forking-daemon.patch to
+  0001-tserong-suse.com-We-don-t-have-python-systemd-so-not.patch
+- Rename use-salt-user-for-master.patch to
+  0002-Run-salt-master-as-dedicated-salt-user.patch
+- Rename 1efe484309a5c776974e723f3da0f5181f4bdb86.patch to
+  0003-List-products-consistently-across-all-SLES-systems.patch
+- Rename zypper-utf-8.patch to
+  0004-zypper-check-package-header-content-for-valid-utf-8.patch
+- Rename salt-2015.8-schedule-ret.patch to
+  0005-Add-missing-return-data-to-scheduled-jobs.patch
+- Rename salt-2015.8-pkg-zypper-attr-filtering.patch to
+  0006-Fix-RPM-issues-with-the-date-time-and-add-package-at.patch
+- Rename salt-2015.8-zypper-info.patch to
+  0007-Bugfix-info_available-does-not-work-correctly-on-SLE.patch
+
+-------------------------------------------------------------------

Old:
----
  1efe484309a5c776974e723f3da0f5181f4bdb86.patch
  salt-2015.8-pkg-zypper-attr-filtering.patch
  salt-2015.8-schedule-ret.patch
  salt-2015.8-zypper-info.patch
  salt-2015.8.3.tar.gz
  use-forking-daemon.patch
  use-salt-user-for-master.patch
  zypper-utf-8.patch

New:
----
  0001-tserong-suse.com-We-don-t-have-python-systemd-so-not.patch
  0002-Run-salt-master-as-dedicated-salt-user.patch
  0003-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch
  0004-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
  0005-Fix-package-status-filtering-on-latest-version-and-i.patch
  0006-add_key-reject_key-do-not-crash-w-Permission-denied-.patch
  0007-Force-kill-websocket-s-child-processes-faster-than-d.patch
  0008-Fix-types-in-the-output-data-and-return-just-a-list-.patch
  0009-The-functions-in-the-state-module-that-return-a-retc.patch
  0010-add-handling-for-OEM-products.patch
  0011-improve-doc-for-list_pkgs.patch
  0012-implement-version_cmp-for-zypper.patch
  0013-pylint-changes.patch
  0014-Check-if-rpm-python-can-be-imported.patch
  0015-call-zypper-with-option-non-interactive-everywhere.patch
  0016-write-a-zypper-command-builder-function.patch
  0017-Fix-crash-with-scheduler-and-runners-31106.patch
  0018-unify-behavior-of-refresh.patch
  0019-add-refresh-option-to-more-functions.patch
  0020-simplify-checking-the-refresh-paramater.patch
  0021-do-not-change-kwargs-in-refresh-while-checking-a-val.patch
  0022-fix-argument-handling-for-pkg.download.patch
  salt-2015.8.7.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ salt.spec ++++++
--- /var/tmp/diff_new_pack.jfoIOI/_old  2016-02-24 18:43:09.000000000 +0100
+++ /var/tmp/diff_new_pack.jfoIOI/_new  2016-02-24 18:43:09.000000000 +0100
@@ -36,29 +36,56 @@
 %bcond_without docs
 
 Name:           salt
-Version:        2015.8.3
+Version:        2015.8.7
 Release:        0
 Summary:        A parallel remote execution system
 License:        Apache-2.0
 Group:          System/Monitoring
 Url:            http://saltstack.org/
+# Git: https://github.com/openSUSE/salt.git
 Source0:        
http://pypi.python.org/packages/source/s/%{name}/%{name}-%{version}.tar.gz
 Source1:        README.SUSE
 Source2:        salt-tmpfiles.d
+
 # PATCH-FIX-OPENSUSE use-forking-daemon.patch [email protected] -- We don't 
have python-systemd, so notify can't work
-Patch1:         use-forking-daemon.patch
+Patch1:         0001-tserong-suse.com-We-don-t-have-python-systemd-so-not.patch
 # PATCH-FIX-OPENSUSE use-salt-user-for-master.patch -- Run salt master as 
dedicated salt user
-Patch2:         use-salt-user-for-master.patch
-# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/29244
-Patch3:         1efe484309a5c776974e723f3da0f5181f4bdb86.patch
-# PATCH-FIX-OPENSUSE detect bad UTF-8 in package header, bsc#958350
-Patch4:         zypper-utf-8.patch
-# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/30246
-Patch5:         salt-2015.8-schedule-ret.patch
-# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/30267
-Patch6:         salt-2015.8-pkg-zypper-attr-filtering.patch
-# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/30384
-Patch7:         salt-2015.8-zypper-info.patch
+Patch2:         0002-Run-salt-master-as-dedicated-salt-user.patch
+# PATCH-FIX-OPENSUSE https://github.com/saltstack/salt/pull/30424
+Patch3:         0003-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch
+# PATCH-FIX-OPENSUSE https://github.com/saltstack/salt/pull/30611
+Patch4:         0004-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch
+# PATCH-FIX-OPENSUSE https://github.com/saltstack/salt/pull/30663
+Patch5:         0005-Fix-package-status-filtering-on-latest-version-and-i.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/30998
+Patch6:         0006-add_key-reject_key-do-not-crash-w-Permission-denied-.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31125
+Patch7:         0007-Force-kill-websocket-s-child-processes-faster-than-d.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31134
+Patch8:         0008-Fix-types-in-the-output-data-and-return-just-a-list-.patch
+# PATCH-FIX-UPSTREAM 
+Patch9:         0009-The-functions-in-the-state-module-that-return-a-retc.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31237
+Patch10:        0010-add-handling-for-OEM-products.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31234
+Patch11:        0011-improve-doc-for-list_pkgs.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31233
+Patch12:        0012-implement-version_cmp-for-zypper.patch
+Patch13:        0013-pylint-changes.patch
+Patch14:        0014-Check-if-rpm-python-can-be-imported.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31305
+Patch15:        0015-call-zypper-with-option-non-interactive-everywhere.patch
+Patch16:        0016-write-a-zypper-command-builder-function.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31189
+Patch17:        0017-Fix-crash-with-scheduler-and-runners-31106.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31378
+Patch18:        0018-unify-behavior-of-refresh.patch
+Patch19:        0019-add-refresh-option-to-more-functions.patch
+Patch20:        0020-simplify-checking-the-refresh-paramater.patch
+Patch21:        0021-do-not-change-kwargs-in-refresh-while-checking-a-val.patch
+# PATCH-FIX-UPSTREAM https://github.com/saltstack/salt/pull/31429
+Patch22:        0022-fix-argument-handling-for-pkg.download.patch
+
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 BuildRequires:  logrotate
 BuildRequires:  python
@@ -123,6 +150,8 @@
 Requires:       python-tornado >= 4.2.1
 Requires:       python-yaml
 %if 0%{?suse_version}
+# required for zypper.py
+Requires:       rpm-python
 # requirements/opt.txt (not all)
 Recommends:     python-MySQL-python
 Recommends:     python-timelib
@@ -178,8 +207,8 @@
 %package api
 Summary:        The api for Salt a parallel remote execution system
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
-Requires:       %{name}-master = %{version}
+Requires:       %{name} = %{version}-%{release}
+Requires:       %{name}-master = %{version}-%{release}
 Requires:       python-CherryPy >= 3.2.2
 
 %description api
@@ -188,8 +217,8 @@
 %package cloud
 Summary:        Generic cloud provisioning tool for Saltstack
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
-Requires:       %{name}-master = %{version}
+Requires:       %{name} = %{version}-%{release}
+Requires:       %{name}-master = %{version}-%{release}
 Requires:       python-apache-libcloud
 %if 0%{?suse_version}
 Recommends:     python-botocore
@@ -214,7 +243,7 @@
 %package master
 Summary:        The management component of Saltstack both protocols zmq and 
raet supported
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 %if 0%{?suse_version}
 Recommends:     python-pygit2 >= 0.20.3
 %endif
@@ -246,7 +275,7 @@
 %package minion
 Summary:        The client component for Saltstack
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 %if %{with systemd}
 %{?systemd_requires}
 %else
@@ -265,7 +294,7 @@
 %package raet
 Summary:        Raet Support for Saltstack
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 Requires:       python-enum34
 Requires:       python-ioflo >= 1.1.7
 Requires:       python-libnacl >= 1.0.0
@@ -287,7 +316,7 @@
 %package proxy
 Summary:        Component for salt that enables controlling arbitrary devices
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 %if %{with systemd}
 %{?systemd_requires}
 %else
@@ -310,8 +339,8 @@
 %package syndic
 Summary:        The syndic component for saltstack
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
-Requires:       %{name}-master = %{version}
+Requires:       %{name} = %{version}-%{release}
+Requires:       %{name}-master = %{version}-%{release}
 %if %{with systemd}
 %{?systemd_requires}
 %else
@@ -331,8 +360,8 @@
 %package ssh
 Summary:        Management component for Saltstack with ssh protocol
 Group:          System/Monitoring
-Requires:       %{name} = %{version}
-Requires:       %{name}-master = %{version}
+Requires:       %{name} = %{version}-%{release}
+Requires:       %{name}-master = %{version}-%{release}
 %if 0%{?suse_version}
 Recommends:     sshpass
 %endif
@@ -355,7 +384,7 @@
 %package bash-completion
 Summary:        Bash Completion for %{name}
 Group:          System/Management
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 Requires:       bash-completion
 %if 0%{?suse_version} > 1110
 BuildArch:      noarch
@@ -370,7 +399,7 @@
 %package fish-completion
 Summary:        Fish Completion for %{name}
 Group:          System/Management
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 
 %if 0%{?suse_version} > 1110
 BuildArch:      noarch
@@ -384,7 +413,7 @@
 %package zsh-completion
 Summary:        Zsh Completion for %{name}
 Group:          System/Management
-Requires:       %{name} = %{version}
+Requires:       %{name} = %{version}-%{release}
 Requires:       zsh
 %if 0%{?suse_version} > 1110
 BuildArch:      noarch
@@ -405,6 +434,21 @@
 %patch5 -p1
 %patch6 -p1
 %patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
+%patch22 -p1
 
 %build
 python setup.py --salt-transport=both build

++++++ 0001-tserong-suse.com-We-don-t-have-python-systemd-so-not.patch ++++++
>From f6534519ed6dcd443e9b5b8f7dc6dfe1fb508ab3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= <[email protected]>
Date: Wed, 20 Jan 2016 11:00:15 +0100
Subject: [PATCH 01/22] [email protected] -- We don't have python-systemd, so
 notify can't work

---
 pkg/salt-master.service | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/pkg/salt-master.service b/pkg/salt-master.service
index 0eadf88..2b0f326 100644
--- a/pkg/salt-master.service
+++ b/pkg/salt-master.service
@@ -4,8 +4,7 @@ After=network.target
 
 [Service]
 LimitNOFILE=16384
-Type=notify
-NotifyAccess=all
+Type=simple
 ExecStart=/usr/bin/salt-master
 KillMode=process
 
-- 
2.1.4

++++++ 0002-Run-salt-master-as-dedicated-salt-user.patch ++++++
>From cd60b85c9e6bfd8ebf3505e5ff05e7fdec6211d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= <[email protected]>
Date: Wed, 20 Jan 2016 11:01:06 +0100
Subject: [PATCH 02/22] Run salt master as dedicated salt user

---
 conf/master               | 3 ++-
 pkg/salt-common.logrotate | 3 +++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/conf/master b/conf/master
index 643b5f4..36657e8 100644
--- a/conf/master
+++ b/conf/master
@@ -25,7 +25,8 @@
 # permissions to allow the specified user to run the master. The exception is
 # the job cache, which must be deleted if this user is changed. If the
 # modified files cause conflicts, set verify_env to False.
-#user: root
+user: salt
+syndic_user: salt
 
 # The port used by the communication interface. The ret (return) port is the
 # interface used for the file server, authentication, job returns, etc.
diff --git a/pkg/salt-common.logrotate b/pkg/salt-common.logrotate
index 3cd0023..8d970c0 100644
--- a/pkg/salt-common.logrotate
+++ b/pkg/salt-common.logrotate
@@ -1,4 +1,5 @@
 /var/log/salt/master {
+       su salt salt
        weekly
        missingok
        rotate 7
@@ -7,6 +8,7 @@
 }
 
 /var/log/salt/minion {
+       su salt salt
        weekly
        missingok
        rotate 7
@@ -15,6 +17,7 @@
 }
 
 /var/log/salt/key {
+       su salt salt
        weekly
        missingok
        rotate 7
-- 
2.1.4

++++++ 0003-Check-if-byte-strings-are-properly-encoded-in-UTF-8.patch ++++++
>From 9dc25e7dfb08a7cd583215d0206f18b15a44ccb1 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <[email protected]>
Date: Mon, 18 Jan 2016 16:28:48 +0100
Subject: [PATCH 03/22] Check if byte strings are properly encoded in UTF-8

Rename keywords arguments variable to a default name.
---
 salt/modules/zypper.py | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 0d62c68..dddcc2f 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -112,9 +112,9 @@ def info_installed(*names, **kwargs):
             summary, description.
 
     :param errors:
-        Handle RPM field errors (true|false). By default, various mistakes in 
the textual fields are simply ignored and
-        omitted from the data. Otherwise a field with a mistake is not 
returned, instead a 'N/A (bad UTF-8)'
-        (not available, broken) text is returned.
+        Handle RPM field errors. If 'ignore' is chosen, then various mistakes 
are simply ignored and omitted
+        from the texts or strings. If 'report' is chonen, then a field with a 
mistake is not returned, instead
+        a 'N/A (broken)' (not available, broken) text is placed.
 
         Valid attributes are:
             ignore, report
@@ -127,7 +127,8 @@ def info_installed(*names, **kwargs):
         salt '*' pkg.info_installed <package1> <package2> <package3> ...
         salt '*' pkg.info_installed <package1> attr=version,vendor
         salt '*' pkg.info_installed <package1> <package2> <package3> ... 
attr=version,vendor
-        salt '*' pkg.info_installed <package1> <package2> <package3> ... 
attr=version,vendor errors=true
+        salt '*' pkg.info_installed <package1> <package2> <package3> ... 
attr=version,vendor errors=ignore
+        salt '*' pkg.info_installed <package1> <package2> <package3> ... 
attr=version,vendor errors=report
     '''
     ret = dict()
     for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names, **kwargs).items():
@@ -138,7 +139,7 @@ def info_installed(*names, **kwargs):
                 # Check, if string is encoded in a proper UTF-8
                 value_ = value.decode('UTF-8', 'ignore').encode('UTF-8', 
'ignore')
                 if value != value_:
-                    value = kwargs.get('errors') and value_ or 'N/A (invalid 
UTF-8)'
+                    value = kwargs.get('errors', 'ignore') == 'ignore' and 
value_ or 'N/A (invalid UTF-8)'
                     log.error('Package {0} has bad UTF-8 code in {1}: 
{2}'.format(pkg_name, key, value))
             if key == 'source_rpm':
                 t_nfo['source'] = value
-- 
2.1.4

++++++ 0004-Fix-pkg.latest-prevent-crash-on-multiple-package-ins.patch ++++++
>From e21ddab93f22d1b2e1ad94368527f41102b69f16 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <[email protected]>
Date: Fri, 22 Jan 2016 18:37:12 +0100
Subject: [PATCH 04/22] Fix pkg.latest - prevent crash on multiple package
 installation

Fix PEP8: line continuation

Replace old fashion string memcopy with the list

Fix PEP8: line continuation

Bugfix: crash on "key not found" error

Fix formatting

Check the version of the package, instead of the package name

Get version as an explicit parameter

Use regexp type for the string.

Avoid backslashes where they are not needed

Remove unnecessary complexity and string increment

Add a new line before the last return

Add error handling

Cleanup formatting

Bugfix: do not treat SLS id as a package name if an empty 'pkgs' list specified.

Put 'kwargs' on its own line according to the common pattern
---
 salt/modules/zypper.py | 43 +++++++++++++---------------------
 salt/states/pkg.py     | 62 ++++++++++++++++++++++++--------------------------
 2 files changed, 46 insertions(+), 59 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index dddcc2f..63b38af 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -598,6 +598,7 @@ def install(name=None,
             pkgs=None,
             sources=None,
             downloadonly=None,
+            version=None,
             **kwargs):
     '''
     Install the passed package(s), add refresh=True to run 'zypper refresh'
@@ -666,23 +667,20 @@ def install(name=None,
                        'new': '<new-version>'}}
     '''
     try:
-        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
-            name, pkgs, sources, **kwargs
-        )
+        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name, 
pkgs, sources, **kwargs)
     except MinionError as exc:
         raise CommandExecutionError(exc)
 
     if pkg_params is None or len(pkg_params) == 0:
         return {}
 
-    version_num = kwargs.get('version')
+    version_num = version
     if version_num:
         if pkgs is None and sources is None:
             # Allow "version" to work for single package target
             pkg_params = {name: version_num}
         else:
-            log.warning('\'version\' parameter will be ignored for multiple '
-                        'package targets')
+            log.warning("'version' parameter will be ignored for multiple 
package targets")
 
     if pkg_type == 'repository':
         targets = []
@@ -691,18 +689,13 @@ def install(name=None,
             if version_num is None:
                 targets.append(param)
             else:
-                match = re.match('^([<>])?(=)?([^<>=]+)$', version_num)
+                match = re.match(r'^([<>])?(=)?([^<>=]+)$', version_num)
                 if match:
                     gt_lt, equal, verstr = match.groups()
-                    prefix = gt_lt or ''
-                    prefix += equal or ''
-                    # If no prefix characters were supplied, use '='
-                    prefix = prefix or '='
-                    targets.append('{0}{1}{2}'.format(param, prefix, verstr))
+                    targets.append('{0}{1}{2}'.format(param, ((gt_lt or '') + 
(equal or '')) or '=', verstr))
                     log.debug(targets)
                 else:
-                    msg = ('Invalid version string {0!r} for package '
-                           '{1!r}'.format(version_num, name))
+                    msg = ('Invalid version string {0!r} for package 
{1!r}'.format(version_num, name))
                     problems.append(msg)
         if problems:
             for problem in problems:
@@ -731,19 +724,14 @@ def install(name=None,
     while targets:
         cmd = cmd_install + targets[:500]
         targets = targets[500:]
-
-        out = __salt__['cmd.run'](
-            cmd,
-            output_loglevel='trace',
-            python_shell=False
-        )
-        for line in out.splitlines():
-            match = re.match(
-                "^The selected package '([^']+)'.+has lower version",
-                line
-            )
-            if match:
-                downgrades.append(match.group(1))
+        call = __salt__['cmd.run_all'](cmd, output_loglevel='trace', 
python_shell=False)
+        if call['retcode'] != 0:
+            raise CommandExecutionError(call['stderr'])  # Fixme: This needs a 
proper report mechanism.
+        else:
+            for line in call['stdout'].splitlines():
+                match = re.match(r"^The selected package '([^']+)'.+has lower 
version", line)
+                if match:
+                    downgrades.append(match.group(1))
 
     while downgrades:
         cmd = cmd_install + ['--force'] + downgrades[:500]
@@ -752,6 +740,7 @@ def install(name=None,
         __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False)
     __context__.pop('pkg.list_pkgs', None)
     new = list_pkgs()
+
     return salt.utils.compare_dicts(old, new)
 
 
diff --git a/salt/states/pkg.py b/salt/states/pkg.py
index 65ba779..d7c4503 100644
--- a/salt/states/pkg.py
+++ b/salt/states/pkg.py
@@ -1373,8 +1373,7 @@ def latest(
     '''
     rtag = __gen_rtag()
     refresh = bool(
-        salt.utils.is_true(refresh)
-        or (os.path.isfile(rtag) and refresh is not False)
+        salt.utils.is_true(refresh) or (os.path.isfile(rtag) and refresh is 
not False)
     )
 
     if kwargs.get('sources'):
@@ -1392,7 +1391,15 @@ def latest(
                     'comment': 'Invalidly formatted "pkgs" parameter. See '
                                'minion log.'}
     else:
-        desired_pkgs = [name]
+        if isinstance(pkgs, list) and len(pkgs) == 0:
+            return {
+                'name': name,
+                'changes': {},
+                'result': True,
+                'comment': 'No packages to install provided'
+            }
+        else:
+            desired_pkgs = [name]
 
     cur = __salt__['pkg.version'](*desired_pkgs, **kwargs)
     try:
@@ -1431,33 +1438,29 @@ def latest(
                 log.error(msg)
                 problems.append(msg)
             else:
-                if salt.utils.compare_versions(ver1=cur[pkg],
-                    oper='!=',
-                    ver2=avail[pkg],
-                    cmp_func=cmp_func):
+                if salt.utils.compare_versions(ver1=cur[pkg], oper='!=', 
ver2=avail[pkg], cmp_func=cmp_func):
                     targets[pkg] = avail[pkg]
                 else:
                     if not cur[pkg] or 
__salt__['portage_config.is_changed_uses'](pkg):
                         targets[pkg] = avail[pkg]
     else:
         for pkg in desired_pkgs:
-            if not avail[pkg]:
-                if not cur[pkg]:
+            if pkg not in avail:
+                if not cur.get(pkg):
                     msg = 'No information found for \'{0}\'.'.format(pkg)
                     log.error(msg)
                     problems.append(msg)
-            elif not cur[pkg] \
-                    or salt.utils.compare_versions(ver1=cur[pkg],
-                                                   oper='<',
-                                                   ver2=avail[pkg],
-                                                   cmp_func=cmp_func):
+            elif not cur.get(pkg) \
+                    or salt.utils.compare_versions(ver1=cur[pkg], oper='<', 
ver2=avail[pkg], cmp_func=cmp_func):
                 targets[pkg] = avail[pkg]
 
     if problems:
-        return {'name': name,
-                'changes': {},
-                'result': False,
-                'comment': ' '.join(problems)}
+        return {
+            'name': name,
+            'changes': {},
+            'result': False,
+            'comment': ' '.join(problems)
+        }
 
     if targets:
         # Find up-to-date packages
@@ -1471,9 +1474,7 @@ def latest(
 
         if __opts__['test']:
             to_be_upgraded = ', '.join(sorted(targets))
-            comment = 'The following packages are set to be ' \
-                      'installed/upgraded: ' \
-                      '{0}'.format(to_be_upgraded)
+            comment = ['The following packages are set to be 
installed/upgraded: {0}'.format(to_be_upgraded)]
             if up_to_date:
                 up_to_date_nb = len(up_to_date)
                 if up_to_date_nb <= 10:
@@ -1482,19 +1483,16 @@ def latest(
                         '{0} ({1})'.format(name, cur[name])
                         for name in up_to_date_sorted
                     )
-                    comment += (
-                        ' The following packages are already '
-                        'up-to-date: {0}'
-                    ).format(up_to_date_details)
+                    comment.append('The following packages are already 
up-to-date: {0}'.format(up_to_date_details))
                 else:
-                    comment += ' {0} packages are already up-to-date'.format(
-                        up_to_date_nb
-                    )
+                    comment.append('{0} packages are already 
up-to-date'.format(up_to_date_nb))
 
-            return {'name': name,
-                    'changes': {},
-                    'result': None,
-                    'comment': comment}
+            return {
+                'name': name,
+                'changes': {},
+                'result': None,
+                'comment': ' '.join(comment)
+            }
 
         # Build updated list of pkgs to exclude non-targeted ones
         targeted_pkgs = list(targets.keys()) if pkgs else None
-- 
2.1.4

++++++ 0005-Fix-package-status-filtering-on-latest-version-and-i.patch ++++++
>From 2747b83d8009fb7386986ada1640456de2fe5304 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <[email protected]>
Date: Wed, 27 Jan 2016 12:37:06 +0100
Subject: [PATCH 05/22] Fix package status filtering on latest version and
 implement epoch support

---
 salt/modules/zypper.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 63b38af..4699904 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -245,7 +245,8 @@ def latest_version(*names, **kwargs):
     package_info = info_available(*names)
     for name in names:
         pkg_info = package_info.get(name, {})
-        if pkg_info.get('status', '').lower() in ['not installed', 
'out-of-date']:
+        status = pkg_info.get('status', '').lower()
+        if status.find('not installed') > -1 or status.find('out-of-date') > 
-1:
             ret[name] = pkg_info.get('version')
 
     # Return a string if only one package name passed
@@ -314,7 +315,7 @@ def list_pkgs(versions_as_list=False, **kwargs):
             __salt__['pkg_resource.stringify'](ret)
             return ret
 
-    cmd = ['rpm', '-qa', '--queryformat', 
'%{NAME}_|-%{VERSION}_|-%{RELEASE}\\n']
+    cmd = ['rpm', '-qa', '--queryformat', 
'%{NAME}_|-%{VERSION}_|-%{RELEASE}_|-%|EPOCH?{%{EPOCH}}:{}|\\n']
     ret = {}
     out = __salt__['cmd.run'](
         cmd,
@@ -322,7 +323,9 @@ def list_pkgs(versions_as_list=False, **kwargs):
         python_shell=False
     )
     for line in out.splitlines():
-        name, pkgver, rel = line.split('_|-')
+        name, pkgver, rel, epoch = line.split('_|-')
+        if epoch:
+            pkgver = '{0}:{1}'.format(epoch, pkgver)
         if rel:
             pkgver += '-{0}'.format(rel)
         __salt__['pkg_resource.add_pkg'](ret, name, pkgver)
-- 
2.1.4

++++++ 0006-add_key-reject_key-do-not-crash-w-Permission-denied-.patch ++++++
>From 697e42284fdd1e18fef1d1747f64cb75be1e0bef Mon Sep 17 00:00:00 2001
From: Duncan Mac-Vicar P <[email protected]>
Date: Wed, 10 Feb 2016 09:24:57 +0100
Subject: [PATCH 06/22] add_key/reject_key: do not crash w/Permission denied:
 '/var/cache/salt/master/.dfn' (#27796)

already upstream
https://github.com/saltstack/salt/pull/30998
---
 salt/crypt.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/salt/crypt.py b/salt/crypt.py
index ce27d9f..907ec0c 100644
--- a/salt/crypt.py
+++ b/salt/crypt.py
@@ -55,6 +55,9 @@ def dropfile(cachedir, user=None):
     mask = os.umask(191)
     try:
         log.info('Rotating AES key')
+        if os.path.isfile(dfn):
+            log.info('AES key rotation already requested')
+            return
 
         with salt.utils.fopen(dfn, 'wb+') as fp_:
             fp_.write('')
-- 
2.1.4

++++++ 0007-Force-kill-websocket-s-child-processes-faster-than-d.patch ++++++
>From a1782a9c76f0af20e88fa913dd2ac6dcb20c9c37 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <[email protected]>
Date: Thu, 11 Feb 2016 15:16:43 +0100
Subject: [PATCH 07/22] Force-kill websocket's child processes faster than
 default two minutes.

---
 pkg/salt-api.service | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pkg/salt-api.service b/pkg/salt-api.service
index ccf3d34..72379ba 100644
--- a/pkg/salt-api.service
+++ b/pkg/salt-api.service
@@ -6,6 +6,7 @@ After=network.target
 Type=simple
 LimitNOFILE=8192
 ExecStart=/usr/bin/salt-api
+TimeoutStopSec=3
 
 [Install]
 WantedBy=multi-user.target
-- 
2.1.4

++++++ 0008-Fix-types-in-the-output-data-and-return-just-a-list-.patch ++++++
>From 1f6af694ef7296f4a32d4adcb658f66865a4c38a Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <[email protected]>
Date: Thu, 11 Feb 2016 18:26:51 +0100
Subject: [PATCH 08/22] Fix types in the output data and return just a list of
 products

---
 salt/modules/zypper.py | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 4699904..76170e6 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -1216,14 +1216,18 @@ def list_products(all=False):
     doc = dom.parseString(__salt__['cmd.run'](("zypper -x 
products{0}".format(not all and ' -i' or '')),
                                               output_loglevel='trace'))
     for prd in 
doc.getElementsByTagName('product-list')[0].getElementsByTagName('product'):
-        p_data = dict()
-        p_nfo = dict(prd.attributes.items())
-        p_name = p_nfo.pop('name')
-        p_data[p_name] = p_nfo
-        p_data[p_name]['eol'] = 
prd.getElementsByTagName('endoflife')[0].getAttribute('text')
-        descr = 
_get_first_aggregate_text(prd.getElementsByTagName('description'))
-        p_data[p_name]['description'] = " ".join([line.strip() for line in 
descr.split(os.linesep)])
-        ret.append(p_data)
+        p_nfo = dict()
+        for k_p_nfo, v_p_nfo in prd.attributes.items():
+            p_nfo[k_p_nfo] = k_p_nfo not in ['isbase', 'installed'] and 
v_p_nfo or v_p_nfo == 'true'
+        p_nfo['eol'] = 
prd.getElementsByTagName('endoflife')[0].getAttribute('text')
+        p_nfo['eol_t'] = 
int(prd.getElementsByTagName('endoflife')[0].getAttribute('time_t'))
+        p_nfo['description'] = " ".join(
+            [line.strip() for line in _get_first_aggregate_text(
+                prd.getElementsByTagName('description')
+            ).split(os.linesep)]
+        )
+
+        ret.append(p_nfo)
 
     return ret
 
-- 
2.1.4

++++++ 0009-The-functions-in-the-state-module-that-return-a-retc.patch ++++++
>From 8d77e22c0c570a0a725216f70c41d4fe00a184ca Mon Sep 17 00:00:00 2001
From: "Gareth J. Greenaway" <[email protected]>
Date: Sat, 6 Feb 2016 15:52:17 -0800
Subject: [PATCH 09/22] The functions in the state module that return a retcode
 when something goes wrong, eg. a 1 or a 2, do not return a 0 when things go
 the way they're supposed to go.  With the recent changes to the scheduler to
 ensure that the retcode is returned this is problematic and results in
 exceptions when a state function is run from the schedule.  This simple fix
 ensures a default retcode of 0 exists, it is then override in the
 _set_retcode function if there is an issue with the run

---
 salt/modules/state.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/salt/modules/state.py b/salt/modules/state.py
index 9cb195b..27e588c 100644
--- a/salt/modules/state.py
+++ b/salt/modules/state.py
@@ -70,6 +70,10 @@ def _set_retcode(ret):
     '''
     Set the return code based on the data back from the state system
     '''
+
+    # Set default retcode to 0
+    __context__['retcode'] = 0
+
     if isinstance(ret, list):
         __context__['retcode'] = 1
         return
@@ -576,7 +580,6 @@ def highstate(test=None,
 
     serial = salt.payload.Serial(__opts__)
     cache_file = os.path.join(__opts__['cachedir'], 'highstate.p')
-
     _set_retcode(ret)
     # Work around Windows multiprocessing bug, set __opts__['test'] back to
     # value from before this function was run.
@@ -770,7 +773,6 @@ def sls(mods,
     except (IOError, OSError):
         msg = 'Unable to write to SLS cache file {0}. Check permission.'
         log.error(msg.format(cache_file))
-
     _set_retcode(ret)
     # Work around Windows multiprocessing bug, set __opts__['test'] back to
     # value from before this function was run.
@@ -876,8 +878,7 @@ def show_highstate(queue=False, **kwargs):
         ret = st_.compile_highstate()
     finally:
         st_.pop_active()
-    if isinstance(ret, list):
-        __context__['retcode'] = 1
+    _set_retcode(ret)
     return ret
 
 
-- 
2.1.4

++++++ 0010-add-handling-for-OEM-products.patch ++++++
>From a7a0b80b0ca22a0a898ac4a4f671c08337f8f996 Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Tue, 16 Feb 2016 12:56:24 +0100
Subject: [PATCH 10/22] add handling for OEM products

---
 salt/modules/zypper.py | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 76170e6..6930f1a 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -1205,6 +1205,9 @@ def list_products(all=False):
     all
         List all products available or only installed. Default is False.
 
+    Includes handling for OEM products, which read the OEM productline file
+    and overwrite the release value.
+
     CLI Examples:
 
     .. code-block:: bash
@@ -1213,6 +1216,7 @@ def list_products(all=False):
         salt '*' pkg.list_products all=True
     '''
     ret = list()
+    OEM_PATH = "/var/lib/suseRegister/OEM"
     doc = dom.parseString(__salt__['cmd.run'](("zypper -x 
products{0}".format(not all and ' -i' or '')),
                                               output_loglevel='trace'))
     for prd in 
doc.getElementsByTagName('product-list')[0].getElementsByTagName('product'):
@@ -1226,7 +1230,13 @@ def list_products(all=False):
                 prd.getElementsByTagName('description')
             ).split(os.linesep)]
         )
-
+        if 'productline' in p_nfo and p_nfo['productline']:
+            oem_file = os.path.join(OEM_PATH, p_nfo['productline'])
+            if os.path.isfile(oem_file):
+                with salt.utils.fopen(oem_file, 'r') as rfile:
+                    oem_release = rfile.readline().strip()
+                    if oem_release:
+                        p_nfo['release'] = oem_release
         ret.append(p_nfo)
 
     return ret
-- 
2.1.4

++++++ 0011-improve-doc-for-list_pkgs.patch ++++++
>From 13fd4a3becab7fd991ae2c6a8ca1c52a51048cef Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Wed, 10 Feb 2016 14:20:34 +0100
Subject: [PATCH 11/22] improve doc for list_pkgs

---
 salt/modules/zypper.py | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 6930f1a..56d9ffb 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -291,9 +291,21 @@ def version(*names, **kwargs):
 
 def list_pkgs(versions_as_list=False, **kwargs):
     '''
-    List the packages currently installed as a dict::
+    List the packages currently installed as a dict with versions
+    as a comma separated string::
 
-        {'<package_name>': '<version>'}
+        {'<package_name>': '<version>[,<version>...]'}
+
+    versions_as_list:
+        If set to true, the versions are provided as a list
+
+        {'<package_name>': ['<version>', '<version>']}
+
+    removed:
+        not supported
+
+    purge_desired:
+        not supported
 
     CLI Example:
 
-- 
2.1.4

++++++ 0012-implement-version_cmp-for-zypper.patch ++++++
>From 82a9f07f27cf95a7dcff32c8434af9b5d7cf55ad Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Wed, 10 Feb 2016 11:47:12 +0100
Subject: [PATCH 12/22] implement version_cmp for zypper

---
 salt/modules/zypper.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 56d9ffb..bd9c30a 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -11,6 +11,7 @@ import copy
 import logging
 import re
 import os
+import rpm
 
 # Import 3rd-party libs
 # pylint: disable=import-error,redefined-builtin,no-name-in-module
@@ -288,6 +289,70 @@ def version(*names, **kwargs):
     '''
     return __salt__['pkg_resource.version'](*names, **kwargs) or {}
 
+def _stringToEVR(verstring):
+    '''
+    Split the version string into epoch, version and release and
+    return this as tuple.
+
+    epoch is always not empty.
+    version and release can be an empty string if such a component
+    could not be found in the version string.
+
+    "2:1.0-1.2" => ('2', '1.0', '1.2)
+    "1.0" => ('0', '1.0', '')
+    "" => ('0', '', '')
+    '''
+    if verstring in [None, '']:
+        return ('0', '', '')
+    i = verstring.find(':')
+    if i != -1:
+        try:
+            epoch = str(long(verstring[:i]))
+        except ValueError:
+            # look, garbage in the epoch field, how fun, kill it
+            epoch = '0' # this is our fallback, deal
+    else:
+        epoch = '0'
+    j = verstring.find('-')
+    if j != -1:
+        version = verstring[i + 1:j]
+        release = verstring[j + 1:]
+    else:
+        version = verstring[i + 1:]
+        release = ''
+    return (epoch, version, release)
+
+def version_cmp(ver1, ver2):
+    '''
+    .. versionadded:: 2015.5.4
+
+    Do a cmp-style comparison on two packages. Return -1 if ver1 < ver2, 0 if
+    ver1 == ver2, and 1 if ver1 > ver2. Return None if there was a problem
+    making the comparison.
+
+    CLI Example:
+
+    .. code-block:: bash
+
+        salt '*' pkg.version_cmp '0.2-001' '0.2.0.1-002'
+    '''
+    try:
+        cmp_result = rpm.labelCompare(
+            _stringToEVR(ver1),
+            _stringToEVR(ver2)
+        )
+        if cmp_result not in (-1, 0, 1):
+            raise Exception(
+                'cmp result \'{0}\' is invalid'.format(cmp_result)
+            )
+        return cmp_result
+    except Exception as exc:
+        log.warning(
+            'Failed to compare version \'{0}\' to \'{1}\' using '
+            'rpmUtils: {2}'.format(ver1, ver2, exc)
+        )
+    return salt.utils.version_cmp(ver1, ver2)
+
 
 def list_pkgs(versions_as_list=False, **kwargs):
     '''
-- 
2.1.4

++++++ 0013-pylint-changes.patch ++++++
>From c26d1b6987a06e972749a10af1c54befae14c6e6 Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Tue, 16 Feb 2016 13:48:50 +0100
Subject: [PATCH 13/22] pylint changes

---
 salt/modules/zypper.py | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index bd9c30a..7448f8b 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -2,7 +2,7 @@
 '''
 Package support for openSUSE via the zypper package manager
 
-:depends: - ``zypp`` Python module.  Install with ``zypper install 
python-zypp``
+:depends: - ``rpm`` Python module.  Install with ``zypper install rpm-python``
 '''
 
 # Import python libs
@@ -11,10 +11,10 @@ import copy
 import logging
 import re
 import os
-import rpm
 
 # Import 3rd-party libs
 # pylint: disable=import-error,redefined-builtin,no-name-in-module
+import rpm
 import salt.ext.six as six
 from salt.ext.six.moves import configparser
 from salt.ext.six.moves.urllib.parse import urlparse as _urlparse
@@ -289,7 +289,8 @@ def version(*names, **kwargs):
     '''
     return __salt__['pkg_resource.version'](*names, **kwargs) or {}
 
-def _stringToEVR(verstring):
+
+def _string_to_evr(verstring):
     '''
     Split the version string into epoch, version and release and
     return this as tuple.
@@ -304,24 +305,25 @@ def _stringToEVR(verstring):
     '''
     if verstring in [None, '']:
         return ('0', '', '')
-    i = verstring.find(':')
-    if i != -1:
+    idx_e = verstring.find(':')
+    if idx_e != -1:
         try:
-            epoch = str(long(verstring[:i]))
+            epoch = str(int(verstring[:idx_e]))
         except ValueError:
             # look, garbage in the epoch field, how fun, kill it
-            epoch = '0' # this is our fallback, deal
+            epoch = '0'  # this is our fallback, deal
     else:
         epoch = '0'
-    j = verstring.find('-')
-    if j != -1:
-        version = verstring[i + 1:j]
-        release = verstring[j + 1:]
+    idx_r = verstring.find('-')
+    if idx_r != -1:
+        version = verstring[idx_e + 1:idx_r]
+        release = verstring[idx_r + 1:]
     else:
-        version = verstring[i + 1:]
+        version = verstring[idx_e + 1:]
         release = ''
     return (epoch, version, release)
 
+
 def version_cmp(ver1, ver2):
     '''
     .. versionadded:: 2015.5.4
@@ -338,8 +340,8 @@ def version_cmp(ver1, ver2):
     '''
     try:
         cmp_result = rpm.labelCompare(
-            _stringToEVR(ver1),
-            _stringToEVR(ver2)
+            _string_to_evr(ver1),
+            _string_to_evr(ver2)
         )
         if cmp_result not in (-1, 0, 1):
             raise Exception(
-- 
2.1.4

++++++ 0014-Check-if-rpm-python-can-be-imported.patch ++++++
>From 4accc710ab2f92118f4777d13bc585d26e8e939e Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Wed, 17 Feb 2016 08:49:15 +0100
Subject: [PATCH 14/22] Check if rpm-python can be imported

---
 salt/modules/zypper.py | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 7448f8b..d44ad6a 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -14,10 +14,15 @@ import os
 
 # Import 3rd-party libs
 # pylint: disable=import-error,redefined-builtin,no-name-in-module
-import rpm
 import salt.ext.six as six
 from salt.ext.six.moves import configparser
 from salt.ext.six.moves.urllib.parse import urlparse as _urlparse
+
+try:
+    import rpm
+    HAS_RPM = True
+except ImportError:
+    HAS_RPM = False
 # pylint: enable=import-error,redefined-builtin,no-name-in-module
 
 from xml.dom import minidom as dom
@@ -338,21 +343,22 @@ def version_cmp(ver1, ver2):
 
         salt '*' pkg.version_cmp '0.2-001' '0.2.0.1-002'
     '''
-    try:
-        cmp_result = rpm.labelCompare(
-            _string_to_evr(ver1),
-            _string_to_evr(ver2)
-        )
-        if cmp_result not in (-1, 0, 1):
-            raise Exception(
-                'cmp result \'{0}\' is invalid'.format(cmp_result)
+    if HAS_RPM:
+        try:
+            cmp_result = rpm.labelCompare(
+                _string_to_evr(ver1),
+                _string_to_evr(ver2)
+            )
+            if cmp_result not in (-1, 0, 1):
+                raise Exception(
+                    'cmp result \'{0}\' is invalid'.format(cmp_result)
+                )
+            return cmp_result
+        except Exception as exc:
+            log.warning(
+                'Failed to compare version \'{0}\' to \'{1}\' using '
+                'rpmUtils: {2}'.format(ver1, ver2, exc)
             )
-        return cmp_result
-    except Exception as exc:
-        log.warning(
-            'Failed to compare version \'{0}\' to \'{1}\' using '
-            'rpmUtils: {2}'.format(ver1, ver2, exc)
-        )
     return salt.utils.version_cmp(ver1, ver2)
 
 
-- 
2.1.4

++++++ 0015-call-zypper-with-option-non-interactive-everywhere.patch ++++++
>From 5009e290b5a318b168fd03095ced7043203fe34c Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Thu, 18 Feb 2016 10:12:55 +0100
Subject: [PATCH 15/22] call zypper with option --non-interactive everywhere

---
 salt/modules/zypper.py | 49 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index d44ad6a..cb26b51 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -56,6 +56,21 @@ def __virtual__():
     return __virtualname__
 
 
+def _zypper(as_list=False):
+    '''
+    Return zypper command with default options as a string.
+
+    CMD: zypper --non-interactive
+
+    as_list:
+        if set to True, the command and the default options
+        are returned as a list
+    '''
+    if as_list:
+        return ['zypper', '--non-interactive']
+    return "zypper --non-interactive "
+
+
 def list_upgrades(refresh=True):
     '''
     List all available package upgrades on this system
@@ -70,7 +85,7 @@ def list_upgrades(refresh=True):
         refresh_db()
     ret = {}
     call = __salt__['cmd.run_all'](
-        'zypper list-updates', output_loglevel='trace'
+        _zypper() + 'list-updates', output_loglevel='trace'
     )
     if call['retcode'] != 0:
         comment = ''
@@ -185,7 +200,7 @@ def info_available(*names, **kwargs):
 
     # Run in batches
     while batch:
-        cmd = 'zypper info -t package {0}'.format(' '.join(batch[:batch_size]))
+        cmd = '{0} info -t package {1}'.format(_zypper(), ' 
'.join(batch[:batch_size]))
         pkg_info.extend(re.split(r"Information for package*", 
__salt__['cmd.run_stdout'](cmd, output_loglevel='trace')))
         batch = batch[batch_size:]
 
@@ -494,7 +509,7 @@ def del_repo(repo):
     repos_cfg = _get_configured_repos()
     for alias in repos_cfg.sections():
         if alias == repo:
-            cmd = ('zypper -x --non-interactive rr --loose-auth --loose-query 
{0}'.format(alias))
+            cmd = ('{0} -x rr --loose-auth --loose-query 
{1}'.format(_zypper(), alias))
             doc = dom.parseString(__salt__['cmd.run'](cmd, 
output_loglevel='trace'))
             msg = doc.getElementsByTagName('message')
             if doc.getElementsByTagName('progress') and msg:
@@ -583,7 +598,7 @@ def mod_repo(repo, **kwargs):
         try:
             # Try to parse the output and find the error,
             # but this not always working (depends on Zypper version)
-            doc = dom.parseString(__salt__['cmd.run'](('zypper -x ar {0} 
\'{1}\''.format(url, repo)),
+            doc = dom.parseString(__salt__['cmd.run'](('{0} -x ar {1} 
\'{2}\''.format(_zypper(), url, repo)),
                                                       output_loglevel='trace'))
         except Exception:
             # No XML out available, but it is still unknown the state of the 
result.
@@ -629,7 +644,7 @@ def mod_repo(repo, **kwargs):
         cmd_opt.append("--name='{0}'".format(kwargs.get('humanname')))
 
     if cmd_opt:
-        __salt__['cmd.run'](('zypper -x mr {0} \'{1}\''.format(' 
'.join(cmd_opt), repo)),
+        __salt__['cmd.run'](('{0} -x mr {1} \'{2}\''.format(_zypper(), ' 
'.join(cmd_opt), repo)),
                             output_loglevel='trace')
 
     # If repo nor added neither modified, error should be thrown
@@ -652,7 +667,7 @@ def refresh_db():
 
         salt '*' pkg.refresh_db
     '''
-    cmd = 'zypper refresh'
+    cmd = _zypper() + 'refresh'
     ret = {}
     call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
     if call['retcode'] != 0:
@@ -799,7 +814,7 @@ def install(name=None,
         log.info('Targeting repo {0!r}'.format(fromrepo))
     else:
         fromrepoopt = ''
-    cmd_install = ['zypper', '--non-interactive']
+    cmd_install = _zypper(as_list=True)
     if not refresh:
         cmd_install.append('--no-refresh')
     cmd_install += ['install', '--name', '--auto-agree-with-licenses']
@@ -855,7 +870,7 @@ def upgrade(refresh=True):
     if salt.utils.is_true(refresh):
         refresh_db()
     old = list_pkgs()
-    cmd = 'zypper --non-interactive update --auto-agree-with-licenses'
+    cmd = _zypper() + 'update --auto-agree-with-licenses'
     call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
     if call['retcode'] != 0:
         ret['result'] = False
@@ -887,8 +902,8 @@ def _uninstall(action='remove', name=None, pkgs=None):
         return {}
     while targets:
         cmd = (
-            'zypper --non-interactive remove {0} {1}'
-            .format(purge_arg, ' '.join(targets[:500]))
+            '{0} remove {1} {2}'
+            .format(_zypper(), purge_arg, ' '.join(targets[:500]))
         )
         __salt__['cmd.run'](cmd, output_loglevel='trace')
         targets = targets[500:]
@@ -1003,7 +1018,7 @@ def clean_locks():
     if not os.path.exists("/etc/zypp/locks"):
         return out
 
-    doc = dom.parseString(__salt__['cmd.run']('zypper --non-interactive -x 
cl', output_loglevel='trace'))
+    doc = dom.parseString(__salt__['cmd.run'](_zypper() + '-x cl', 
output_loglevel='trace'))
     for node in doc.getElementsByTagName("message"):
         text = node.childNodes[0].nodeValue.lower()
         if text.startswith(LCK):
@@ -1041,7 +1056,7 @@ def remove_lock(packages, **kwargs):  # pylint: 
disable=unused-argument
             missing.append(pkg)
 
     if removed:
-        __salt__['cmd.run'](('zypper --non-interactive rl {0}'.format(' 
'.join(removed))),
+        __salt__['cmd.run'](('{0} rl {1}'.format(_zypper(), ' 
'.join(removed))),
                             output_loglevel='trace')
 
     return {'removed': len(removed), 'not_found': missing}
@@ -1071,7 +1086,7 @@ def add_lock(packages, **kwargs):  # pylint: 
disable=unused-argument
             added.append(pkg)
 
     if added:
-        __salt__['cmd.run'](('zypper --non-interactive al {0}'.format(' 
'.join(added))),
+        __salt__['cmd.run'](('{0} al {1}'.format(_zypper(), ' '.join(added))),
                             output_loglevel='trace')
 
     return {'added': len(added), 'packages': added}
@@ -1204,7 +1219,7 @@ def _get_patterns(installed_only=None):
     List all known patterns in repos.
     '''
     patterns = {}
-    doc = dom.parseString(__salt__['cmd.run'](('zypper --xmlout se -t 
pattern'),
+    doc = dom.parseString(__salt__['cmd.run']((_zypper() + '--xmlout se -t 
pattern'),
                                               output_loglevel='trace'))
     for element in doc.getElementsByTagName('solvable'):
         installed = element.getAttribute('status') == 'installed'
@@ -1253,7 +1268,7 @@ def search(criteria):
 
         salt '*' pkg.search <criteria>
     '''
-    doc = dom.parseString(__salt__['cmd.run'](('zypper --xmlout se 
{0}'.format(criteria)),
+    doc = dom.parseString(__salt__['cmd.run'](('{0} --xmlout se 
{1}'.format(_zypper(), criteria)),
                                               output_loglevel='trace'))
     solvables = doc.getElementsByTagName('solvable')
     if not solvables:
@@ -1302,7 +1317,7 @@ def list_products(all=False):
     '''
     ret = list()
     OEM_PATH = "/var/lib/suseRegister/OEM"
-    doc = dom.parseString(__salt__['cmd.run'](("zypper -x 
products{0}".format(not all and ' -i' or '')),
+    doc = dom.parseString(__salt__['cmd.run'](("{0} -x 
products{1}".format(_zypper(), not all and ' -i' or '')),
                                               output_loglevel='trace'))
     for prd in 
doc.getElementsByTagName('product-list')[0].getElementsByTagName('product'):
         p_nfo = dict()
@@ -1342,7 +1357,7 @@ def download(*packages):
         raise CommandExecutionError("No packages has been specified.")
 
     doc = dom.parseString(__salt__['cmd.run'](
-        ('zypper -x --non-interactive download {0}'.format(' 
'.join(packages))),
+        ('{0} -x download {1}'.format(_zypper(), ' '.join(packages))),
         output_loglevel='trace'))
     pkg_ret = {}
     for dld_result in doc.getElementsByTagName("download-result"):
-- 
2.1.4

++++++ 0016-write-a-zypper-command-builder-function.patch ++++++
>From 8d25c4c8906581fa44380f72f0f754b56f5e30c3 Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Fri, 19 Feb 2016 11:50:31 +0100
Subject: [PATCH 16/22] write a zypper command builder function

---
 salt/modules/zypper.py | 62 +++++++++++++++++++++++---------------------------
 1 file changed, 29 insertions(+), 33 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index cb26b51..f878c95 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -56,19 +56,18 @@ def __virtual__():
     return __virtualname__
 
 
-def _zypper(as_list=False):
+def _zypper(*opts):
     '''
-    Return zypper command with default options as a string.
+    Return zypper command with default options as a list.
 
-    CMD: zypper --non-interactive
+    opts
+        additional options for zypper command
 
-    as_list:
-        if set to True, the command and the default options
-        are returned as a list
     '''
-    if as_list:
-        return ['zypper', '--non-interactive']
-    return "zypper --non-interactive "
+    cmd = ['zypper', '--non-interactive']
+    cmd.extend(opts)
+
+    return cmd
 
 
 def list_upgrades(refresh=True):
@@ -85,7 +84,7 @@ def list_upgrades(refresh=True):
         refresh_db()
     ret = {}
     call = __salt__['cmd.run_all'](
-        _zypper() + 'list-updates', output_loglevel='trace'
+        _zypper('list-updates'), output_loglevel='trace'
     )
     if call['retcode'] != 0:
         comment = ''
@@ -200,7 +199,7 @@ def info_available(*names, **kwargs):
 
     # Run in batches
     while batch:
-        cmd = '{0} info -t package {1}'.format(_zypper(), ' 
'.join(batch[:batch_size]))
+        cmd = _zypper('info', '-t', 'package', *batch[:batch_size])
         pkg_info.extend(re.split(r"Information for package*", 
__salt__['cmd.run_stdout'](cmd, output_loglevel='trace')))
         batch = batch[batch_size:]
 
@@ -509,7 +508,7 @@ def del_repo(repo):
     repos_cfg = _get_configured_repos()
     for alias in repos_cfg.sections():
         if alias == repo:
-            cmd = ('{0} -x rr --loose-auth --loose-query 
{1}'.format(_zypper(), alias))
+            cmd = _zypper('-x', 'rr', '--loose-auth', '--loose-query', alias)
             doc = dom.parseString(__salt__['cmd.run'](cmd, 
output_loglevel='trace'))
             msg = doc.getElementsByTagName('message')
             if doc.getElementsByTagName('progress') and msg:
@@ -598,8 +597,8 @@ def mod_repo(repo, **kwargs):
         try:
             # Try to parse the output and find the error,
             # but this not always working (depends on Zypper version)
-            doc = dom.parseString(__salt__['cmd.run'](('{0} -x ar {1} 
\'{2}\''.format(_zypper(), url, repo)),
-                                                      output_loglevel='trace'))
+            doc = dom.parseString(__salt__['cmd.run'](
+                _zypper('-x', 'ar', url, repo), output_loglevel='trace'))
         except Exception:
             # No XML out available, but it is still unknown the state of the 
result.
             pass
@@ -644,7 +643,8 @@ def mod_repo(repo, **kwargs):
         cmd_opt.append("--name='{0}'".format(kwargs.get('humanname')))
 
     if cmd_opt:
-        __salt__['cmd.run'](('{0} -x mr {1} \'{2}\''.format(_zypper(), ' 
'.join(cmd_opt), repo)),
+        cmd_opt.append(repo)
+        __salt__['cmd.run'](_zypper('-x', 'mr', *cmd_opt),
                             output_loglevel='trace')
 
     # If repo nor added neither modified, error should be thrown
@@ -667,7 +667,7 @@ def refresh_db():
 
         salt '*' pkg.refresh_db
     '''
-    cmd = _zypper() + 'refresh'
+    cmd = _zypper('refresh')
     ret = {}
     call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
     if call['retcode'] != 0:
@@ -814,7 +814,7 @@ def install(name=None,
         log.info('Targeting repo {0!r}'.format(fromrepo))
     else:
         fromrepoopt = ''
-    cmd_install = _zypper(as_list=True)
+    cmd_install = _zypper()
     if not refresh:
         cmd_install.append('--no-refresh')
     cmd_install += ['install', '--name', '--auto-agree-with-licenses']
@@ -870,7 +870,7 @@ def upgrade(refresh=True):
     if salt.utils.is_true(refresh):
         refresh_db()
     old = list_pkgs()
-    cmd = _zypper() + 'update --auto-agree-with-licenses'
+    cmd = _zypper('update', '--auto-agree-with-licenses')
     call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
     if call['retcode'] != 0:
         ret['result'] = False
@@ -901,10 +901,7 @@ def _uninstall(action='remove', name=None, pkgs=None):
     if not targets:
         return {}
     while targets:
-        cmd = (
-            '{0} remove {1} {2}'
-            .format(_zypper(), purge_arg, ' '.join(targets[:500]))
-        )
+        cmd = _zypper('remove', purge_arg, *targets[:500])
         __salt__['cmd.run'](cmd, output_loglevel='trace')
         targets = targets[500:]
     __context__.pop('pkg.list_pkgs', None)
@@ -1018,7 +1015,7 @@ def clean_locks():
     if not os.path.exists("/etc/zypp/locks"):
         return out
 
-    doc = dom.parseString(__salt__['cmd.run'](_zypper() + '-x cl', 
output_loglevel='trace'))
+    doc = dom.parseString(__salt__['cmd.run'](_zypper('-x', 'cl'), 
output_loglevel='trace'))
     for node in doc.getElementsByTagName("message"):
         text = node.childNodes[0].nodeValue.lower()
         if text.startswith(LCK):
@@ -1056,8 +1053,7 @@ def remove_lock(packages, **kwargs):  # pylint: 
disable=unused-argument
             missing.append(pkg)
 
     if removed:
-        __salt__['cmd.run'](('{0} rl {1}'.format(_zypper(), ' 
'.join(removed))),
-                            output_loglevel='trace')
+        __salt__['cmd.run'](_zypper('rl', *removed), output_loglevel='trace')
 
     return {'removed': len(removed), 'not_found': missing}
 
@@ -1086,8 +1082,7 @@ def add_lock(packages, **kwargs):  # pylint: 
disable=unused-argument
             added.append(pkg)
 
     if added:
-        __salt__['cmd.run'](('{0} al {1}'.format(_zypper(), ' '.join(added))),
-                            output_loglevel='trace')
+        __salt__['cmd.run'](_zypper('al', *added), output_loglevel='trace')
 
     return {'added': len(added), 'packages': added}
 
@@ -1219,7 +1214,7 @@ def _get_patterns(installed_only=None):
     List all known patterns in repos.
     '''
     patterns = {}
-    doc = dom.parseString(__salt__['cmd.run']((_zypper() + '--xmlout se -t 
pattern'),
+    doc = dom.parseString(__salt__['cmd.run'](_zypper('--xmlout', 'se', '-t', 
'pattern'),
                                               output_loglevel='trace'))
     for element in doc.getElementsByTagName('solvable'):
         installed = element.getAttribute('status') == 'installed'
@@ -1268,7 +1263,7 @@ def search(criteria):
 
         salt '*' pkg.search <criteria>
     '''
-    doc = dom.parseString(__salt__['cmd.run'](('{0} --xmlout se 
{1}'.format(_zypper(), criteria)),
+    doc = dom.parseString(__salt__['cmd.run'](_zypper('--xmlout', 'se', 
criteria),
                                               output_loglevel='trace'))
     solvables = doc.getElementsByTagName('solvable')
     if not solvables:
@@ -1317,8 +1312,10 @@ def list_products(all=False):
     '''
     ret = list()
     OEM_PATH = "/var/lib/suseRegister/OEM"
-    doc = dom.parseString(__salt__['cmd.run'](("{0} -x 
products{1}".format(_zypper(), not all and ' -i' or '')),
-                                              output_loglevel='trace'))
+    cmd = _zypper('-x', 'products')
+    if not all:
+        cmd.append('-i')
+    doc = dom.parseString(__salt__['cmd.run'](cmd, output_loglevel='trace'))
     for prd in 
doc.getElementsByTagName('product-list')[0].getElementsByTagName('product'):
         p_nfo = dict()
         for k_p_nfo, v_p_nfo in prd.attributes.items():
@@ -1357,8 +1354,7 @@ def download(*packages):
         raise CommandExecutionError("No packages has been specified.")
 
     doc = dom.parseString(__salt__['cmd.run'](
-        ('{0} -x download {1}'.format(_zypper(), ' '.join(packages))),
-        output_loglevel='trace'))
+        _zypper('-x', 'download', *packages), output_loglevel='trace'))
     pkg_ret = {}
     for dld_result in doc.getElementsByTagName("download-result"):
         repo = dld_result.getElementsByTagName("repository")[0]
-- 
2.1.4

++++++ 0017-Fix-crash-with-scheduler-and-runners-31106.patch ++++++
>From 978afba658cff38ebc1d6a7aecee4813796db528 Mon Sep 17 00:00:00 2001
From: Duncan Mac-Vicar P <[email protected]>
Date: Sat, 13 Feb 2016 00:23:30 +0100
Subject: [PATCH 17/22] Fix crash with scheduler and runners (#31106)

* runner wrapper ClientFuncsDict do not provide access to 'pack' attribute
* runners do not provide retcode, therefore ignore it in the schedule if it is 
not
  provided by __context__
---
 salt/client/mixins.py  | 6 ++++++
 salt/utils/schedule.py | 5 ++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/salt/client/mixins.py b/salt/client/mixins.py
index cdb1d0c..6fa3e6f 100644
--- a/salt/client/mixins.py
+++ b/salt/client/mixins.py
@@ -53,6 +53,12 @@ class ClientFuncsDict(collections.MutableMapping):
     def __init__(self, client):
         self.client = client
 
+    def __getattr__(self, attr):
+        '''
+        Provide access eg. to 'pack'
+        '''
+        return getattr(self.client.functions, attr)
+
     def __setitem__(self, key, val):
         raise NotImplementedError()
 
diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py
index cae5fcf..5ed49f7 100644
--- a/salt/utils/schedule.py
+++ b/salt/utils/schedule.py
@@ -700,7 +700,10 @@ class Schedule(object):
                             )
                         )
 
-            ret['retcode'] = self.functions.pack['__context__']['retcode']
+            # runners do not provide retcode
+            if 'retcode' in self.functions.pack['__context__']:
+                ret['retcode'] = self.functions.pack['__context__']['retcode']
+
             ret['success'] = True
         except Exception:
             log.exception("Unhandled exception running {0}".format(ret['fun']))
-- 
2.1.4

++++++ 0018-unify-behavior-of-refresh.patch ++++++
>From 29ab56413c60c958d5d62b1acdea5a97ce80fdb9 Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Thu, 18 Feb 2016 12:30:19 +0100
Subject: [PATCH 18/22] unify behavior of refresh

---
 salt/modules/zypper.py | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index f878c95..f5b09c0 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -74,6 +74,11 @@ def list_upgrades(refresh=True):
     '''
     List all available package upgrades on this system
 
+    refresh
+        force a refresh if set to True (default).
+        If set to False it depends on zypper if a refresh is
+        executed.
+
     CLI Example:
 
     .. code-block:: bash
@@ -175,6 +180,11 @@ def info_available(*names, **kwargs):
     '''
     Return the information of the named package available for the system.
 
+    refresh
+        force a refresh if set to True (default).
+        If set to False it depends on zypper if a refresh is
+        executed or not.
+
     CLI example:
 
     .. code-block:: bash
@@ -657,7 +667,7 @@ def mod_repo(repo, **kwargs):
 
 def refresh_db():
     '''
-    Just run a ``zypper refresh``, return a dict::
+    Force a repository refresh by calling ``zypper refresh --force``, return a 
dict::
 
         {'<database name>': Bool}
 
@@ -667,7 +677,7 @@ def refresh_db():
 
         salt '*' pkg.refresh_db
     '''
-    cmd = _zypper('refresh')
+    cmd = _zypper('refresh', '--force')
     ret = {}
     call = __salt__['cmd.run_all'](cmd, output_loglevel='trace')
     if call['retcode'] != 0:
@@ -704,7 +714,7 @@ def install(name=None,
             version=None,
             **kwargs):
     '''
-    Install the passed package(s), add refresh=True to run 'zypper refresh'
+    Install the passed package(s), add refresh=True to force a 'zypper refresh'
     before package is installed.
 
     name
@@ -721,7 +731,9 @@ def install(name=None,
             salt '*' pkg.install <package name>
 
     refresh
-        Whether or not to refresh the package database before installing.
+        force a refresh if set to True.
+        If set to False (default) it depends on zypper if a refresh is
+        executed.
 
     fromrepo
         Specify a package repository to install from.
@@ -769,6 +781,9 @@ def install(name=None,
         {'<package>': {'old': '<old-version>',
                        'new': '<new-version>'}}
     '''
+    if salt.utils.is_true(refresh):
+        refresh_db()
+
     try:
         pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](name, 
pkgs, sources, **kwargs)
     except MinionError as exc:
@@ -815,8 +830,6 @@ def install(name=None,
     else:
         fromrepoopt = ''
     cmd_install = _zypper()
-    if not refresh:
-        cmd_install.append('--no-refresh')
     cmd_install += ['install', '--name', '--auto-agree-with-licenses']
     if downloadonly:
         cmd_install.append('--download-only')
@@ -851,6 +864,11 @@ def upgrade(refresh=True):
     '''
     Run a full system upgrade, a zypper upgrade
 
+    refresh
+        force a refresh if set to True (default).
+        If set to False it depends on zypper if a refresh is
+        executed.
+
     Return a dict containing the new package names and versions::
 
         {'<package>': {'old': '<old-version>',
-- 
2.1.4

++++++ 0019-add-refresh-option-to-more-functions.patch ++++++
>From 478871aebfcb2ddf1b1c2a47b4fccb820180c9ed Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Thu, 18 Feb 2016 12:39:52 +0100
Subject: [PATCH 19/22] add refresh option to more functions

---
 salt/modules/zypper.py | 40 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index f5b09c0..9afdeef 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -1245,16 +1245,24 @@ def _get_patterns(installed_only=None):
     return patterns
 
 
-def list_patterns():
+def list_patterns(refresh=False):
     '''
     List all known patterns from available repos.
 
+    refresh
+        force a refresh if set to True.
+        If set to False (default) it depends on zypper if a refresh is
+        executed.
+
     CLI Examples:
 
     .. code-block:: bash
 
         salt '*' pkg.list_patterns
     '''
+    if salt.utils.is_true(refresh):
+        refresh_db()
+
     return _get_patterns()
 
 
@@ -1271,16 +1279,24 @@ def list_installed_patterns():
     return _get_patterns(installed_only=True)
 
 
-def search(criteria):
+def search(criteria, refresh=False):
     '''
     List known packags, available to the system.
 
+    refresh
+        force a refresh if set to True.
+        If set to False (default) it depends on zypper if a refresh is
+        executed.
+
     CLI Examples:
 
     .. code-block:: bash
 
         salt '*' pkg.search <criteria>
     '''
+    if salt.utils.is_true(refresh):
+        refresh_db()
+
     doc = dom.parseString(__salt__['cmd.run'](_zypper('--xmlout', 'se', 
criteria),
                                               output_loglevel='trace'))
     solvables = doc.getElementsByTagName('solvable')
@@ -1311,13 +1327,18 @@ def _get_first_aggregate_text(node_list):
     return '\n'.join(out)
 
 
-def list_products(all=False):
+def list_products(all=False, refresh=False):
     '''
     List all available or installed SUSE products.
 
     all
         List all products available or only installed. Default is False.
 
+    refresh
+        force a refresh if set to True.
+        If set to False (default) it depends on zypper if a refresh is
+        executed.
+
     Includes handling for OEM products, which read the OEM productline file
     and overwrite the release value.
 
@@ -1328,6 +1349,9 @@ def list_products(all=False):
         salt '*' pkg.list_products
         salt '*' pkg.list_products all=True
     '''
+    if salt.utils.is_true(refresh):
+        refresh_db()
+
     ret = list()
     OEM_PATH = "/var/lib/suseRegister/OEM"
     cmd = _zypper('-x', 'products')
@@ -1357,10 +1381,15 @@ def list_products(all=False):
     return ret
 
 
-def download(*packages):
+def download(refresh=False, *packages):
     """
     Download packages to the local disk.
 
+    refresh
+        force a refresh if set to True.
+        If set to False (default) it depends on zypper if a refresh is
+        executed.
+
     CLI example:
 
     .. code-block:: bash
@@ -1371,6 +1400,9 @@ def download(*packages):
     if not packages:
         raise CommandExecutionError("No packages has been specified.")
 
+    if salt.utils.is_true(refresh):
+        refresh_db()
+
     doc = dom.parseString(__salt__['cmd.run'](
         _zypper('-x', 'download', *packages), output_loglevel='trace'))
     pkg_ret = {}
-- 
2.1.4

++++++ 0020-simplify-checking-the-refresh-paramater.patch ++++++
>From 0a09ae513698029eb1e05cd8b6e6b45d2830a0cb Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Sun, 21 Feb 2016 11:26:51 +0100
Subject: [PATCH 20/22] simplify checking the refresh paramater

---
 salt/modules/zypper.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 9afdeef..e2cd5f9 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -85,7 +85,7 @@ def list_upgrades(refresh=True):
 
         salt '*' pkg.list_upgrades
     '''
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
     ret = {}
     call = __salt__['cmd.run_all'](
@@ -200,7 +200,7 @@ def info_available(*names, **kwargs):
         names = sorted(list(set(names)))
 
     # Refresh db before extracting the latest package
-    if salt.utils.is_true(kwargs.pop('refresh', True)):
+    if kwargs.pop('refresh', True):
         refresh_db()
 
     pkg_info = []
@@ -781,7 +781,7 @@ def install(name=None,
         {'<package>': {'old': '<old-version>',
                        'new': '<new-version>'}}
     '''
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
 
     try:
@@ -885,7 +885,7 @@ def upgrade(refresh=True):
            'comment': '',
     }
 
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
     old = list_pkgs()
     cmd = _zypper('update', '--auto-agree-with-licenses')
@@ -1260,7 +1260,7 @@ def list_patterns(refresh=False):
 
         salt '*' pkg.list_patterns
     '''
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
 
     return _get_patterns()
@@ -1294,7 +1294,7 @@ def search(criteria, refresh=False):
 
         salt '*' pkg.search <criteria>
     '''
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
 
     doc = dom.parseString(__salt__['cmd.run'](_zypper('--xmlout', 'se', 
criteria),
@@ -1349,7 +1349,7 @@ def list_products(all=False, refresh=False):
         salt '*' pkg.list_products
         salt '*' pkg.list_products all=True
     '''
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
 
     ret = list()
@@ -1400,7 +1400,7 @@ def download(refresh=False, *packages):
     if not packages:
         raise CommandExecutionError("No packages has been specified.")
 
-    if salt.utils.is_true(refresh):
+    if refresh:
         refresh_db()
 
     doc = dom.parseString(__salt__['cmd.run'](
-- 
2.1.4

++++++ 0021-do-not-change-kwargs-in-refresh-while-checking-a-val.patch ++++++
>From ea6898f82ddc21c73f3ea369e6af241753a2ceda Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Mon, 22 Feb 2016 09:51:01 +0100
Subject: [PATCH 21/22] do not change kwargs in refresh while checking a value

---
 salt/modules/zypper.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index e2cd5f9..1499b27 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -200,7 +200,7 @@ def info_available(*names, **kwargs):
         names = sorted(list(set(names)))
 
     # Refresh db before extracting the latest package
-    if kwargs.pop('refresh', True):
+    if kwargs.get('refresh', True):
         refresh_db()
 
     pkg_info = []
-- 
2.1.4

++++++ 0022-fix-argument-handling-for-pkg.download.patch ++++++
>From c9bab6bb32f9ca2e65b6e0c24283146b66bf91be Mon Sep 17 00:00:00 2001
From: Michael Calmer <[email protected]>
Date: Tue, 23 Feb 2016 11:46:09 +0100
Subject: [PATCH 22/22] fix argument handling for pkg.download

---
 salt/modules/zypper.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py
index 1499b27..33e5da9 100644
--- a/salt/modules/zypper.py
+++ b/salt/modules/zypper.py
@@ -1381,7 +1381,7 @@ def list_products(all=False, refresh=False):
     return ret
 
 
-def download(refresh=False, *packages):
+def download(*packages, **kwargs):
     """
     Download packages to the local disk.
 
@@ -1397,6 +1397,7 @@ def download(refresh=False, *packages):
         salt '*' pkg.download httpd
         salt '*' pkg.download httpd postfix
     """
+    refresh = kwargs.get('refresh', False)
     if not packages:
         raise CommandExecutionError("No packages has been specified.")
 
-- 
2.1.4

++++++ salt-2015.8.3.tar.gz -> salt-2015.8.7.tar.gz ++++++
/work/SRC/openSUSE:Factory/salt/salt-2015.8.3.tar.gz 
/work/SRC/openSUSE:Factory/.salt.new/salt-2015.8.7.tar.gz differ: char 5, line 1


Reply via email to