From 86c13548fd2f96a7987b34c1cf49f2a5a3c8ac9a457e0ae0e1e8415a782a5e32 Mon Sep 17 00:00:00 2001 From: Dominique Leuenberger Date: Tue, 26 Jan 2016 09:14:44 +0000 Subject: [PATCH] Accepting request 354612 from devel:languages:python 1 OBS-URL: https://build.opensuse.org/request/show/354612 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=54 --- 0001-Add-rpm.minimal_info-fix-rpm.info.patch | 139 ------------ ...ion-returned-from-pkg.info_installed.patch | 27 --- salt-2015.8-pkg-zypper-attr-filtering.patch | 201 ++++++++++++++++++ salt-2015.8-schedule-ret.patch | 170 +++++++++++++++ salt-2015.8-zypper-info.patch | 20 ++ salt.changes | 26 +++ salt.spec | 16 +- zypper-utf-8.patch | 37 +++- 8 files changed, 456 insertions(+), 180 deletions(-) delete mode 100644 0001-Add-rpm.minimal_info-fix-rpm.info.patch delete mode 100644 0002-Reduce-information-returned-from-pkg.info_installed.patch create mode 100644 salt-2015.8-pkg-zypper-attr-filtering.patch create mode 100644 salt-2015.8-schedule-ret.patch create mode 100644 salt-2015.8-zypper-info.patch diff --git a/0001-Add-rpm.minimal_info-fix-rpm.info.patch b/0001-Add-rpm.minimal_info-fix-rpm.info.patch deleted file mode 100644 index 801ea00..0000000 --- a/0001-Add-rpm.minimal_info-fix-rpm.info.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 1832daa1d247a546069f901427995f0b9f2addf3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= -Date: Tue, 15 Dec 2015 14:36:41 +0100 -Subject: [PATCH 1/2] Add rpm.minimal_info, fix rpm.info - -rpm.info: report epoch (if present) and architecture - -add rpm.minimal_info to just report name, epoch, version, release, -architecture, and installtime ---- - salt/modules/rpm.py | 97 +++++++++++++++++++++++++++++++++++------------------ - 1 file changed, 65 insertions(+), 32 deletions(-) - -diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py -index 032f8dadc87a..9fb89c994d9b 100644 ---- a/salt/modules/rpm.py -+++ b/salt/modules/rpm.py -@@ -413,43 +413,15 @@ def _pkg_time_to_iso(pkg_time): - return datetime.datetime(ptime.tm_year, ptime.tm_mon, ptime.tm_mday, - ptime.tm_hour, ptime.tm_min, ptime.tm_sec).isoformat() + "Z" - -- --def info(*packages): -+def query_rpm(queryformat, *packages): - ''' -- Return a detailed package(s) summary information. -- If no packages specified, all packages will be returned. -- -- :param packages: -- :return: -- -- CLI example: -- -- .. code-block:: bash -- -- salt '*' lowpkg.info apache2 bash -+ Internal function for info() and minimal_info() to query rpm and parse it's output - ''' - - cmd = packages and "rpm -q {0}".format(' '.join(packages)) or "rpm -qa" - - # Locale needs to be en_US instead of C, because RPM otherwise will yank the timezone from the timestamps -- call = __salt__['cmd.run_all'](cmd + (" --queryformat 'Name: %{NAME}\n" -- "Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n" -- "Version: %{VERSION}\n" -- "Vendor: %{VENDOR}\n" -- "Release: %{RELEASE}\n" -- "Build Date: %{BUILDTIME:date}\n" -- "Install Date: %|INSTALLTIME?{%{INSTALLTIME:date}}:{(not installed)}|\n" -- "Build Host: %{BUILDHOST}\n" -- "Group: %{GROUP}\n" -- "Source RPM: %{SOURCERPM}\n" -- "Size: %{LONGSIZE}\n" -- "%|LICENSE?{License: %{LICENSE}\n}|" -- "Signature: %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n" -- "%|PACKAGER?{Packager: %{PACKAGER}\n}|" -- "%|URL?{URL: %{URL}\n}|" -- "Summary: %{SUMMARY}\n" -- "Description:\n%{DESCRIPTION}\n" -- "-----\n'"), -+ call = __salt__['cmd.run_all'](cmd + queryformat, - output_loglevel='trace', env={'LC_ALL': 'en_US', 'TZ': 'UTC'}, clean_env=True) - if call['retcode'] != 0: - comment = '' -@@ -490,8 +462,69 @@ def info(*packages): - value = _pkg_time_to_iso(value) - if key != 'description' and value: - pkg_data[key] = value -- pkg_data['description'] = os.linesep.join(descr) -+ if len(descr) > 0: -+ pkg_data['description'] = os.linesep.join(descr) - if pkg_name: - ret[pkg_name] = pkg_data - - return ret -+ -+def info(*packages): -+ ''' -+ Return a detailed package(s) summary information. -+ If no packages specified, all packages will be returned. -+ -+ :param packages: -+ :return: -+ -+ CLI example: -+ -+ .. code-block:: bash -+ -+ salt '*' lowpkg.info apache2 bash -+ ''' -+ -+ return query_rpm(" --queryformat 'Name: %{NAME}\n" -+ "Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n" -+ "%|EPOCH?{Epoch: %{EPOCH}\n}|" -+ "Version: %{VERSION}\n" -+ "Vendor: %{VENDOR}\n" -+ "Release: %{RELEASE}\n" -+ "Architecture: %{ARCH}\n" -+ "Build Date: %{BUILDTIME:date}\n" -+ "Install Date: %|INSTALLTIME?{%{INSTALLTIME:date}}:{(not installed)}|\n" -+ "Build Host: %{BUILDHOST}\n" -+ "Group: %{GROUP}\n" -+ "Source RPM: %{SOURCERPM}\n" -+ "Size: %{LONGSIZE}\n" -+ "%|LICENSE?{License: %{LICENSE}\n}|" -+ "Signature: %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n" -+ "%|PACKAGER?{Packager: %{PACKAGER}\n}|" -+ "%|URL?{URL: %{URL}\n}|" -+ "Summary: %{SUMMARY}\n" -+ "Description:\n%{DESCRIPTION}\n" -+ "-----\n'", *packages) -+ -+def minimal_info(*packages): -+ ''' -+ Return a minimal package(s) information (name, epoch, version, release, arch, installtime). -+ If no packages specified, all packages will be returned. -+ -+ :param packages: -+ :return: -+ -+ CLI example: -+ -+ .. code-block:: bash -+ -+ salt '*' lowpkg.minimal_info apache2 bash -+ ''' -+ -+ return query_rpm(" --queryformat 'Name: %{NAME}\n" -+ "%|EPOCH?{Epoch: %{EPOCH}\n}|" -+ "Version: %{VERSION}\n" -+ "Release: %{RELEASE}\n" -+ "Architecture: %{ARCH}\n" -+ "Install Date: %|INSTALLTIME?{%{INSTALLTIME:date}}:{(not installed)}|\n" -+ "-----\n'", *packages) -+ -\ No newline at end of file --- -2.6.3 - diff --git a/0002-Reduce-information-returned-from-pkg.info_installed.patch b/0002-Reduce-information-returned-from-pkg.info_installed.patch deleted file mode 100644 index 9faecfa..0000000 --- a/0002-Reduce-information-returned-from-pkg.info_installed.patch +++ /dev/null @@ -1,27 +0,0 @@ -From e6c0629e1fbbc739a856494641330a346966ccfb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= -Date: Tue, 15 Dec 2015 14:37:54 +0100 -Subject: [PATCH 2/2] Reduce information returned from pkg.info_installed - -Only report name, epoch (if set), version, release, architecture, and -installtime ---- - 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 26c0580d027e..2954e8b1f06d 100644 ---- a/salt/modules/zypper.py -+++ b/salt/modules/zypper.py -@@ -111,7 +111,7 @@ def info_installed(*names): - salt '*' pkg.info_installed ... - ''' - ret = dict() -- for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names).items(): -+ for pkg_name, pkg_nfo in __salt__['lowpkg.minimal_info'](*names).items(): - t_nfo = dict() - # Translate dpkg-specific keys to a common structure - for key, value in pkg_nfo.items(): --- -2.6.3 - diff --git a/salt-2015.8-pkg-zypper-attr-filtering.patch b/salt-2015.8-pkg-zypper-attr-filtering.patch new file mode 100644 index 0000000..be0bc80 --- /dev/null +++ b/salt-2015.8-pkg-zypper-attr-filtering.patch @@ -0,0 +1,201 @@ +diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py +index 7810e22..51c72c9 100644 +--- a/salt/modules/rpm.py ++++ b/salt/modules/rpm.py +@@ -8,7 +8,6 @@ from __future__ import absolute_import + import logging + import os + import re +-import time + import datetime + + # Import Salt libs +@@ -399,24 +398,20 @@ def diff(package, path): + return res + + +-def _pkg_time_to_iso(pkg_time): +- ''' +- Convert package time to ISO 8601. +- +- :param pkg_time: +- :return: +- ''' +- ptime = time.strptime(pkg_time, '%a %d %b %Y %H:%M:%S %p %Z') +- return datetime.datetime(ptime.tm_year, ptime.tm_mon, ptime.tm_mday, +- ptime.tm_hour, ptime.tm_min, ptime.tm_sec).isoformat() + "Z" +- +- +-def info(*packages): ++def info(*packages, **attr): + ''' + Return a detailed package(s) summary information. + If no packages specified, all packages will be returned. + + :param packages: ++ ++ :param attr: ++ Comma-separated package attributes. If no 'attr' is specified, all available attributes returned. ++ ++ Valid attributes are: ++ version, vendor, release, build_date, build_date_time_t, install_date, install_date_time_t, ++ build_host, group, source_rpm, arch, epoch, size, license, signature, packager, url, summary, description. ++ + :return: + + CLI example: +@@ -424,30 +419,59 @@ def info(*packages): + .. code-block:: bash + + salt '*' lowpkg.info apache2 bash ++ salt '*' lowpkg.info apache2 bash attr=version ++ salt '*' lowpkg.info apache2 bash attr=version,build_date_iso,size + ''' + + cmd = packages and "rpm -q {0}".format(' '.join(packages)) or "rpm -qa" + +- # Locale needs to be en_US instead of C, because RPM otherwise will yank the timezone from the timestamps +- call = __salt__['cmd.run_all'](cmd + (" --queryformat 'Name: %{NAME}\n" +- "Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\n" +- "Version: %{VERSION}\n" +- "Vendor: %{VENDOR}\n" +- "Release: %{RELEASE}\n" +- "Build Date: %{BUILDTIME:date}\n" +- "Install Date: %|INSTALLTIME?{%{INSTALLTIME:date}}:{(not installed)}|\n" +- "Build Host: %{BUILDHOST}\n" +- "Group: %{GROUP}\n" +- "Source RPM: %{SOURCERPM}\n" +- "Size: %{LONGSIZE}\n" +- "%|LICENSE?{License: %{LICENSE}\n}|" +- "Signature: %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\n" +- "%|PACKAGER?{Packager: %{PACKAGER}\n}|" +- "%|URL?{URL: %{URL}\n}|" +- "Summary: %{SUMMARY}\n" +- "Description:\n%{DESCRIPTION}\n" +- "-----\n'"), +- output_loglevel='trace', env={'LC_ALL': 'en_US', 'TZ': 'UTC'}, clean_env=True) ++ # Construct query format ++ attr_map = { ++ "name": "name: %{NAME}\\n", ++ "relocations": "relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|\\n", ++ "version": "version: %{VERSION}\\n", ++ "vendor": "vendor: %{VENDOR}\\n", ++ "release": "release: %{RELEASE}\\n", ++ "epoch": "%|EPOCH?{epoch: %{EPOCH}\\n}|", ++ "build_date_time_t": "build_date_time_t: %{BUILDTIME}\\n", ++ "build_date": "build_date: %{BUILDTIME}\\n", ++ "install_date_time_t": "install_date_time_t: %|INSTALLTIME?{%{INSTALLTIME}}:{(not installed)}|\\n", ++ "install_date": "install_date: %|INSTALLTIME?{%{INSTALLTIME}}:{(not installed)}|\\n", ++ "build_host": "build_host: %{BUILDHOST}\\n", ++ "group": "group: %{GROUP}\\n", ++ "source_rpm": "source_rpm: %{SOURCERPM}\\n", ++ "size": "size: %{LONGSIZE}\\n", ++ "arch": "arch: %{ARCH}\\n", ++ "license": "%|LICENSE?{license: %{LICENSE}\\n}|", ++ "signature": "signature: %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:" ++ "{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|\\n", ++ "packager": "%|PACKAGER?{packager: %{PACKAGER}\\n}|", ++ "url": "%|URL?{url: %{URL}\\n}|", ++ "summary": "summary: %{SUMMARY}\\n", ++ "description": "description:\\n%{DESCRIPTION}\\n", ++ } ++ ++ attr = attr.get('attr', None) and attr['attr'].split(",") or None ++ query = list() ++ if attr: ++ for attr_k in attr: ++ if attr_k in attr_map and attr_k != 'description': ++ query.append(attr_map[attr_k]) ++ if not query: ++ raise CommandExecutionError('No valid attributes found.') ++ if 'name' not in attr: ++ attr.append('name') ++ query.append(attr_map['name']) ++ else: ++ for attr_k, attr_v in attr_map.iteritems(): ++ if attr_k != 'description': ++ query.append(attr_v) ++ if attr and 'description' in attr or not attr: ++ query.append(attr_map['description']) ++ query.append("-----\\n") ++ ++ call = __salt__['cmd.run_all'](cmd + (" --queryformat '{0}'".format(''.join(query))), ++ output_loglevel='trace', env={'TZ': 'UTC'}, clean_env=True) + if call['retcode'] != 0: + comment = '' + if 'stderr' in call: +@@ -477,17 +501,31 @@ def info(*packages): + if len(line) != 2: + continue + key, value = line +- key = key.replace(' ', '_').lower() + if key == 'description': + descr_marker = True + continue + if key == 'name': + pkg_name = value ++ ++ # Convert Unix ticks into ISO time format + if key in ['build_date', 'install_date']: +- value = _pkg_time_to_iso(value) +- if key != 'description' and value: ++ try: ++ pkg_data[key] = datetime.datetime.fromtimestamp(int(value)).isoformat() + "Z" ++ except ValueError: ++ log.warning('Could not convert "{0}" into Unix time'.format(value)) ++ continue ++ ++ # Convert Unix ticks into an Integer ++ if key in ['build_date_time_t', 'install_date_time_t']: ++ try: ++ pkg_data[key] = int(value) ++ except ValueError: ++ log.warning('Could not convert "{0}" into Unix time'.format(value)) ++ continue ++ if key not in ['description', 'name'] and value: + pkg_data[key] = value +- pkg_data['description'] = os.linesep.join(descr) ++ if attr and 'description' in attr or not attr: ++ pkg_data['description'] = os.linesep.join(descr) + if pkg_name: + ret[pkg_name] = pkg_data + +diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py +index 84b5d51..ccba713 100644 +--- a/salt/modules/zypper.py ++++ b/salt/modules/zypper.py +@@ -96,19 +96,32 @@ def list_upgrades(refresh=True): + list_updates = salt.utils.alias_function(list_upgrades, 'list_updates') + + +-def info_installed(*names): ++def info_installed(*names, **attr): + ''' + Return the information of the named package(s), installed on the system. + ++ :param names: ++ Names of the packages to get information about. ++ ++ :param attr: ++ Comma-separated package attributes. If no 'attr' is specified, all available attributes returned. ++ ++ Valid attributes are: ++ version, vendor, release, build_date, build_date_time_t, install_date, install_date_time_t, ++ build_host, group, source_rpm, arch, epoch, size, license, signature, packager, url, ++ summary, description. ++ + CLI example: + + .. code-block:: bash + + salt '*' pkg.info_installed + salt '*' pkg.info_installed ... ++ salt '*' pkg.info_installed attr=version,vendor ++ salt '*' pkg.info_installed ... attr=version,vendor + ''' + ret = dict() +- for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names).items(): ++ for pkg_name, pkg_nfo in __salt__['lowpkg.info'](*names, **attr).items(): + t_nfo = dict() + # Translate dpkg-specific keys to a common structure + for key, value in pkg_nfo.items(): diff --git a/salt-2015.8-schedule-ret.patch b/salt-2015.8-schedule-ret.patch new file mode 100644 index 0000000..4869297 --- /dev/null +++ b/salt-2015.8-schedule-ret.patch @@ -0,0 +1,170 @@ +diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py +index 4458202..cae5fcf 100644 +--- a/salt/utils/schedule.py ++++ b/salt/utils/schedule.py +@@ -482,24 +482,24 @@ class Schedule(object): + func = None + if func not in self.functions: + log.info( +- 'Invalid function: {0} in job {1}. Ignoring.'.format( ++ 'Invalid function: {0} in scheduled job {1}.'.format( + func, name + ) + ) ++ ++ if 'name' not in data: ++ data['name'] = name ++ log.info( ++ 'Running Job: {0}.'.format(name) ++ ) ++ if self.opts.get('multiprocessing', True): ++ thread_cls = multiprocessing.Process + else: +- if 'name' not in data: +- data['name'] = name +- log.info( +- 'Running Job: {0}.'.format(name) +- ) +- if self.opts.get('multiprocessing', True): +- thread_cls = multiprocessing.Process +- else: +- thread_cls = threading.Thread +- proc = thread_cls(target=self.handle_func, args=(func, data)) +- proc.start() +- if self.opts.get('multiprocessing', True): +- proc.join() ++ thread_cls = threading.Thread ++ proc = thread_cls(target=self.handle_func, args=(func, data)) ++ proc.start() ++ if self.opts.get('multiprocessing', True): ++ proc.join() + + def enable_schedule(self): + ''' +@@ -642,33 +642,39 @@ class Schedule(object): + except OSError: + log.info('Unable to remove file: {0}.'.format(fn_)) + +- salt.utils.daemonize_if(self.opts) ++ try: ++ salt.utils.daemonize_if(self.opts) + +- ret['pid'] = os.getpid() ++ ret['pid'] = os.getpid() + +- if 'jid_include' not in data or data['jid_include']: +- log.debug('schedule.handle_func: adding this job to the jobcache ' +- 'with data {0}'.format(ret)) +- # write this to /var/cache/salt/minion/proc +- with salt.utils.fopen(proc_fn, 'w+b') as fp_: +- fp_.write(salt.payload.Serial(self.opts).dumps(ret)) +- +- args = tuple() +- if 'args' in data: +- args = data['args'] +- +- kwargs = {} +- if 'kwargs' in data: +- kwargs = data['kwargs'] +- # if the func support **kwargs, lets pack in the pub data we have +- # TODO: pack the *same* pub data as a minion? +- argspec = salt.utils.args.get_function_argspec(self.functions[func]) +- if argspec.keywords: +- # this function accepts **kwargs, pack in the publish data +- for key, val in six.iteritems(ret): +- kwargs['__pub_{0}'.format(key)] = val ++ if 'jid_include' not in data or data['jid_include']: ++ log.debug('schedule.handle_func: adding this job to the jobcache ' ++ 'with data {0}'.format(ret)) ++ # write this to /var/cache/salt/minion/proc ++ with salt.utils.fopen(proc_fn, 'w+b') as fp_: ++ fp_.write(salt.payload.Serial(self.opts).dumps(ret)) ++ ++ args = tuple() ++ if 'args' in data: ++ args = data['args'] ++ ++ kwargs = {} ++ if 'kwargs' in data: ++ kwargs = data['kwargs'] ++ ++ if func not in self.functions: ++ ret['return'] = self.functions.missing_fun_string(func) ++ salt.utils.error.raise_error( ++ message=self.functions.missing_fun_string(func)) ++ ++ # if the func support **kwargs, lets pack in the pub data we have ++ # TODO: pack the *same* pub data as a minion? ++ argspec = salt.utils.args.get_function_argspec(self.functions[func]) ++ if argspec.keywords: ++ # this function accepts **kwargs, pack in the publish data ++ for key, val in six.iteritems(ret): ++ kwargs['__pub_{0}'.format(key)] = val + +- try: + ret['return'] = self.functions[func](*args, **kwargs) + + data_returner = data.get('returner', None) +@@ -694,28 +700,34 @@ class Schedule(object): + ) + ) + +- # Only attempt to return data to the master +- # if the scheduled job is running on a minion. +- if '__role' in self.opts and self.opts['__role'] == 'minion': +- if 'return_job' in data and not data['return_job']: +- pass +- else: +- # Send back to master so the job is included in the job list +- mret = ret.copy() +- mret['jid'] = 'req' +- channel = salt.transport.Channel.factory(self.opts, usage='salt_schedule') +- load = {'cmd': '_return', 'id': self.opts['id']} +- for key, value in six.iteritems(mret): +- load[key] = value +- channel.send(load) +- ++ ret['retcode'] = self.functions.pack['__context__']['retcode'] ++ ret['success'] = True + except Exception: + log.exception("Unhandled exception running {0}".format(ret['fun'])) + # Although catch-all exception handlers are bad, the exception here + # is to let the exception bubble up to the top of the thread context, + # where the thread will die silently, which is worse. ++ if 'return' not in ret: ++ ret['return'] = "Unhandled exception running {0}".format(ret['fun']) ++ ret['success'] = False ++ ret['retcode'] = 254 + finally: + try: ++ # Only attempt to return data to the master ++ # if the scheduled job is running on a minion. ++ if '__role' in self.opts and self.opts['__role'] == 'minion': ++ if 'return_job' in data and not data['return_job']: ++ pass ++ else: ++ # Send back to master so the job is included in the job list ++ mret = ret.copy() ++ mret['jid'] = 'req' ++ channel = salt.transport.Channel.factory(self.opts, usage='salt_schedule') ++ load = {'cmd': '_return', 'id': self.opts['id']} ++ for key, value in six.iteritems(mret): ++ load[key] = value ++ channel.send(load) ++ + log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) + os.unlink(proc_fn) + except OSError as exc: +@@ -757,11 +769,10 @@ class Schedule(object): + func = None + if func not in self.functions: + log.info( +- 'Invalid function: {0} in job {1}. Ignoring.'.format( ++ 'Invalid function: {0} in scheduled job {1}.'.format( + func, job + ) + ) +- continue + if 'name' not in data: + data['name'] = job + # Add up how many seconds between now and then diff --git a/salt-2015.8-zypper-info.patch b/salt-2015.8-zypper-info.patch new file mode 100644 index 0000000..ff2b655 --- /dev/null +++ b/salt-2015.8-zypper-info.patch @@ -0,0 +1,20 @@ +diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py +index ccba713..9d654a2 100644 +--- a/salt/modules/zypper.py ++++ b/salt/modules/zypper.py +@@ -164,12 +164,14 @@ def info_available(*names, **kwargs): + # Run in batches + while batch: + cmd = 'zypper info -t package {0}'.format(' '.join(batch[:batch_size])) +- pkg_info.extend(re.split(r"----*", __salt__['cmd.run_stdout'](cmd, output_loglevel='trace'))) ++ pkg_info.extend(re.split(r"Information for package*", __salt__['cmd.run_stdout'](cmd, output_loglevel='trace'))) + batch = batch[batch_size:] + + for pkg_data in pkg_info: + nfo = {} + for line in [data for data in pkg_data.split("\n") if ":" in data]: ++ if line.startswith("-----"): ++ continue + kw = [data.strip() for data in line.split(":", 1)] + if len(kw) == 2 and kw[1]: + nfo[kw[0].lower()] = kw[1] diff --git a/salt.changes b/salt.changes index 415e11e..4aaac86 100644 --- a/salt.changes +++ b/salt.changes @@ -1,3 +1,29 @@ +------------------------------------------------------------------- +Fri Jan 15 13:16:46 UTC 2016 - dmacvicar@suse.de + +- Fix zypper module info_available on SLE-11 + * add salt-2015.8-zypper-info.patch + * https://github.com/saltstack/salt/pull/30384 +- zypper/pkg: add package attributes filtering + * add salt-2015.8-pkg-zypper-attr-filtering.patch + * https://github.com/saltstack/salt/pull/30267 +- Remove obsoleted patches and fixes: + * 0001-Add-rpm.minimal_info-fix-rpm.info.patch + * 0002-Reduce-information-returned-from-pkg.info_installed.patch + * Remove require on glibc-locale (bsc#959572) + +------------------------------------------------------------------- +Wed Jan 13 12:03:06 UTC 2016 - dmacvicar@suse.de + +- Add missing return data to scheduled jobs + * add salt-2015.8-schedule-ret.patch for + * https://github.com/saltstack/salt/pull/30246 + +------------------------------------------------------------------- +Mon Dec 21 14:06:27 UTC 2015 - kkaempf@suse.com + +- Update zypper-utf-8.patch for Python 2.6 + ------------------------------------------------------------------- Thu Dec 17 15:53:47 UTC 2015 - kkaempf@suse.com diff --git a/salt.spec b/salt.spec index 9e5c094..26f3fe7 100644 --- a/salt.spec +++ b/salt.spec @@ -1,7 +1,7 @@ # # spec file for package salt # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -53,11 +53,12 @@ Patch2: use-salt-user-for-master.patch Patch3: 1efe484309a5c776974e723f3da0f5181f4bdb86.patch # PATCH-FIX-OPENSUSE detect bad UTF-8 in package header, bsc#958350 Patch4: zypper-utf-8.patch -# PATCH-FIX-OPENSUSE report epoch and architecture -Patch5: 0001-Add-rpm.minimal_info-fix-rpm.info.patch -# PATCH-FIX-OPENSUSE use minimal_info for pkg.info_installed -Patch6: 0002-Reduce-information-returned-from-pkg.info_installed.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 BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: logrotate BuildRequires: python @@ -105,8 +106,6 @@ Requires(pre): %{_sbindir}/useradd %if 0%{?suse_version} Requires(pre): %fillup_prereq Requires(pre): pwdutils -# bsc#959572 -Requires: glibc-locale %endif Requires: logrotate Requires: python @@ -405,6 +404,7 @@ cp %{S:1} . %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 %build python setup.py --salt-transport=both build diff --git a/zypper-utf-8.patch b/zypper-utf-8.patch index ffb0bcc..ebc20fb 100644 --- a/zypper-utf-8.patch +++ b/zypper-utf-8.patch @@ -1,15 +1,40 @@ -diff -wruN -x '*~' -x '*.o' -x '*.a' -x '*.so' -x '*.so.[0-9]' -x autom4te.cache -x .deps -x .libs ../orig-salt-2015.8.3/salt/modules/zypper.py ./salt/modules/zypper.py ---- ../orig-salt-2015.8.3/salt/modules/zypper.py 2015-12-01 22:25:13.000000000 +0100 -+++ ./salt/modules/zypper.py 2015-12-09 09:15:41.157266587 +0100 -@@ -112,6 +112,11 @@ +From 8fcc530f0473e9fcd5a7099617516a6d184b5303 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= +Date: Thu, 10 Dec 2015 13:21:41 +0100 +Subject: [PATCH] zypper: check package header content for valid utf-8 + +"salt 'system.domain.tld' pkg.info_installed --out json" can crash with + + [ERROR ] An un-handled exception was caught by salt's global exception handler: + UnicodeDecodeError: 'utf8' codec can't decode byte ... + +if a package name, summary, or description contains invalid UTF-8. + +This patch detects such rpm header values, logs them as errors, and +replaces them with "*** Bad UTF-8 ***". + +Update: drop the 'errors=' named parameter from the encode() call as it +is incompatible with Python 2.6 as used in SLE 11. +--- + salt/modules/zypper.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py +index be28311ae1bd..483d63e08edc 100644 +--- a/salt/modules/zypper.py ++++ b/salt/modules/zypper.py +@@ -115,6 +115,11 @@ def info_installed(*names): t_nfo = dict() # Translate dpkg-specific keys to a common structure for key, value in pkg_nfo.items(): + try: -+ value = value.encode('UTF-8', errors='replace') ++ value = value.encode('UTF-8', 'replace') + except(UnicodeDecodeError): -+ log.error('Package ' + pkg_name + ' has bad UTF-8 code in ' + key + ': ' + value) ++ log.error('Package {0} has bad UTF-8 code in {1}: {2}'.format(pkg_name, key, value)) + value = '*** Bad UTF-8 ***' if key == 'source_rpm': t_nfo['source'] = value else: +-- +2.6.3 +