Merge pull request #28464 from basepi/merge-forward-2015.8

[2015.8] Merge forward from 2015.5 to 2015.8
This commit is contained in:
Colton Myers 2015-11-02 13:18:21 -07:00
commit 238411c8ce
21 changed files with 350 additions and 181 deletions

View file

@ -414,13 +414,17 @@ from the Salt Master. For example:
{% set some_data = salt.pillar.get('some_data', {'sane default': True}) %}
{# or #}
{% import_yaml 'path/to/file.yaml' as some_data %}
{# or #}
{% load_json 'path/to/file.json' as some_data %}
{% import_json 'path/to/file.json' as some_data %}
{# or #}
{% load_text 'path/to/ssh_key.pub' as ssh_pub_key %}
{% import_text 'path/to/ssh_key.pub' as ssh_pub_key %}
{# or #}

View file

@ -55,13 +55,18 @@ Silent Installer Options
========================
The installer can be run silently by providing the `/S` option at the command
line. The options `/master` and `/minion-name` allow for configuring the master
hostname and minion name, respectively. Here's an example of using the silent
installer:
line. The installer also accepts the following options for configuring the Salt
Minion silently:
- `/master=` A string value to set the IP address or host name of the master. Default value is 'salt'
- `/minion-name=` A string value to set the minion name. Default is 'hostname'
- `/start-service=` Either a 1 or 0. '1' will start the service, '0' will not. Default is to start the service after installation.
Here's an example of using the silent installer:
.. code-block:: bat
Salt-Minion-0.17.0-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname
Salt-Minion-2015.5.6-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname /start-service=0
Running the Salt Minion on Windows as an Unprivileged User

View file

@ -4,10 +4,26 @@
MinionFS Backend Walkthrough
============================
Propagating Files
=================
.. versionadded:: 2014.1.0
Sometimes, you might need to propagate files that are generated on a minion.
Salt already has a feature to send files from a minion to the master:
Sometimes, one might need to propagate files that are generated on a minion.
Salt already has a feature to send files from a minion to the master.
Enabling File Propagation
=========================
To enable propagation, the :conf_master:`file_recv` option needs to be set to ``True``.
.. code-block:: yaml
file_recv: True
These changes require a restart of the master, then new requests for the
``salt://minion-id/`` protocol will send files that are pushed by ``cp.push``
from ``minion-id`` to the master.
.. code-block:: bash
@ -24,6 +40,9 @@ This command will store the file, including its full path, under
<salt.modules.cp.push>`. To get up to speed, check out the
:doc:`walkthrough </topics/tutorials/walkthrough>`.
MinionFS Backend
================
Since it is not a good idea to expose the whole :conf_master:`cachedir`, MinionFS
should be used to send these files to other minions.
@ -136,4 +155,4 @@ Or we can use a more elegant and salty way to add an SSH key:
.. [*] Yes, that was the actual key on my server, but the server is already destroyed.
.. [*] Yes, that was the actual key on my server, but the server is already destroyed.

View file

@ -315,6 +315,19 @@ line:
the key that is passed in will overwrite the entire value of that key,
rather than merging only the specified value set via the command line.
The example below will swap the value for vim with telnet in the previously
specified list, notice the nested pillar dict:
.. code-block:: bash
salt '*' state.sls edit.vim pillar='{"pkgs": {"vim": "telnet"}}'
.. note::
This will attempt to install telnet on your minions, feel free to
uninstall the package or replace telnet value with anything else.
More On Pillar
==============

View file

@ -31,6 +31,14 @@ You can specify multiple :ref:`state-declaration` under an
Try stopping Apache before running ``state.highstate`` once again and observe
the output.
.. note::
For those running RedhatOS derivatives (Centos, AWS), you will want to specify the
service name to be httpd. More on state service here, :mod:`service state
<salt.states.service>`. With the example above, just add "- name: httpd"
above the require line and with the same spacing.
Require other states
====================

View file

@ -6,7 +6,7 @@
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
; MUI 1.67 compatible ------
!include "MUI.nsh"
!include "MUI2.nsh"
!include "nsDialogs.nsh"
!include "LogicLib.nsh"
@ -36,6 +36,7 @@ Var MasterHost
Var MasterHost_State
Var MinionName
Var MinionName_State
Var StartService
; MUI Settings
!define MUI_ABORTWARNING
@ -54,6 +55,7 @@ Page custom nsDialogsPage nsDialogsPageLeave
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!define MUI_PAGE_CUSTOMFUNCTION_SHOW FinishPage.Show
!define MUI_FINISHPAGE_RUN "$INSTDIR\nssm"
!define MUI_FINISHPAGE_RUN_PARAMETERS "start salt-minion"
!insertmacro MUI_PAGE_FINISH
@ -76,6 +78,7 @@ Page custom nsDialogsPage nsDialogsPageLeave
Function nsDialogsPage
nsDialogs::Create 1018
Pop $Dialog
@ -110,6 +113,68 @@ Function nsDialogsPageLeave
FunctionEnd
Function getMinionConfig
confFind:
IfFileExists "$INSTDIR\conf\minion" confFound confNotFound
confNotFound:
${If} $INSTDIR == "c:\salt\bin\Scripts"
StrCpy $INSTDIR "C:\salt"
goto confFind
${Else}
goto confReallyNotFound
${EndIf}
confFound:
FileOpen $0 "$INSTDIR\conf\minion" r
confLoop:
FileRead $0 $1
IfErrors EndOfFile
${StrLoc} $2 $1 "master:" ">"
${If} $2 == 0
${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0"
${Trim} $2 $2
StrCpy $MasterHost_State $2
${EndIf}
${StrLoc} $2 $1 "id:" ">"
${If} $2 == 0
${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0"
${Trim} $2 $2
StrCpy $MinionName_State $2
${EndIf}
Goto confLoop
EndOfFile:
FileClose $0
confReallyNotFound:
Push $R0
Push $R1
Push $R2
${GetParameters} $R0
${GetOptions} $R0 "/master=" $R1
${GetOptions} $R0 "/minion-name=" $R2
${IfNot} $R1 == ""
StrCpy $MasterHost_State $R1
${ElseIf} $MasterHost_State == ""
StrCpy $MasterHost_State "salt"
${EndIf}
${IfNot} $R2 == ""
StrCpy $MinionName_State $R2
${ElseIf} $MinionName_State == ""
StrCpy $MinionName_State "hostname"
${EndIf}
Pop $R2
Pop $R1
Pop $R0
FunctionEnd
Function updateMinionConfig
ClearErrors
@ -181,13 +246,54 @@ Section -Post
RMDir /R "$INSTDIR\var\cache\salt" ; removing cache from old version
Call updateMinionConfig
Call checkStartService
SectionEnd
Function FinishPage.Show
${IfNot} $StartService == 1
SendMessage $mui.FinishPage.Run ${BM_SETCHECK} ${BST_UNCHECKED} 0
${EndIf}
FunctionEnd
Function checkStartService
; Check if the start-service option was passed
Push $R0
Push $R1
${GetParameters} $R0
${GetOptions} $R0 "/start-service=" $R1
; If start-service was passed something, then set it
${IfNot} $R1 == ""
StrCpy $StartService $R1
; Otherwise default to 1
${Else}
StrCpy $StartService 1
${EndIf}
Pop $R0
Pop $R1
FunctionEnd
Function .onInstSuccess
; If the installer is running Silently, start the service
IfSilent 0 +2
Exec 'net start salt-minion'
; If the installer is running Silently, start the service
IfSilent silentOption notSilent
silentOption:
; If start-service is 1, then start the service
${If} $StartService == 1
Exec 'net start salt-minion'
${EndIf}
notSilent:
FunctionEnd
@ -233,62 +339,37 @@ Function .onInit
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
confFind:
IfFileExists "$INSTDIR\conf\minion" confFound confNotFound
Call getMinionConfig
confNotFound:
; Check for existing installation
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString"
StrCmp $R0 "" skipUninstall
; Found existing installation, prompt to uninstall
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "${PRODUCT_NAME} is already installed. $\n$\nClick `OK` to remove the existing installation." /SD IDOK IDOK uninst
Abort
uninst:
; Make sure we're in the right directory
${If} $INSTDIR == "c:\salt\bin\Scripts"
StrCpy $INSTDIR "C:\salt"
goto confFind
${Else}
goto confReallyNotFound
${EndIf}
confFound:
FileOpen $0 "$INSTDIR\conf\minion" r
; Stop and remove the salt-minion service
ExecWait "net stop salt-minion"
ExecWait "sc delete salt-minion"
confLoop:
FileRead $0 $1
IfErrors EndOfFile
${StrLoc} $2 $1 "master:" ">"
${If} $2 == 0
${StrStrAdv} $2 $1 "master: " ">" ">" "0" "0" "0"
${Trim} $2 $2
StrCpy $MasterHost_State $2
${EndIf}
; Remove salt binaries and batch files
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\nssm.exe"
Delete "$INSTDIR\salt*"
RMDir /r "$INSTDIR\bin"
${StrLoc} $2 $1 "id:" ">"
${If} $2 == 0
${StrStrAdv} $2 $1 "id: " ">" ">" "0" "0" "0"
${Trim} $2 $2
StrCpy $MinionName_State $2
${EndIf}
; Remove registry entries
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
Goto confLoop
EndOfFile:
FileClose $0
confReallyNotFound:
Push $R0
Push $R1
Push $R2
${GetParameters} $R0
${GetOptions} $R0 "/master=" $R1
${GetOptions} $R0 "/minion-name=" $R2
${IfNot} $R1 == ""
StrCpy $MasterHost_State $R1
${ElseIf} $MasterHost_State == ""
StrCpy $MasterHost_State "salt"
${EndIf}
${IfNot} $R2 == ""
StrCpy $MinionName_State $R2
${ElseIf} $MinionName_State == ""
StrCpy $MinionName_State "hostname"
${EndIf}
Pop $R2
Pop $R1
Pop $R0
skipUninstall:
FunctionEnd

View file

@ -2704,6 +2704,8 @@ def apply_minion_config(overrides=None,
if overrides:
opts.update(overrides)
opts['__cli'] = os.path.basename(sys.argv[0])
if len(opts['sock_dir']) > len(opts['cachedir']) + 10:
opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix')

View file

@ -732,6 +732,8 @@ def _virtual(osdata):
)
if product.startswith('VMware'):
grains['virtual'] = 'VMware'
if product.startswith('VirtualBox'):
grains['virtual'] = 'VirtualBox'
if maker.startswith('Xen'):
grains['virtual_subtype'] = '{0} {1}'.format(maker, product)
grains['virtual'] = 'xen'

View file

@ -879,9 +879,9 @@ def _parse_settings_bond_1(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -962,9 +962,9 @@ def _parse_settings_bond_3(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -1006,9 +1006,9 @@ def _parse_settings_bond_4(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -1049,9 +1049,9 @@ def _parse_settings_bond_5(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -1085,9 +1085,9 @@ def _parse_settings_bond_6(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)

View file

@ -51,16 +51,23 @@ def fire_master(data, tag, preload=None):
pass
return True
if preload:
if preload or __opts__.get('__cli') == 'salt-call':
# If preload is specified, we must send a raw event (this is
# slower because it has to independently authenticate)
load = preload
if 'master_uri' not in __opts__:
__opts__['master_uri'] = 'tcp://{ip}:{port}'.format(
ip=salt.utils.ip_bracket(__opts__['interface']),
port=__opts__.get('ret_port', '4506') # TODO, no fallback
)
auth = salt.crypt.SAuth(__opts__)
load.update({'id': __opts__['id'],
load = {'id': __opts__['id'],
'tag': tag,
'data': data,
'tok': auth.gen_token('salt'),
'cmd': '_minion_event'})
'cmd': '_minion_event'}
if isinstance(preload, dict):
load.update(preload)
channel = salt.transport.Channel.factory(__opts__)
try:

View file

@ -29,6 +29,7 @@ import tempfile
import time
import glob
import hashlib
import mmap
from functools import reduce # pylint: disable=redefined-builtin
from collections import Iterable, Mapping
@ -1631,7 +1632,7 @@ def replace(path,
pattern,
repl,
count=0,
flags=0,
flags=8,
bufsize=1,
append_if_not_found=False,
prepend_if_not_found=False,
@ -1665,14 +1666,14 @@ def replace(path,
A list of flags defined in the :ref:`re module documentation
<contents-of-module-re>`. Each list item should be a string that will
correlate to the human-friendly flag name. E.g., ``['IGNORECASE',
'MULTILINE']``. Note: multiline searches must specify ``file`` as the
``bufsize`` argument below.
'MULTILINE']``. Optionally, ``flags`` may be an int, with a value
corresponding to the XOR (``|``) of all the desired flags. Defaults to
8 (which supports 'MULTILINE').
bufsize (int or str)
How much of the file to buffer into memory at once. The
default value ``1`` processes one line at a time. The special value
``file`` may be specified which will read the entire file into memory
before processing. Note: multiline searches must specify ``file``
buffering.
before processing.
append_if_not_found
.. versionadded:: 2014.7.0
@ -1773,8 +1774,9 @@ def replace(path,
flags_num = _get_flags(flags)
cpattern = re.compile(str(pattern), flags_num)
filesize = os.path.getsize(path)
if bufsize == 'file':
bufsize = os.path.getsize(path)
bufsize = filesize
# Search the file; track if any changes have been made for the return val
has_changes = False
@ -1795,55 +1797,57 @@ def replace(path,
append_if_not_found) \
else repl
if search_only:
# mmap throws a ValueError if the file is empty, but if it is empty we
# should be able to skip the search anyway. NOTE: Is there a use case for
# searching an empty file with an empty pattern?
if filesize is not 0:
# First check the whole file, determine whether to make the replacement
# Searching first avoids modifying the time stamp if there are no changes
try:
# allow multiline searching
with salt.utils.filebuffer.BufferedReader(path) as breader:
for chunk in breader:
if re.search(cpattern, chunk):
return True
return False
# Use a read-only handle to open the file
with salt.utils.fopen(path,
mode='rb',
buffering=bufsize) as r_file:
r_data = mmap.mmap(r_file.fileno(),
0,
access=mmap.ACCESS_READ)
if search_only:
# Just search; bail as early as a match is found
if re.search(cpattern, r_data):
return True # `with` block handles file closure
else:
result, nrepl = re.subn(cpattern, repl, r_data, count)
# found anything? (even if no change)
if nrepl > 0:
found = True
# Identity check the potential change
has_changes = True if pattern != repl else has_changes
if prepend_if_not_found or append_if_not_found:
# Search for content, to avoid pre/appending the
# content if it was pre/appended in a previous run.
if re.search('^{0}$'.format(re.escape(content)),
r_data,
flags=flags_num):
# Content was found, so set found.
found = True
# Keep track of show_changes here, in case the file isn't
# modified
if show_changes or append_if_not_found or \
prepend_if_not_found:
orig_file = r_data.read(filesize).splitlines(True)
new_file = result.splitlines(True)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to read file '{0}'. Exception: {1}".format(path, exc)
"Unable to open file '{0}'. "
"Exception: {1}".format(path, exc)
)
# First check the whole file, determine whether to make the replacement
# Searching first avoids modifying the time stamp if there are no changes
try:
# Use a read-only handle to open the file
with salt.utils.fopen(path,
mode='r',
buffering=bufsize) as r_file:
for line in r_file:
result, nrepl = re.subn(cpattern, repl, line, count)
# found anything? (even if no change)
if nrepl > 0:
found = True
if prepend_if_not_found or append_if_not_found:
# Search for content, so we don't continue pre/appending
# the content if it's been pre/appended in a previous run.
if re.search('^{0}$'.format(re.escape(content)), line):
# Content was found, so set found.
found = True
# Identity check each potential change until one change is made
if has_changes is False and result != line:
has_changes = True
# Keep track of show_changes here, in case the file isn't
# modified
if show_changes or append_if_not_found or \
prepend_if_not_found:
orig_file.append(line)
new_file.append(result)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to open file '{0}'. Exception: {1}".format(path, exc)
)
finally:
if r_data and isinstance(r_data, mmap.mmap):
r_data.close()
if has_changes and not dry_run:
# Write the replacement text in this block.
@ -1864,20 +1868,25 @@ def replace(path,
with salt.utils.fopen(temp_file,
mode='r',
buffering=bufsize) as r_file:
for line in r_file:
result, nrepl = re.subn(cpattern, repl,
line, count)
try:
w_file.write(result)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to write file '{0}'. Contents may "
"be truncated. Temporary file contains copy "
"at '{1}'. "
"Exception: {2}".format(path, temp_file, exc)
)
r_data = mmap.mmap(r_file.fileno(),
0,
access=mmap.ACCESS_READ)
result, nrepl = re.subn(cpattern, repl,
r_data, count)
try:
w_file.write(result)
except (OSError, IOError) as exc:
raise CommandExecutionError(
"Unable to write file '{0}'. Contents may "
"be truncated. Temporary file contains copy "
"at '{1}'. "
"Exception: {2}".format(path, temp_file, exc)
)
except (OSError, IOError) as exc:
raise CommandExecutionError("Exception: {0}".format(exc))
finally:
if r_data and isinstance(r_data, mmap.mmap):
r_data.close()
except (OSError, IOError) as exc:
raise CommandExecutionError("Exception: {0}".format(exc))
@ -2162,7 +2171,7 @@ def blockreplace(path,
def search(path,
pattern,
flags=0,
flags=8,
bufsize=1,
ignore_if_missing=False,
multiline=False

View file

@ -443,7 +443,7 @@ def mkpart(device, part_type, fs_type=None, start=None, end=None):
'''
_validate_device(device)
if not start or not end:
if start in [None, ''] or end in [None, '']:
raise CommandExecutionError(
'partition.mkpart requires a start and an end'
)

View file

@ -322,9 +322,9 @@ def _parse_settings_bond_1(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -405,9 +405,9 @@ def _parse_settings_bond_3(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -449,9 +449,9 @@ def _parse_settings_bond_4(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -492,9 +492,9 @@ def _parse_settings_bond_5(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)
@ -528,9 +528,9 @@ def _parse_settings_bond_6(opts, iface, bond_def):
if 'use_carrier' in opts:
if opts['use_carrier'] in _CONFIG_TRUE:
bond.update({'use_carrier': 'on'})
bond.update({'use_carrier': '1'})
elif opts['use_carrier'] in _CONFIG_FALSE:
bond.update({'use_carrier': 'off'})
bond.update({'use_carrier': '0'})
else:
valid = _CONFIG_TRUE + _CONFIG_FALSE
_raise_error_iface(iface, 'use_carrier', valid)

View file

@ -335,7 +335,7 @@ def build_schedule_item(name, **kwargs):
schedule[name]['splay'] = kwargs['splay']
for item in ['range', 'when', 'once', 'once_fmt', 'cron', 'returner',
'return_config', 'until']:
'return_config', 'until', 'enabled']:
if item in kwargs:
schedule[name][item] = kwargs[item]

View file

@ -714,7 +714,7 @@ def list_runner_functions(*args, **kwargs): # pylint: disable=unused-argument
def list_returners(*args):
'''
List the runners loaded on the minion
List the returners loaded on the minion
.. versionadded:: 2014.7.0

View file

@ -1914,6 +1914,14 @@ def mod_repo(repo, basedir=None, **kwargs):
del repo_opts[key]
todelete.append(key)
# convert disabled=True to enabled=0 from pkgrepo state
if 'disabled' in repo_opts:
kw_disabled = repo_opts['disabled']
if kw_disabled is True or str(kw_disabled).lower() == 'true':
repo_opts['enabled'] = 0
del repo_opts['disabled']
todelete.append('disabled')
# Add baseurl or mirrorlist to the 'todelete' list if the other was
# specified in the repo_opts
if 'mirrorlist' in repo_opts:

View file

@ -2453,7 +2453,7 @@ def replace(name,
pattern,
repl,
count=0,
flags=0,
flags=8,
bufsize=1,
append_if_not_found=False,
prepend_if_not_found=False,
@ -2480,16 +2480,18 @@ def replace(name,
replaced, otherwise all occurrences will be replaced.
flags
A list of flags defined in the :ref:`re module documentation <contents-of-module-re>`.
Each list item should be a string that will correlate to the human-friendly flag name.
E.g., ``['IGNORECASE', 'MULTILINE']``. Note: multiline searches must specify ``file``
as the ``bufsize`` argument below. Defaults to 0 and can be a list or an int.
A list of flags defined in the :ref:`re module documentation
<contents-of-module-re>`. Each list item should be a string that will
correlate to the human-friendly flag name. E.g., ``['IGNORECASE',
'MULTILINE']``. Optionally, ``flags`` may be an int, with a value
corresponding to the XOR (``|``) of all the desired flags. Defaults to
8 (which supports 'MULTILINE').
bufsize
How much of the file to buffer into memory at once. The default value ``1`` processes
one line at a time. The special value ``file`` may be specified which will read the
entire file into memory before processing. Note: multiline searches must specify ``file``
buffering. Can be an int or a str.
How much of the file to buffer into memory at once. The default value
``1`` processes one line at a time. The special value ``file`` may be
specified which will read the entire file into memory before
processing.
append_if_not_found
If pattern is not found and set to ``True`` then, the content will be appended to the file.

View file

@ -368,27 +368,28 @@ def _find_install_targets(name=None,
for name, version in desired.items()
if not (name in cur_pkgs and version in (None, cur_pkgs[name]))
])
problems = _preflight_check(not_installed, **kwargs)
comments = []
if problems.get('no_suggest'):
comments.append(
'The following package(s) were not found, and no possible '
'matches were found in the package db: '
'{0}'.format(', '.join(sorted(problems['no_suggest'])))
)
if problems.get('suggest'):
for pkgname, suggestions in six.iteritems(problems['suggest']):
if not_installed:
problems = _preflight_check(not_installed, **kwargs)
comments = []
if problems.get('no_suggest'):
comments.append(
'Package \'{0}\' not found (possible matches: {1})'
.format(pkgname, ', '.join(suggestions))
'The following package(s) were not found, and no possible '
'matches were found in the package db: '
'{0}'.format(', '.join(sorted(problems['no_suggest'])))
)
if comments:
if len(comments) > 1:
comments.append('')
return {'name': name,
'changes': {},
'result': False,
'comment': '. '.join(comments).rstrip()}
if problems.get('suggest'):
for pkgname, suggestions in six.iteritems(problems['suggest']):
comments.append(
'Package \'{0}\' not found (possible matches: {1})'
.format(pkgname, ', '.join(suggestions))
)
if comments:
if len(comments) > 1:
comments.append('')
return {'name': name,
'changes': {},
'result': False,
'comment': '. '.join(comments).rstrip()}
# Find out which packages will be targeted in the call to pkg.install
targets = {}

View file

@ -187,6 +187,12 @@ def present(name,
ret['comment'] = new_item['comment']
return ret
# The schedule.list gives us an item that is guaranteed to have an
# 'enabled' argument. Before comparing, add 'enabled' if it's not
# available (assume True, like schedule.list does)
if 'enabled' not in new_item:
new_item['enabled'] = True
if new_item == current_schedule[name]:
ret['comment'].append('Job {0} in correct state'.format(name))
else:

View file

@ -113,6 +113,7 @@ class PillarModuleTest(integration.ModuleCase):
self.assertEqual(grepo.rp_location, repo.remotes.origin.url)
if __name__ == '__main__':
from integration import run_tests
run_tests(PillarModuleTest)

View file

@ -50,7 +50,8 @@ class EventTestCase(TestCase):
self.assertTrue(event.fire_master('data', 'tag'))
with patch.dict(event.__opts__, {'transport': 'A',
'id': 'id'}):
'id': 'id',
'master_uri': 'localhost'}):
with patch.object(salt_crypt_sauth, 'gen_token',
return_value='tok'):
with patch.object(salt_transport_channel_factory, 'send',