From 1a0457af51769b4e3f6132dd8bba36eec4546587 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Wed, 2 Aug 2017 10:30:29 -0600 Subject: [PATCH 01/17] allow adding extra remotes to a repository --- salt/states/git.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/salt/states/git.py b/salt/states/git.py index 274662e83b..caf75399de 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -1154,13 +1154,22 @@ def latest(name, password=password, https_user=https_user, https_pass=https_pass) - comments.append( - 'Remote \'{0}\' changed from {1} to {2}'.format( - remote, - salt.utils.url.redact_http_basic_auth(fetch_url), - redacted_fetch_url + if fetch_url is None: + comments.append( + 'Remote \'{0}\' set to {1}'.format( + remote, + redacted_fetch_url + ) + ) + ret['changes']['new'] = name + ' => ' + remote + else: + comments.append( + 'Remote \'{0}\' changed from {1} to {2}'.format( + remote, + salt.utils.url.redact_http_basic_auth(fetch_url), + redacted_fetch_url + ) ) - ) if remote_rev is not None: if __opts__['test']: From f3dcfca4e0f4937b066767321bdcb30e80aa515d Mon Sep 17 00:00:00 2001 From: Adam Mendlik Date: Fri, 4 Aug 2017 09:09:15 -0600 Subject: [PATCH 02/17] Fix infinite loops on failed Windows deployments --- salt/utils/cloud.py | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py index e8a98ee9c3..25817b26d7 100644 --- a/salt/utils/cloud.py +++ b/salt/utils/cloud.py @@ -806,21 +806,21 @@ def wait_for_winexesvc(host, port, username, password, timeout=900): log.debug('winexe connected...') return True log.debug('Return code was {0}'.format(ret_code)) - time.sleep(1) except socket.error as exc: log.debug('Caught exception in wait_for_winexesvc: {0}'.format(exc)) - time.sleep(1) - if time.time() - start > timeout: - log.error('winexe connection timed out: {0}'.format(timeout)) - return False - log.debug( - 'Retrying winexe connection to host {0} on port {1} ' - '(try {2})'.format( - host, - port, - try_count - ) + + if time.time() - start > timeout: + log.error('winexe connection timed out: {0}'.format(timeout)) + return False + log.debug( + 'Retrying winexe connection to host {0} on port {1} ' + '(try {2})'.format( + host, + port, + try_count ) + ) + time.sleep(1) def wait_for_winrm(host, port, username, password, timeout=900): @@ -846,19 +846,19 @@ def wait_for_winrm(host, port, username, password, timeout=900): log.debug('WinRM session connected...') return s log.debug('Return code was {0}'.format(r.status_code)) - time.sleep(1) except WinRMTransportError as exc: log.debug('Caught exception in wait_for_winrm: {0}'.format(exc)) - if time.time() - start > timeout: - log.error('WinRM connection timed out: {0}'.format(timeout)) - return None - log.debug( - 'Retrying WinRM connection to host {0} on port {1} ' - '(try {2})'.format( - host, port, trycount - ) + + if time.time() - start > timeout: + log.error('WinRM connection timed out: {0}'.format(timeout)) + return None + log.debug( + 'Retrying WinRM connection to host {0} on port {1} ' + '(try {2})'.format( + host, port, trycount ) - time.sleep(1) + ) + time.sleep(1) def validate_windows_cred(host, From de60b77c82bfab349c4d60a561c7326f89555ff9 Mon Sep 17 00:00:00 2001 From: Seth House Date: Fri, 4 Aug 2017 12:36:06 -0600 Subject: [PATCH 03/17] Workaround Orchestrate problem that highstate outputter mutates data --- salt/client/mixins.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/client/mixins.py b/salt/client/mixins.py index 634133c352..78d0bb4bb6 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -408,8 +408,6 @@ class SyncClientMixin(object): ) data['success'] = False - namespaced_event.fire_event(data, 'ret') - if self.store_job: try: salt.utils.job.store_job( @@ -427,6 +425,9 @@ class SyncClientMixin(object): log.error('Could not store job cache info. ' 'Job details for this run may be unavailable.') + # Outputters _can_ mutate data so write to the job cache first! + namespaced_event.fire_event(data, 'ret') + # if we fired an event, make sure to delete the event object. # This will ensure that we call destroy, which will do the 0MQ linger log.info('Runner completed: {0}'.format(data['jid'])) From 90a2fb66a25fe9e39d52f63d9ba5c6df4436513d Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Mon, 7 Aug 2017 16:45:42 -0400 Subject: [PATCH 04/17] Fix typo for template_dict in http docs --- doc/topics/tutorials/http.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/topics/tutorials/http.rst b/doc/topics/tutorials/http.rst index 1eaee62071..e6b20c62a2 100644 --- a/doc/topics/tutorials/http.rst +++ b/doc/topics/tutorials/http.rst @@ -110,7 +110,7 @@ To pass through a file that contains jinja + yaml templating (the default): method='POST', data_file='/srv/salt/somefile.jinja', data_render=True, - template_data={'key1': 'value1', 'key2': 'value2'} + template_dict={'key1': 'value1', 'key2': 'value2'} ) To pass through a file that contains mako templating: @@ -123,7 +123,7 @@ To pass through a file that contains mako templating: data_file='/srv/salt/somefile.mako', data_render=True, data_renderer='mako', - template_data={'key1': 'value1', 'key2': 'value2'} + template_dict={'key1': 'value1', 'key2': 'value2'} ) Because this function uses Salt's own rendering system, any Salt renderer can @@ -140,7 +140,7 @@ However, this can be changed to ``master`` if necessary. method='POST', data_file='/srv/salt/somefile.jinja', data_render=True, - template_data={'key1': 'value1', 'key2': 'value2'}, + template_dict={'key1': 'value1', 'key2': 'value2'}, opts=__opts__ ) @@ -149,7 +149,7 @@ However, this can be changed to ``master`` if necessary. method='POST', data_file='/srv/salt/somefile.jinja', data_render=True, - template_data={'key1': 'value1', 'key2': 'value2'}, + template_dict={'key1': 'value1', 'key2': 'value2'}, node='master' ) @@ -170,11 +170,11 @@ a Python dict. header_file='/srv/salt/headers.jinja', header_render=True, header_renderer='jinja', - template_data={'key1': 'value1', 'key2': 'value2'} + template_dict={'key1': 'value1', 'key2': 'value2'} ) Because much of the data that would be templated between headers and data may be -the same, the ``template_data`` is the same for both. Correcting possible +the same, the ``template_dict`` is the same for both. Correcting possible variable name collisions is up to the user. Authentication From 695f8c1ae41cbcc6675930a379d277fb81edbeac Mon Sep 17 00:00:00 2001 From: lomeroe Date: Thu, 3 Aug 2017 12:07:49 -0500 Subject: [PATCH 05/17] fix #42600 in develop attempt to write data to regpol file even if data_to_write is empty (i.e. no policies configured) --- salt/modules/win_lgpo.py | 143 +++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index d941521dda..21f855e3c2 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -3989,78 +3989,77 @@ def _write_regpol_data(data_to_write, gpt_extension_guid: admx registry extension guid for the class ''' try: - if data_to_write: - reg_pol_header = u'\u5250\u6765\x01\x00' - if not os.path.exists(policy_file_path): - ret = __salt__['file.makedirs'](policy_file_path) - with open(policy_file_path, 'wb') as pol_file: - if not data_to_write.startswith(reg_pol_header): - pol_file.write(reg_pol_header.encode('utf-16-le')) - pol_file.write(data_to_write.encode('utf-16-le')) - try: - gpt_ini_data = '' - if os.path.exists(gpt_ini_path): - with open(gpt_ini_path, 'rb') as gpt_file: - gpt_ini_data = gpt_file.read() - if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data): - gpt_ini_data = '[General]\r\n' + gpt_ini_data - if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data): - # ensure the line contains the ADM guid - gpt_ext_loc = re.search(r'^{0}=.*\r\n'.format(re.escape(gpt_extension)), - gpt_ini_data, - re.IGNORECASE | re.MULTILINE) - gpt_ext_str = gpt_ini_data[gpt_ext_loc.start():gpt_ext_loc.end()] - if not _regexSearchRegPolData(r'{0}'.format(re.escape(gpt_extension_guid)), - gpt_ext_str): - gpt_ext_str = gpt_ext_str.split('=') - gpt_ext_str[1] = gpt_extension_guid + gpt_ext_str[1] - gpt_ext_str = '='.join(gpt_ext_str) - gpt_ini_data = gpt_ini_data[0:gpt_ext_loc.start()] + gpt_ext_str + gpt_ini_data[gpt_ext_loc.end():] - else: - general_location = re.search(r'^\[General\]\r\n', - gpt_ini_data, - re.IGNORECASE | re.MULTILINE) - gpt_ini_data = "{0}{1}={2}\r\n{3}".format( - gpt_ini_data[general_location.start():general_location.end()], - gpt_extension, gpt_extension_guid, - gpt_ini_data[general_location.end():]) - # https://technet.microsoft.com/en-us/library/cc978247.aspx - if _regexSearchRegPolData(r'Version=', gpt_ini_data): - version_loc = re.search(r'^Version=.*\r\n', - gpt_ini_data, - re.IGNORECASE | re.MULTILINE) - version_str = gpt_ini_data[version_loc.start():version_loc.end()] - version_str = version_str.split('=') - version_nums = struct.unpack('>2H', struct.pack('>I', int(version_str[1]))) - if gpt_extension.lower() == 'gPCMachineExtensionNames'.lower(): - version_nums = (version_nums[0], version_nums[1] + 1) - elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower(): - version_nums = (version_nums[0] + 1, version_nums[1]) - version_num = struct.unpack('>I', struct.pack('>2H', *version_nums))[0] - gpt_ini_data = "{0}{1}={2}\r\n{3}".format( - gpt_ini_data[0:version_loc.start()], - 'Version', version_num, - gpt_ini_data[version_loc.end():]) - else: - general_location = re.search(r'^\[General\]\r\n', - gpt_ini_data, - re.IGNORECASE | re.MULTILINE) - if gpt_extension.lower() == 'gPCMachineExtensionNames'.lower(): - version_nums = (0, 1) - elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower(): - version_nums = (1, 0) - gpt_ini_data = "{0}{1}={2}\r\n{3}".format( - gpt_ini_data[general_location.start():general_location.end()], - 'Version', - int("{0}{1}".format(str(version_nums[0]).zfill(4), str(version_nums[1]).zfill(4)), 16), - gpt_ini_data[general_location.end():]) - if gpt_ini_data: - with open(gpt_ini_path, 'wb') as gpt_file: - gpt_file.write(gpt_ini_data) - except Exception as e: - msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format( - gpt_ini_path, e) - raise CommandExecutionError(msg) + reg_pol_header = u'\u5250\u6765\x01\x00' + if not os.path.exists(policy_file_path): + ret = __salt__['file.makedirs'](policy_file_path) + with salt.utils.files.fopen(policy_file_path, 'wb') as pol_file: + if not data_to_write.startswith(reg_pol_header): + pol_file.write(reg_pol_header.encode('utf-16-le')) + pol_file.write(data_to_write.encode('utf-16-le')) + try: + gpt_ini_data = '' + if os.path.exists(gpt_ini_path): + with salt.utils.files.fopen(gpt_ini_path, 'rb') as gpt_file: + gpt_ini_data = gpt_file.read() + if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data): + gpt_ini_data = '[General]\r\n' + gpt_ini_data + if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data): + # ensure the line contains the ADM guid + gpt_ext_loc = re.search(r'^{0}=.*\r\n'.format(re.escape(gpt_extension)), + gpt_ini_data, + re.IGNORECASE | re.MULTILINE) + gpt_ext_str = gpt_ini_data[gpt_ext_loc.start():gpt_ext_loc.end()] + if not _regexSearchRegPolData(r'{0}'.format(re.escape(gpt_extension_guid)), + gpt_ext_str): + gpt_ext_str = gpt_ext_str.split('=') + gpt_ext_str[1] = gpt_extension_guid + gpt_ext_str[1] + gpt_ext_str = '='.join(gpt_ext_str) + gpt_ini_data = gpt_ini_data[0:gpt_ext_loc.start()] + gpt_ext_str + gpt_ini_data[gpt_ext_loc.end():] + else: + general_location = re.search(r'^\[General\]\r\n', + gpt_ini_data, + re.IGNORECASE | re.MULTILINE) + gpt_ini_data = "{0}{1}={2}\r\n{3}".format( + gpt_ini_data[general_location.start():general_location.end()], + gpt_extension, gpt_extension_guid, + gpt_ini_data[general_location.end():]) + # https://technet.microsoft.com/en-us/library/cc978247.aspx + if _regexSearchRegPolData(r'Version=', gpt_ini_data): + version_loc = re.search(r'^Version=.*\r\n', + gpt_ini_data, + re.IGNORECASE | re.MULTILINE) + version_str = gpt_ini_data[version_loc.start():version_loc.end()] + version_str = version_str.split('=') + version_nums = struct.unpack('>2H', struct.pack('>I', int(version_str[1]))) + if gpt_extension.lower() == 'gPCMachineExtensionNames'.lower(): + version_nums = (version_nums[0], version_nums[1] + 1) + elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower(): + version_nums = (version_nums[0] + 1, version_nums[1]) + version_num = struct.unpack('>I', struct.pack('>2H', *version_nums))[0] + gpt_ini_data = "{0}{1}={2}\r\n{3}".format( + gpt_ini_data[0:version_loc.start()], + 'Version', version_num, + gpt_ini_data[version_loc.end():]) + else: + general_location = re.search(r'^\[General\]\r\n', + gpt_ini_data, + re.IGNORECASE | re.MULTILINE) + if gpt_extension.lower() == 'gPCMachineExtensionNames'.lower(): + version_nums = (0, 1) + elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower(): + version_nums = (1, 0) + gpt_ini_data = "{0}{1}={2}\r\n{3}".format( + gpt_ini_data[general_location.start():general_location.end()], + 'Version', + int("{0}{1}".format(str(version_nums[0]).zfill(4), str(version_nums[1]).zfill(4)), 16), + gpt_ini_data[general_location.end():]) + if gpt_ini_data: + with salt.utils.files.fopen(gpt_ini_path, 'wb') as gpt_file: + gpt_file.write(gpt_ini_data) + except Exception as e: + msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format( + gpt_ini_path, e) + raise CommandExecutionError(msg) except Exception as e: msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(policy_file_path, e) raise CommandExecutionError(msg) From dbd29e4aaaef6d3ad631959f93392752dff49588 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Mon, 7 Aug 2017 14:37:10 -0600 Subject: [PATCH 06/17] only read file if it is not a string --- salt/utils/http.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/utils/http.py b/salt/utils/http.py index e34280cbfb..51d43dcfdd 100644 --- a/salt/utils/http.py +++ b/salt/utils/http.py @@ -763,7 +763,8 @@ def _render(template, render, renderer, template_dict, opts): blacklist = opts.get('renderer_blacklist') whitelist = opts.get('renderer_whitelist') ret = compile_template(template, rend, renderer, blacklist, whitelist, **template_dict) - ret = ret.read() + if salt.utils.stringio.is_readable(ret): + ret = ret.read() if str(ret).startswith('#!') and not str(ret).startswith('#!/'): ret = str(ret).split('\n', 1)[1] return ret From 5a91c1f2d1311d8d16d82f6c101a8c5829b8c088 Mon Sep 17 00:00:00 2001 From: remijouannet Date: Wed, 26 Jul 2017 01:27:38 +0200 Subject: [PATCH 07/17] update consul module following this documentation https://www.consul.io/api/acl.html --- salt/modules/consul.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/salt/modules/consul.py b/salt/modules/consul.py index 4ed96efea9..2629971a58 100644 --- a/salt/modules/consul.py +++ b/salt/modules/consul.py @@ -1972,6 +1972,8 @@ def acl_create(consul_url=None, **kwargs): Create a new ACL token. :param consul_url: The Consul server URL. + :param id: Unique identifier for the ACL to create + leave it blank to let consul server generate one :param name: Meaningful indicator of the ACL's purpose. :param type: Type is either client or management. A management token is comparable to a root user and has the @@ -2002,6 +2004,9 @@ def acl_create(consul_url=None, **kwargs): else: raise SaltInvocationError('Required argument "name" is missing.') + if 'id' in kwargs: + data['ID'] = kwargs['id'] + if 'type' in kwargs: data['Type'] = kwargs['type'] @@ -2120,7 +2125,7 @@ def acl_delete(consul_url=None, **kwargs): ret['res'] = False return ret - function = 'acl/delete/{0}'.format(kwargs['id']) + function = 'acl/destroy/{0}'.format(kwargs['id']) res = _query(consul_url=consul_url, data=data, method='PUT', From 8c8640d6b8fa39cb5c0bda1b922788d0c449af15 Mon Sep 17 00:00:00 2001 From: rallytime Date: Tue, 8 Aug 2017 14:35:53 -0400 Subject: [PATCH 08/17] Update doc references in glusterfs.volume_present The "created" option has been deprecated in favor of volume_present and the docs need to match. Fixes #42683 --- salt/states/glusterfs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/states/glusterfs.py b/salt/states/glusterfs.py index 5ee7120c5a..9116243916 100644 --- a/salt/states/glusterfs.py +++ b/salt/states/glusterfs.py @@ -121,13 +121,13 @@ def volume_present(name, bricks, stripe=False, replica=False, device_vg=False, .. code-block:: yaml myvolume: - glusterfs.created: + glusterfs.volume_present: - bricks: - host1:/srv/gluster/drive1 - host2:/srv/gluster/drive2 Replicated Volume: - glusterfs.created: + glusterfs.volume_present: - name: volume2 - bricks: - host1:/srv/gluster/drive2 From 00f93142e4ed39fc0b09a0cdef4339ac227e12aa Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 9 Aug 2017 12:24:06 -0500 Subject: [PATCH 09/17] Fix misspelling of "versions" --- salt/modules/boto_iam.py | 2 +- salt/modules/status.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/modules/boto_iam.py b/salt/modules/boto_iam.py index 2bc34168b0..e955504ade 100644 --- a/salt/modules/boto_iam.py +++ b/salt/modules/boto_iam.py @@ -1892,7 +1892,7 @@ def list_policy_versions(policy_name, return ret.get('list_policy_versions_response', {}).get('list_policy_versions_result', {}).get('versions') except boto.exception.BotoServerError as e: log.debug(e) - msg = 'Failed to list {0} policy vesions.' + msg = 'Failed to list {0} policy versions.' log.error(msg.format(policy_name)) return [] diff --git a/salt/modules/status.py b/salt/modules/status.py index 26871084f5..90c10b68b5 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -214,7 +214,7 @@ def uptime(): raise CommandExecutionError("File {ut_path} was not found.".format(ut_path=ut_path)) seconds = int(float(salt.utils.fopen(ut_path).read().split()[0])) elif salt.utils.is_sunos(): - # note: some flavors/vesions report the host uptime inside a zone + # note: some flavors/versions report the host uptime inside a zone # https://support.oracle.com/epmos/faces/BugDisplay?id=15611584 res = __salt__['cmd.run_all']('kstat -p unix:0:system_misc:boot_time') if res['retcode'] > 0: From 81fefa6e67cf598c9ca5b6b13cbdddbb2f2245d5 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 9 Aug 2017 11:59:32 -0600 Subject: [PATCH 10/17] Add ability to pass version in pkgs list --- salt/modules/win_pkg.py | 122 +++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 38 deletions(-) diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index b0d4052496..9872f9891d 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -861,56 +861,93 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): r''' Install the passed package(s) on the system using winrepo - :param name: - The name of a single package, or a comma-separated list of packages to - install. (no spaces after the commas) - :type name: str, list, or None + Args: - :param bool refresh: Boolean value representing whether or not to refresh - the winrepo db + name (str): + The name of a single package, or a comma-separated list of packages + to install. (no spaces after the commas) - :param pkgs: A list of packages to install from a software repository. - All packages listed under ``pkgs`` will be installed via a single - command. + refresh (bool): + Boolean value representing whether or not to refresh the winrepo db - :type pkgs: list or None + pkgs (list): + A list of packages to install from a software repository. All + packages listed under ``pkgs`` will be installed via a single + command. - *Keyword Arguments (kwargs)* + You can specify a version by passing the item as a dict: - :param str version: - The specific version to install. If omitted, the latest version will be - installed. If passed with multiple install, the version will apply to - all packages. Recommended for single installation only. + CLI Example: - :param str cache_file: - A single file to copy down for use with the installer. Copied to the - same location as the installer. Use this over ``cache_dir`` if there - are many files in the directory and you only need a specific file and - don't want to cache additional files that may reside in the installer - directory. Only applies to files on ``salt://`` + .. code-block:: bash - :param bool cache_dir: - True will copy the contents of the installer directory. This is useful - for installations that are not a single file. Only applies to - directories on ``salt://`` + # will install the latest version of foo and bar + salt '*' pkg.install pkgs='["foo", "bar"]' - :param str saltenv: Salt environment. Default 'base' + # will install the latest version of foo and version 1.2.3 of bar + salt '*' pkg.install pkgs='["foo", {"bar": "1.2.3"}]' - :param bool report_reboot_exit_codes: - If the installer exits with a recognized exit code indicating that - a reboot is required, the module function + Kwargs: + + version (str): + The specific version to install. If omitted, the latest version will + be installed. Recommend for use when installing a single package. + + If passed with a list of packages in the ``pkgs`` parameter, the + version will be ignored. + + CLI Example: + + .. code-block:: bash + + # Version is ignored + salt '*' pkg.install pkgs="['foo', 'bar']" version=1.2.3 + + If passed with a comma seperated list in the ``name`` parameter, the + version will apply to all packages in the list. + + CLI Example: + + .. code-block:: bash + + # Version 1.2.3 will apply to packages foo and bar + salt '*' pkg.install foo,bar version=1.2.3 + + cache_file (str): + A single file to copy down for use with the installer. Copied to the + same location as the installer. Use this over ``cache_dir`` if there + are many files in the directory and you only need a specific file + and don't want to cache additional files that may reside in the + installer directory. Only applies to files on ``salt://`` + + cache_dir (bool): + True will copy the contents of the installer directory. This is + useful for installations that are not a single file. Only applies to + directories on ``salt://`` + + extra_install_flags (str): + Additional install flags that will be appended to the + ``install_flags`` defined in the software definition file. Only + applies when single package is passed. + + saltenv (str): + Salt environment. Default 'base' + + report_reboot_exit_codes (bool): + If the installer exits with a recognized exit code indicating that + a reboot is required, the module function *win_system.set_reboot_required_witnessed* - will be called, preserving the knowledge of this event - for the remainder of the current boot session. For the time being, - 3010 is the only recognized exit code. The value of this param - defaults to True. + will be called, preserving the knowledge of this event + for the remainder of the current boot session. For the time being, + 3010 is the only recognized exit code. The value of this param + defaults to True. - .. versionadded:: 2016.11.0 + .. versionadded:: 2016.11.0 - :return: Return a dict containing the new package names and versions:: - :rtype: dict + Returns: + dict: Return a dict containing the new package names and versions: If the package is installed by ``pkg.install``: @@ -989,13 +1026,22 @@ def install(name=None, refresh=False, pkgs=None, **kwargs): # "sources" argument pkg_params = __salt__['pkg_resource.parse_targets'](name, pkgs, **kwargs)[0] + if len(pkg_params) > 1: + if kwargs.get('extra_install_flags') is not None: + log.warning('\'extra_install_flags\' argument will be ignored for ' + 'multiple package targets') + + # Windows expects an Options dictionary containing 'version' + for pkg in pkg_params: + pkg_params[pkg] = {'version': pkg_params[pkg]} + if pkg_params is None or len(pkg_params) == 0: log.error('No package definition found') return {} if not pkgs and len(pkg_params) == 1: - # Only use the 'version' param if 'name' was not specified as a - # comma-separated list + # Only use the 'version' param if a single item was passed to the 'name' + # parameter pkg_params = { name: { 'version': kwargs.get('version'), From 83b9b230cd83a044891c95df8fbc1337eb60b8f2 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 9 Aug 2017 12:05:42 -0600 Subject: [PATCH 11/17] Add winrepo to docs about supporting versions in pkgs --- salt/states/pkg.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 260aca1387..fe2a67a057 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -1073,8 +1073,11 @@ def installed( ``NOTE:`` For :mod:`apt `, :mod:`ebuild `, - :mod:`pacman `, :mod:`yumpkg `, - and :mod:`zypper `, version numbers can be specified + :mod:`pacman `, + :mod:`winrepo `, + :mod:`yumpkg `, and + :mod:`zypper `, + version numbers can be specified in the ``pkgs`` argument. For example: .. code-block:: yaml From 7de687aa5747a0cac28b58f057fe2e467cd15bc8 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 9 Aug 2017 17:49:20 -0600 Subject: [PATCH 12/17] Document requirements for win_pki --- salt/modules/win_pki.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/salt/modules/win_pki.py b/salt/modules/win_pki.py index 5b046b364a..25228cc567 100644 --- a/salt/modules/win_pki.py +++ b/salt/modules/win_pki.py @@ -1,9 +1,18 @@ # -*- coding: utf-8 -*- ''' -Microsoft certificate management via the Pki PowerShell module. +Microsoft certificate management via the PKIClient PowerShell module. +https://technet.microsoft.com/en-us/itpro/powershell/windows/pkiclient/pkiclient + +The PKI Client PowerShell module is only available on Windows 8+ and Windows +Server 2012+. +https://technet.microsoft.com/en-us/library/hh848636(v=wps.620).aspx :platform: Windows +:depends: + - PowerShell 4 + - PKIClient Module (Windows 8+ / Windows Server 2012+) + .. versionadded:: 2016.11.0 ''' # Import python libs @@ -29,11 +38,17 @@ __virtualname__ = 'win_pki' def __virtual__(): ''' - Only works on Windows systems with the PKI PowerShell module installed. + Requires Windows + Requires Windows 8+ / Windows Server 2012+ + Requires PowerShell + Requires PKIClient PowerShell module installed. ''' if not salt.utils.is_windows(): return False, 'Only available on Windows Systems' + if salt.utils.version_cmp(__grains__['osversion'], '6.2.9200') == -1: + return False, 'Only available on Windows 8+ / Windows Server 2012 +' + if not __salt__['cmd.shell_info']('powershell')['installed']: return False, 'Powershell not available' From f0a1d06b46e87fa44d8784c07348df42cc8bee00 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 9 Aug 2017 17:53:22 -0600 Subject: [PATCH 13/17] Standardize PKI Client --- salt/modules/win_pki.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/modules/win_pki.py b/salt/modules/win_pki.py index 25228cc567..ca17b6d626 100644 --- a/salt/modules/win_pki.py +++ b/salt/modules/win_pki.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ''' -Microsoft certificate management via the PKIClient PowerShell module. +Microsoft certificate management via the PKI Client PowerShell module. https://technet.microsoft.com/en-us/itpro/powershell/windows/pkiclient/pkiclient The PKI Client PowerShell module is only available on Windows 8+ and Windows @@ -11,7 +11,7 @@ https://technet.microsoft.com/en-us/library/hh848636(v=wps.620).aspx :depends: - PowerShell 4 - - PKIClient Module (Windows 8+ / Windows Server 2012+) + - PKI Client Module (Windows 8+ / Windows Server 2012+) .. versionadded:: 2016.11.0 ''' @@ -41,7 +41,7 @@ def __virtual__(): Requires Windows Requires Windows 8+ / Windows Server 2012+ Requires PowerShell - Requires PKIClient PowerShell module installed. + Requires PKI Client PowerShell module installed. ''' if not salt.utils.is_windows(): return False, 'Only available on Windows Systems' From 21934f61bbba1243d0b4120939d948f0338deb78 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Mon, 31 Jul 2017 13:25:27 -0600 Subject: [PATCH 14/17] python2- prefix for fedora 26 packages --- salt/modules/yumpkg.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 9ccd66d105..890a78fb04 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -180,7 +180,10 @@ def _check_versionlock(): Ensure that the appropriate versionlock plugin is present ''' if _yum() == 'dnf': - vl_plugin = 'python-dnf-plugins-extras-versionlock' + if int(__grains__.get('osmajorrelease')) < 26: + vl_plugin = 'python-dnf-plugins-extras-versionlock' + else: + vl_plugin = 'python2-dnf-plugins-extras-versionlock' else: vl_plugin = 'yum-versionlock' \ if __grains__.get('osmajorrelease') == '5' \ From f83b553d6e84ec87676354e280d62cb4d2b90859 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Mon, 31 Jul 2017 13:56:30 -0600 Subject: [PATCH 15/17] add py3 for versionlock --- salt/modules/yumpkg.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 890a78fb04..f4b80b10c2 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -180,7 +180,9 @@ def _check_versionlock(): Ensure that the appropriate versionlock plugin is present ''' if _yum() == 'dnf': - if int(__grains__.get('osmajorrelease')) < 26: + if six.PY3: + vl_plugin = 'python3-dnf-plugins-extras-versionlock' + elif int(__grains__.get('osmajorrelease')) < 26: vl_plugin = 'python-dnf-plugins-extras-versionlock' else: vl_plugin = 'python2-dnf-plugins-extras-versionlock' From 6ecdbcec1d14ecdbf494359243cc8948df45cd99 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Mon, 31 Jul 2017 14:15:52 -0600 Subject: [PATCH 16/17] make sure names are correct --- salt/modules/yumpkg.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index f4b80b10c2..371cea8863 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -180,12 +180,16 @@ def _check_versionlock(): Ensure that the appropriate versionlock plugin is present ''' if _yum() == 'dnf': - if six.PY3: - vl_plugin = 'python3-dnf-plugins-extras-versionlock' - elif int(__grains__.get('osmajorrelease')) < 26: - vl_plugin = 'python-dnf-plugins-extras-versionlock' + elif int(__grains__.get('osmajorrelease')) >= 26: + if six.PY3: + vl_plugin = 'python3-dnf-plugin-versionlock' + else: + vl_plugin = 'python2-dnf-plugin-versionlock' else: - vl_plugin = 'python2-dnf-plugins-extras-versionlock' + if six.PY3: + vl_plugin = 'python3-dnf-plugins-extras-versionlock' + else: + vl_plugin = 'python-dnf-plugins-extras-versionlock' else: vl_plugin = 'yum-versionlock' \ if __grains__.get('osmajorrelease') == '5' \ From a3da86eea8b4b3ef00edbbd8f5a8e1ab7cd88e28 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Tue, 1 Aug 2017 15:23:28 -0600 Subject: [PATCH 17/17] fix syntax --- salt/modules/yumpkg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 371cea8863..b0a183d70a 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -180,7 +180,7 @@ def _check_versionlock(): Ensure that the appropriate versionlock plugin is present ''' if _yum() == 'dnf': - elif int(__grains__.get('osmajorrelease')) >= 26: + if int(__grains__.get('osmajorrelease')) >= 26: if six.PY3: vl_plugin = 'python3-dnf-plugin-versionlock' else: