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

[2015.8] Merge forward from 2015.5 to 2015.8
This commit is contained in:
Colton Myers 2015-09-17 13:53:22 -06:00
commit 8c204a45ab
33 changed files with 314 additions and 152 deletions

View file

@ -28,6 +28,9 @@
# The level of messages to send to the console.
# One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'.
#
# The following log levels are considered INSECURE and may log sensitive data:
# ['garbage', 'trace', 'debug']
#
# Default: 'info'
#
#log_level: info

View file

@ -692,6 +692,10 @@
# The level of messages to send to the console.
# One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'.
#
# The following log levels are considered INSECURE and may log sensitive data:
# ['garbage', 'trace', 'debug']
#
#log_level: warning
# The level of messages to send to the log file.

View file

@ -511,6 +511,10 @@
# The level of messages to send to the console.
# One of 'garbage', 'trace', 'debug', info', 'warning', 'error', 'critical'.
#
# The following log levels are considered INSECURE and may log sensitive data:
# ['garbage', 'trace', 'debug']
#
# Default: 'warning'
#log_level: warning

View file

@ -1,3 +1,5 @@
.. _faq:
Frequently Asked Questions
==========================
@ -301,3 +303,18 @@ More information about salting the Salt master can be found in the salt-formula
for salt itself:
https://github.com/saltstack-formulas/salt-formula
.. _faq-grain-security:
Is Targeting using Grain Data Secure?
=====================================
Because grains can be set by users that have access to the minion configuration
files on the local system, grains are considered less secure than other
identifiers in Salt. Use caution when targeting sensitive operations or setting
pillar values based on grain data.
When possible, you should target sensitive operations and data using the Minion
ID. If the Minion ID of a system changes, the Salt Minion's public key must be
re-accepted by an administrator on the Salt Master, making it less vulnerable
to impersonation attacks.

View file

@ -238,15 +238,6 @@ The ``__virtual__`` function is used to return either a
False is returned then the module is not loaded, if a string is returned then
the module is loaded with the name of the string.
.. note::
Optionally, modules may additionally return a list of reasons that a module could
not be loaded. For example, if a dependency for 'my_mod' was not met, a
__virtual__ function could do as follows:
return False, ['My Module must be installed before this module can be
used.']
This means that the package manager modules can be presented as the ``pkg`` module
regardless of what the actual module is named.
@ -265,6 +256,16 @@ function. Some examples:
Modules which return a string from ``__virtual__`` that is already used by a module that
ships with Salt will _override_ the stock module.
Returning Error Information from ``__virtual__``
------------------------------------------------
Optionally, modules may additionally return a list of reasons that a module could
not be loaded. For example, if a dependency for 'my_mod' was not met, a
__virtual__ function could do as follows:
return False, ['My Module must be installed before this module can be
used.']
Documentation
=============

View file

@ -60,6 +60,7 @@ Google Compute Engine Setup
*If you are using ``libcloud >= 0.17.0`` it is recommended that you use the ``JSON
format`` file you downloaded above and skip to the "Configuration" section below, using
the JSON file **_in place of 'NEW.pem'_** in the documentation.
If you are using an older version of libcloud or are unsure of the version you
have, please follow the instructions below to generate and format a new P12 key.*
@ -78,35 +79,31 @@ Google Compute Engine Setup
Configuration
=============
Provider Configuration
======================
Set up the cloud config at ``/etc/salt/cloud``:
Set up the provider cloud config at ``/etc/salt/cloud.providers`` or
``/etc/salt/cloud.providers.d/*.conf``:
.. code-block:: yaml
# Note: This example is for /etc/salt/cloud
gce-config:
# Set up the Project name and Service Account authorization
project: "your-project-id"
service_account_email_address: "123-a5gt@developer.gserviceaccount.com"
service_account_private_key: "/path/to/your/NEW.pem"
providers:
gce-config:
# Set up the Project name and Service Account authorization
#
project: "your-project-id"
service_account_email_address: "123-a5gt@developer.gserviceaccount.com"
service_account_private_key: "/path/to/your/NEW.pem"
# Set up the location of the salt master
minion:
master: saltmaster.example.com
# Set up the location of the salt master
#
minion:
master: saltmaster.example.com
# Set up grains information, which will be common for all nodes
# using this provider
grains:
node_type: broker
release: 1.0.1
# Set up grains information, which will be common for all nodes
# using this provider
grains:
node_type: broker
release: 1.0.1
driver: gce
driver: gce
.. note::
@ -122,13 +119,14 @@ Set up the cloud config at ``/etc/salt/cloud``:
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Cloud Profiles
==============
Set up an initial profile at ``/etc/salt/cloud.profiles``:
Profile Configuration
=====================
Set up an initial profile at ``/etc/salt/cloud.profiles`` or
``/etc/salt/cloud.profiles.d/*.conf``:
.. code-block:: yaml
all_settings:
my-gce-profile:
image: centos-6
size: n1-standard-1
location: europe-west1-b
@ -145,18 +143,18 @@ The profile can be realized now with a salt command:
.. code-block:: bash
salt-cloud -p all_settings gce-instance
salt-cloud -p my-gce-profile gce-instance
This will create an salt minion instance named ``gce-instance`` in GCE. If
the command was executed on the salt-master, its Salt key will automatically
be signed on the master.
Once the instance has been created with salt-minion installed, connectivity to
Once the instance has been created with a salt-minion installed, connectivity to
it can be verified with Salt:
.. code-block:: bash
salt 'ami.example.com' test.ping
salt gce-instance test.ping
GCE Specific Settings
@ -167,7 +165,7 @@ typically also include a hard-coded default.
.. code-block:: yaml
all_settings:
my-gce-profile:
# Image is used to define what Operating System image should be used
# to for the instance. Examples are Debian 7 (wheezy) and CentOS 6.
@ -239,11 +237,12 @@ typically also include a hard-coded default.
GCE instances do not allow remote access to the root user by default.
Instead, another user must be used to run the deploy script using sudo.
Append something like this to ``/etc/salt/cloud.profiles``:
Append something like this to ``/etc/salt/cloud.profiles`` or
``/etc/salt/cloud.profiles.d/*.conf``:
.. code-block:: yaml
all_settings:
my-gce-profile:
...
# SSH to GCE instances as gceuser
@ -259,7 +258,7 @@ the metadata setting too:
.. code-block:: yaml
all_settings:
my-gce-profile:
...
metadata: '{"one": "1", "2": "two",
@ -432,7 +431,7 @@ Specify the network name to view information about the network.
salt-cloud -f show_network gce name=mynet
Create address
---------------
--------------
Create a new named static IP address in a region.
.. code-block:: bash
@ -440,7 +439,7 @@ Create a new named static IP address in a region.
salt-cloud -f create_address gce name=my-fixed-ip region=us-central1
Delete address
---------------
--------------
Delete an existing named fixed IP address.
.. code-block:: bash
@ -448,7 +447,7 @@ Delete an existing named fixed IP address.
salt-cloud -f delete_address gce name=my-fixed-ip region=us-central1
Show address
---------------
------------
View details on a named address.
.. code-block:: bash

View file

@ -64,6 +64,87 @@ installer:
Salt-Minion-0.17.0-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname
Running the Salt Minion on Windows as an Unprivileged User
==========================================================
Notes:
- These instructions were tested with Windows Server 2008 R2
- They are generalizable to any version of Windows that supports a salt-minion
A. Create the Unprivileged User that the Salt Minion will Run As
----------------------------------------------------------------
1. Click "Start", "Control Panel", "User Accounts"
2. Click "Add or remove user accounts"
3. Click "Create new account"
4. Enter "salt-user" (or a name of your preference) in the "New account name" field
5. Select the "Standard user" radio button
6. Click the "Create Account" button
7. Click on the newly created user account
8. Click the "Create a password" link
9. In the "New password" and "Confirm new password" fields, provide a password (e.g "SuperSecretMinionPassword4Me!")
10. In the "Type a password hint" field, provide appropriate text (e.g. "My Salt Password")
11. Click the "Create password" button
12. Close the "Change an Account" window
B. Add the New User to the Access Control List for the Salt Folder
------------------------------------------------------------------
1. In a File Explorer window, browse to the path where Salt is installed (the default path is C:\Salt)
2. Right-click on the "Salt" folder and select "Properties"
3. Click on the "Security" tab
4. Click the "Edit" button
5. Click the "Add" button
6. Type the name of your designated Salt user and click the "OK" button
7. Check the box to "Allow" the "Modify" permission
8. Click the "OK" button
9. Click the "OK" button to close the "Salt Properties" window
C. Update the Windows Service User for the "salt-minion" Service
----------------------------------------------------------------
1. Click "Start", "Administrative Tools", "Services"
2. In the list of Services, Right-Click on "salt-minion" and select "Properties"
3. Click the "Log On" tab
4. Click the "This account" radio button
5. Provide the account credentials created in section A
6. Click the "OK" button
7. Click the "OK" button to the prompt confirming that the user "has been granted the Log On As A Service right"
8. Click the "OK" button to the prompt confirming that "The new logon name will not take effect until you stop and restart the service"
9. Right-Click on "salt-minion" and select "Stop"
10. Right-Click on "salt-minion" and select "Start"
Setting up a Windows build environment
======================================

View file

@ -5,7 +5,7 @@ Release notes
See the :doc:`version numbers</topics/releases/version_numbers>` page for more
information about the version numbering scheme.
Latest Stable Release
Latest Branch Release
=====================
|current_release_doc|

View file

@ -16,6 +16,7 @@ import logging
import salt.utils.parsers as parsers
import salt.version
import salt.syspaths as syspaths
from salt.utils.verify import verify_log
# Import 3rd-party libs
import salt.ext.six as six
@ -48,6 +49,7 @@ class SaltAPI(six.with_metaclass(parsers.OptionParserMeta, # pylint: disable=W0
import salt.client.netapi
self.parse_args()
self.setup_logfile_logger()
verify_log(self.config)
self.daemonize_if_required()
client = salt.client.netapi.NetapiClient(self.config)
self.set_pidfile()

View file

@ -4,6 +4,7 @@ from __future__ import absolute_import
import os
from salt.utils import parsers
from salt.utils.verify import verify_log
from salt.config import _expand_glob_path
import salt.cli.caller
import salt.defaults.exitcodes
@ -37,6 +38,7 @@ class SaltCall(parsers.SaltCallOptionParser):
# Setup file logging!
self.setup_logfile_logger()
verify_log(self.config)
caller = salt.cli.caller.Caller.factory(self.config)

View file

@ -15,6 +15,7 @@ import sys
# Import salt libs
import salt.client
from salt.utils import parsers, print_cli
from salt.utils.verify import verify_log
import salt.output
@ -31,6 +32,7 @@ class SaltCPCli(parsers.SaltCPOptionParser):
# Setup file logging!
self.setup_logfile_logger()
verify_log(self.config)
cp_ = SaltCP(self.config)
cp_.run()

View file

@ -8,6 +8,7 @@ from __future__ import absolute_import
import os
import sys
import warnings
from salt.utils.verify import verify_log
# All salt related deprecation warnings should be shown once each!
warnings.filterwarnings(
@ -115,6 +116,7 @@ class Master(parsers.MasterOptionParser):
sys.exit(err.errno)
self.setup_logfile_logger()
verify_log(self.config)
logger.info('Setting up the Salt Master')
# TODO: AIO core is separate from transport
@ -226,6 +228,7 @@ class Minion(parsers.MinionOptionParser): # pylint: disable=no-init
sys.exit(err.errno)
self.setup_logfile_logger()
verify_log(self.config)
logger.info(
'Setting up the Salt Minion "{0}"'.format(
self.config['id']
@ -387,6 +390,7 @@ class ProxyMinion(parsers.ProxyMinionOptionParser): # pylint: disable=no-init
sys.exit(err.errno)
self.setup_logfile_logger()
verify_log(self.config)
logger.info(
'Setting up a Salt Proxy Minion "{0}"'.format(
self.config['id']
@ -484,6 +488,7 @@ class Syndic(parsers.SyndicOptionParser):
sys.exit(err.errno)
self.setup_logfile_logger()
verify_log(self.config)
logger.info(
'Setting up the Salt Syndic Minion "{0}"'.format(
self.config['id']

View file

@ -3,7 +3,7 @@ from __future__ import print_function
from __future__ import absolute_import
from salt.utils import parsers
from salt.utils.verify import check_user
from salt.utils.verify import check_user, verify_log
class SaltKey(parsers.SaltKeyOptionParser):
@ -22,6 +22,7 @@ class SaltKey(parsers.SaltKeyOptionParser):
multi = True
self.setup_logfile_logger()
verify_log(self.config)
if multi:
key = salt.key.MultiKeyCLI(self.config)

View file

@ -5,7 +5,7 @@ from __future__ import absolute_import
from salt.utils import parsers
from salt.utils import activate_profile
from salt.utils import output_profile
from salt.utils.verify import check_user
from salt.utils.verify import check_user, verify_log
from salt.exceptions import SaltClientError
import salt.defaults.exitcodes # pylint: disable=W0611
@ -24,6 +24,7 @@ class SaltRun(parsers.SaltRunOptionParser):
# Setup file logging!
self.setup_logfile_logger()
verify_log(self.config)
profiling_enabled = self.options.profiling_enabled
runner = salt.runner.Runner(self.config)

View file

@ -9,6 +9,7 @@ import sys
import salt.utils.job
from salt.ext.six import string_types
from salt.utils import parsers, print_cli
from salt.utils.verify import verify_log
from salt.exceptions import (
SaltClientError,
SaltInvocationError,
@ -34,6 +35,7 @@ class SaltCMD(parsers.SaltCMDOptionParser):
# Setup file logging!
self.setup_logfile_logger()
verify_log(self.config)
try:
# We don't need to bail on config file permission errors

View file

@ -4,6 +4,7 @@ from __future__ import print_function
from __future__ import absolute_import
import salt.client.ssh
from salt.utils import parsers
from salt.utils.verify import verify_log
class SaltSSH(parsers.SaltSSHOptionParser):
@ -14,6 +15,7 @@ class SaltSSH(parsers.SaltSSHOptionParser):
def run(self):
self.parse_args()
self.setup_logfile_logger()
verify_log(self.config)
ssh = salt.client.ssh.SSH(self.config)
ssh.run()

View file

@ -25,7 +25,7 @@ import salt.defaults.exitcodes
import salt.output
import salt.utils
from salt.utils import parsers
from salt.utils.verify import check_user, verify_env, verify_files
from salt.utils.verify import check_user, verify_env, verify_files, verify_log
# Import salt.cloud libs
import salt.cloud
@ -77,6 +77,7 @@ class SaltCloud(parsers.SaltCloudParser):
# Setup log file logging
self.setup_logfile_logger()
verify_log(self.config)
if self.options.update_bootstrap:
ret = salt.utils.cloud.update_bootstrap(self.config)

View file

@ -3027,6 +3027,11 @@ def list_nodes_full(location=None, call=None):
get_location(vm_) for vm_ in six.itervalues(__opts__['profiles'])
if _vm_provider_driver(vm_)
)
# If there aren't any profiles defined for EC2, check
# the provider config file, or use the default location.
if not locations:
locations = [get_location()]
for loc in locations:
ret.update(_list_nodes_full(loc))
return ret

View file

@ -119,7 +119,7 @@ list_nodes = namespaced_function(list_nodes, globals())
list_nodes_full = namespaced_function(list_nodes_full, globals())
list_nodes_select = namespaced_function(list_nodes_select, globals())
GCE_VM_NAME_REGEX = re.compile(r'(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)')
GCE_VM_NAME_REGEX = re.compile(r'^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$')
# Only load in this module if the GCE configurations are in place
@ -2041,9 +2041,8 @@ def create(vm_=None, call=None):
if not GCE_VM_NAME_REGEX.match(vm_['name']):
raise SaltCloudSystemExit(
'The allowed VM names must match the following regular expression: {0}'.format(
GCE_VM_NAME_REGEX.pattern
)
'VM names must start with a letter, only contain letters, numbers, or dashes '
'and cannot end in a dash.'
)
try:

View file

@ -492,7 +492,7 @@ def list_nodes_full(mask='mask[id]', call=None):
)
ret = {}
conn = get_conn(service='Account')
conn = get_conn(service='SoftLayer_Account')
response = conn.getVirtualGuests()
for node_id in response:
ret[node_id['hostname']] = node_id
@ -605,5 +605,5 @@ def list_vlans(call=None):
'The list_vlans function must be called with -f or --function.'
)
conn = get_conn(service='Account')
conn = get_conn(service='SoftLayer_Account')
return conn.getNetworkVlans()

View file

@ -424,7 +424,7 @@ def list_nodes_full(mask='mask[id, hostname, primaryIpAddress, \
)
ret = {}
conn = get_conn(service='Account')
conn = get_conn(service='SoftLayer_Account')
response = conn.getHardware(mask=mask)
for node in response:
@ -544,7 +544,7 @@ def list_vlans(call=None):
'The list_vlans function must be called with -f or --function.'
)
conn = get_conn(service='Account')
conn = get_conn(service='SoftLayer_Account')
return conn.getNetworkVlans()

View file

@ -1487,8 +1487,8 @@ def build(path=None,
except Exception:
_invalid(status,
out=traceback.format_exc(),
comment='Unexpected error while building an image')
out=traceback.format_exc(),
comment='Unexpected error while building an image')
return status
return status
@ -1863,16 +1863,13 @@ def _run_wrapper(status, container, func, cmd, *args, **kwargs):
comment = 'Executed {0}'.format(full_cmd)
try:
ret = __salt__[func](full_cmd, *args, **kwargs)
if ((isinstance(ret, dict) and
('retcode' in ret) and
(ret['retcode'] != 0))
or (func == 'cmd.retcode' and ret != 0)):
return _invalid(status, id_=container, out=ret,
comment=comment)
_valid(status, id_=container, out=ret, comment=comment,)
if ((isinstance(ret, dict) and ('retcode' in ret) and (ret['retcode'] != 0))
or (func == 'cmd.retcode' and ret != 0)):
_invalid(status, id_=container, out=ret, comment=comment)
else:
_valid(status, id_=container, out=ret, comment=comment)
except Exception:
_invalid(status, id_=container,
comment=comment, out=traceback.format_exc())
_invalid(status, id_=container, comment=comment, out=traceback.format_exc())
return status
@ -1897,9 +1894,7 @@ def load(imagepath):
try:
dockercmd = ['docker', 'load', '-i', imagepath]
ret = __salt__['cmd.run'](dockercmd, python_shell=False)
if ((isinstance(ret, dict) and
('retcode' in ret) and
(ret['retcode'] != 0))):
if isinstance(ret, dict) and ('retcode' in ret) and (ret['retcode'] != 0):
return _invalid(status, id_=None,
out=ret,
comment='Command to load image {0} failed.'.format(imagepath))
@ -1907,12 +1902,12 @@ def load(imagepath):
_valid(status, id_=None, out=ret, comment='Image load success')
except Exception:
_invalid(status, id_=None,
comment="Image not loaded.",
out=traceback.format_exc())
comment="Image not loaded.",
out=traceback.format_exc())
else:
_invalid(status, id_=None,
comment='Image file {0} could not be found.'.format(imagepath),
out=traceback.format_exc())
comment='Image file {0} could not be found.'.format(imagepath),
out=traceback.format_exc())
return status
@ -1943,16 +1938,14 @@ def save(image, filename):
ok = True
except Exception:
_invalid(status, id_=image,
comment="docker image {0} could not be found.".format(image),
out=traceback.format_exc())
comment="docker image {0} could not be found.".format(image),
out=traceback.format_exc())
if ok:
try:
dockercmd = ['docker', 'save', '-o', filename, image]
ret = __salt__['cmd.run'](dockercmd)
if ((isinstance(ret, dict) and
('retcode' in ret) and
(ret['retcode'] != 0))):
if isinstance(ret, dict) and ('retcode' in ret) and (ret['retcode'] != 0):
return _invalid(status,
id_=image,
out=ret,
@ -2097,9 +2090,7 @@ def retcode(container, cmd):
command to execute
.. note::
The return is a bit different as we use the docker struct.
Output of the command is in 'out' and result is ``False`` if
command failed to execute.
The return is True or False depending on the commands success.
.. warning::
Be advised that this function allows for raw shell access to the named
@ -2114,7 +2105,7 @@ def retcode(container, cmd):
'''
status = base_status.copy()
return _run_wrapper(
status, container, 'cmd.retcode', cmd)
status, container, 'cmd.retcode', cmd)['status']
def get_container_root(container):

View file

@ -198,19 +198,25 @@ def read_value(hive, key, vname=None):
ret['vname'] = '(Default)'
registry = Registry()
hive = registry.hkeys[hive]
hkey = registry.hkeys[hive]
try:
handle = _winreg.OpenKey(hive, key)
vdata, vtype = _winreg.QueryValueEx(handle, vname)
if vdata:
ret['vdata'] = vdata
ret['vtype'] = registry.vtype_reverse[vtype]
else:
ret['comment'] = 'Empty Value'
handle = _winreg.OpenKey(hkey, key)
try:
vdata, vtype = _winreg.QueryValueEx(handle, vname)
if vdata or vdata in [0, '']:
ret['vtype'] = registry.vtype_reverse[vtype]
ret['vdata'] = vdata
else:
ret['comment'] = 'Empty Value'
except WindowsError as exc: # pylint: disable=E0602
ret['vdata'] = ('(value not set)')
ret['vtype'] = 'REG_SZ'
ret['success'] = True
except WindowsError as exc: # pylint: disable=E0602
log.debug(exc)
ret['comment'] = '{0}'.format(exc)
log.debug('Cannot find key: {0}\\{1}'.format(hive, key))
ret['comment'] = 'Cannot find key: {0}\\{1}'.format(hive, key)
ret['success'] = False
return ret
@ -310,7 +316,7 @@ def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', reflection=True
_winreg.CloseKey(handle)
return True
except (WindowsError, ValueError) as exc: # pylint: disable=E0602
log.error(exc)
log.error(exc, exc_info=True)
return False
@ -430,7 +436,7 @@ def delete_key(hkey, path, key=None, reflection=True, force=False):
_winreg.DeleteKey(hive, key)
return True
except WindowsError as exc: # pylint: disable=E0602
log.error(exc)
log.error(exc, exc_info=True)
return False
@ -500,7 +506,7 @@ def delete_key_recursive(hive, key):
_winreg.DeleteKey(hkey, keypath)
ret['Deleted'].append(r'{0}\{1}'.format(hive, keypath))
except WindowsError as exc: # pylint: disable=E0602
log.error(exc)
log.error(exc, exc_info=True)
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc))
# Delete the key now that all the subkeys are deleted
@ -508,7 +514,7 @@ def delete_key_recursive(hive, key):
_winreg.DeleteKey(hkey, key)
ret['Deleted'].append(r'{0}\{1}'.format(hive, key))
except WindowsError as exc: # pylint: disable=E0602
log.error(exc)
log.error(exc, exc_info=True)
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc))
return ret
@ -557,5 +563,5 @@ def delete_value(hive, key, vname=None, reflection=True):
return True
except WindowsError as exc: # pylint: disable=E0602
_winreg.CloseKey(handle)
log.error(exc)
log.error(exc, exc_info=True)
return False

View file

@ -452,7 +452,8 @@ def sync_log_handlers(saltenv=None, refresh=True):
def sync_all(saltenv=None, refresh=True):
'''
Sync down all of the dynamic modules from the file server for a specific
environment
environment. This function synchronizes custom modules, states, beacons,
grains, returners, outputters, renderers, and utils.
refresh : True
Also refresh the execution modules available to the minion.

View file

@ -73,7 +73,7 @@ def get_path():
salt '*' win_path.get_path
'''
ret = __salt__['reg.read_key']('HKEY_LOCAL_MACHINE',
ret = __salt__['reg.read_value']('HKEY_LOCAL_MACHINE',
'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',
'PATH')
if isinstance(ret, dict):
@ -155,8 +155,8 @@ def add(path, index=0):
regedit = __salt__['reg.set_value'](
'HKEY_LOCAL_MACHINE',
'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',
';'.join(sysPath),
'PATH',
';'.join(sysPath),
'REG_EXPAND_SZ'
)
@ -197,8 +197,8 @@ def remove(path):
regedit = __salt__['reg.set_value'](
'HKEY_LOCAL_MACHINE',
'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment',
';'.join(sysPath),
'PATH',
';'.join(sysPath),
'REG_EXPAND_SZ'
)
if regedit:

View file

@ -300,8 +300,8 @@ def _parse_volumes(volumes):
contvolumes.append(str(vol))
continue
bindvolumes[source] = {
'bind': target,
'ro': read_only
'bind': target,
'ro': read_only
}
result = {'bindvols': bindvolumes, 'contvols': contvolumes}
log.trace("Finished parsing volumes, with result: " + str(result))
@ -507,9 +507,9 @@ def loaded(name, tag='latest', source=None, source_hash='', force=False):
tmp_filename = salt.utils.mkstemp()
__salt__['state.single']('file.managed',
name=tmp_filename,
source=source,
source_hash=source_hash)
name=tmp_filename,
source=source,
source_hash=source_hash)
changes = {}
if image_infos['status']:
@ -517,9 +517,8 @@ def loaded(name, tag='latest', source=None, source_hash='', force=False):
remove_image = __salt__['docker.remove_image']
remove_info = remove_image(image_name)
if not remove_info['status']:
return _invalid(
name=name,
comment='Image could not be removed: {0}'.format(image_name))
return _invalid(name=name,
comment='Image could not be removed: {0}'.format(name))
load = __salt__['docker.load']
returned = load(tmp_filename)
@ -757,23 +756,23 @@ def absent(name):
is_gone = __salt__['docker.exists'](cid)
if is_gone:
return _valid(comment=('Container {0!r}'
' was stopped and destroyed, '.format(cid)),
changes={name: True})
' was stopped and destroyed, '.format(cid)),
changes={name: True})
else:
return _valid(comment=('Container {0!r}'
' was stopped but could not be destroyed,'.format(cid)),
changes={name: True})
' was stopped but could not be destroyed,'.format(cid)),
changes={name: True})
else:
__salt__['docker.remove_container'](cid)
is_gone = __salt__['docker.exists'](cid)
if is_gone:
return _valid(comment=('Container {0!r}'
' is stopped and was destroyed, '.format(cid)),
changes={name: True})
'is stopped and was destroyed, '.format(cid)),
changes={name: True})
else:
return _valid(comment=('Container {0!r}'
' is stopped but could not be destroyed,'.format(cid)),
changes={name: True})
' is stopped but could not be destroyed,'.format(cid)),
changes={name: True})
else:
return _valid(comment="Container {0!r} not found".format(name))
@ -862,7 +861,7 @@ def run(name,
if not onlyif:
return valid(comment='onlyif execution failed')
elif isinstance(onlyif, string_types):
if retcode(cid, onlyif) != 0:
if not __salt__['cmd.retcode'](onlyif) == 0:
return valid(comment='onlyif execution failed')
if unless is not None:
@ -870,7 +869,7 @@ def run(name,
if unless:
return valid(comment='unless execution succeeded')
elif isinstance(unless, string_types):
if retcode(cid, unless) == 0:
if __salt__['cmd.retcode'](unless) == 0:
return valid(comment='unless execution succeeded')
if docked_onlyif is not None:
@ -878,7 +877,7 @@ def run(name,
if not docked_onlyif:
return valid(comment='docked_onlyif execution failed')
elif isinstance(docked_onlyif, string_types):
if retcode(cid, docked_onlyif) != 0:
if not retcode(cid, docked_onlyif):
return valid(comment='docked_onlyif execution failed')
if docked_unless is not None:
@ -886,7 +885,7 @@ def run(name,
if docked_unless:
return valid(comment='docked_unless execution succeeded')
elif isinstance(docked_unless, string_types):
if retcode(cid, docked_unless) == 0:
if retcode(cid, docked_unless):
return valid(comment='docked_unless execution succeeded')
if __opts__['test']:
@ -1266,9 +1265,8 @@ def running(name,
if is_running:
changes.append('Container {0!r} started.\n'.format(name))
else:
return _invalid(comment=(
'Container {0!r} cannot be started\n{1!s}'
.format(name, started['out'],)))
return _invalid(comment=('Container {0!r} cannot be started\n{1!s}'
.format(name, started['out'],)))
else:
changes.append('Container {0!r} started.\n'.format(name))
return _valid(comment='\n'.join(changes), changes={name: True})

View file

@ -1445,6 +1445,8 @@ def managed(name,
if ret['changes']:
ret['result'] = None
ret['comment'] = 'The file {0} is set to be changed'.format(name)
if not show_diff:
ret['changes']['diff'] = '<show_diff=False>'
else:
ret['result'] = True
ret['comment'] = 'The file {0} is in the correct state'.format(name)
@ -3825,11 +3827,16 @@ def copy(
)
if __opts__['test']:
ret['comment'] = 'File "{0}" is set to be copied to "{1}"'.format(
source,
name
)
ret['result'] = None
if changed:
ret['comment'] = 'File "{0}" is set to be copied to "{1}"'.format(
source,
name
)
ret['result'] = None
else:
ret['comment'] = ('The target file "{0}" exists and will not be '
'overwritten'.format(name))
ret['result'] = True
return ret
if not changed:
@ -4248,10 +4255,10 @@ def serialize(name,
if os.path.isfile(name):
if formatter == 'yaml':
with salt.utils.fopen(name, 'r') as fhr:
existing_data = yaml.safe_load(fhr.read())
existing_data = yaml.safe_load(fhr)
elif formatter == 'json':
with salt.utils.fopen(name, 'r') as fhr:
existing_data = json.load(fhr.read())
existing_data = json.load(fhr)
else:
return {'changes': {},
'comment': ('{0} format is not supported for merging'

View file

@ -186,7 +186,7 @@ def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection
# This is for backwards compatibility
# If 'value' is passed a value, vdata becomes value and the vname is
# obtained from the key path
if value:
if value or value in [0, '']:
hive, key, vname = _parse_key_value(name)
vdata = value
ret['comment'] = 'State file is using deprecated syntax. Please update.'
@ -208,7 +208,7 @@ def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection
add_change = {'Key': r'{0}\{1}'.format(hive, key),
'Entry': '{0}'.format(vname if vname else '(Default)'),
'Value': '{0}'.format(vdata if vdata else '(Empty String)')}
'Value': '{0}'.format(vdata)}
# Check for test option
if __opts__['test']:
@ -256,9 +256,15 @@ def absent(name, vname=None):
hive, key = _parse_key(name)
# Determine what to do
if not __salt__['reg.read_value'](hive, key, vname)['success']:
hive, key, vname = _parse_key_value(name)
if not __salt__['reg.read_value'](hive, key, vname)['success']:
reg_check = __salt__['reg.read_value'](hive, key, vname)
if not reg_check['success'] or reg_check['vdata'] == '(value not set)':
if not vname:
hive, key, vname = _parse_key_value(name)
reg_check = __salt__['reg.read_value'](hive, key, vname)
if not reg_check['success'] or reg_check['vdata'] == '(value not set)':
ret['comment'] = '{0} is already absent'.format(name)
return ret
else:
ret['comment'] = '{0} is already absent'.format(name)
return ret
@ -275,11 +281,10 @@ def absent(name, vname=None):
ret['result'] = __salt__['reg.delete_value'](hive, key, vname)
if not ret['result']:
ret['changes'] = {}
ret['comment'] = r'Failed to remove {0} from {1}\{2}'.format(name, hive,
key)
ret['comment'] = r'Failed to remove {0} from {1}'.format(key, hive)
else:
ret['changes'] = {'reg': {'Removed': remove_change}}
ret['comment'] = r'Removed {0} from {1}\{2}'.format(name, hive, key)
ret['comment'] = r'Removed {0} from {1}'.format(key, hive)
return ret

View file

@ -954,6 +954,9 @@ def deploy_windows(host,
newtimeout = timeout - (time.mktime(time.localtime()) - starttime)
smb_conn = salt.utils.smb.get_conn(host, username, password)
if smb_conn is False:
log.error('Please install impacket to enable SMB functionality')
return False
creds = "-U '{0}%{1}' //{2}".format(
username, password, host)

View file

@ -47,6 +47,9 @@ def get_conn(host=None, username=None, password=None):
'''
Get an SMB connection
'''
if not HAS_IMPACKET:
return False
conn = impacket.smbconnection.SMBConnection(
remoteName='*SMBSERVER',
remoteHost=host,
@ -65,6 +68,9 @@ def mkdirs(path, share='C$', conn=None, host=None, username=None, password=None)
if conn is None:
conn = get_conn(host, username, password)
if conn is False:
return False
comps = path.split('/')
pos = 1
for comp in comps:
@ -85,5 +91,8 @@ def put_str(content, path, share='C$', conn=None, host=None, username=None, pass
if conn is None:
conn = get_conn(host, username, password)
if conn is False:
return False
fh_ = StrHandle(content)
conn.putFile(share, path, fh_.string)

View file

@ -510,3 +510,11 @@ def safe_py_code(code):
if code.count(bad):
return False
return True
def verify_log(opts):
'''
If an insecre logging configuration is found, show a warning
'''
if opts.get('log_level') in ('garbage', 'trace', 'debug'):
log.warn('Insecure logging configuration detected! Sensitive data may be logged.')

View file

@ -70,7 +70,7 @@ class WinPathTestCase(TestCase):
Test to Returns the system path
'''
mock = MagicMock(return_value={'vdata': 'c:\\salt'})
with patch.dict(win_path.__salt__, {'reg.read_key': mock}):
with patch.dict(win_path.__salt__, {'reg.read_value': mock}):
self.assertListEqual(win_path.get_path(), ['c:\\salt'])
def test_exists(self):

View file

@ -80,34 +80,37 @@ class RegTestCase(TestCase):
'''
Test to remove a registry entry.
'''
name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt'
hive = 'HKEY_CURRENT_USER'
key = 'SOFTWARE\\Salt'
name = hive + '\\' + key
vname = 'version'
vdata = '0.15.3'
ret = {'name': name,
'changes': {},
'result': True,
'comment': '{0} is already absent'.format(name)}
mock_read = MagicMock(side_effect=[{'success': False},
{'success': False},
{'success': True},
{'success': True}])
mock_read_true = MagicMock(return_value={'success': True, 'vdata': vdata})
mock_read_false = MagicMock(return_value={'success': False, 'vdata': False})
mock_t = MagicMock(return_value=True)
with patch.dict(reg.__salt__, {'reg.read_value': mock_read,
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_false,
'reg.delete_value': mock_t}):
self.assertDictEqual(reg.absent(name, vname), ret)
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_true}):
with patch.dict(reg.__opts__, {'test': True}):
ret.update({'comment': '', 'result': None,
'changes': {'reg': {'Will remove': {'Entry': vname,
'Key': name}}}})
'changes': {'reg': {'Will remove': {'Entry': vname, 'Key': name}}}})
self.assertDictEqual(reg.absent(name, vname), ret)
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_true,
'reg.delete_value': mock_t}):
with patch.dict(reg.__opts__, {'test': False}):
ret.update({'result': True,
'changes': {'reg': {'Removed': {'Entry': vname,
'Key': name}}},
'comment': 'Removed {0} from {0}'.format(name)})
'changes': {'reg': {'Removed': {'Entry': vname, 'Key': name}}},
'comment': 'Removed {0} from {1}'.format(key, hive)})
self.assertDictEqual(reg.absent(name, vname), ret)