Merge branch '2015.2' into 2015.2-develop

This commit is contained in:
Erik Johnson 2015-03-10 17:47:30 -05:00
commit d25677e954
49 changed files with 98922 additions and 32569 deletions

View file

@ -147,11 +147,11 @@ intersphinx_mapping = {
# -- General Configuration -----------------------------------------------------
project = 'Salt'
copyright = '2014 SaltStack, Inc.'
copyright = '2015 SaltStack, Inc.'
version = salt.version.__version__
#release = '.'.join(map(str, salt.version.__version_info__))
release = '2014.7.2'
release = '2015.2'
needs_sphinx = '1.3'

View file

@ -1,8 +1,8 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-API" "1" "April 05, 2014" "0.8.3" "salt-api"
.TH "SALT-API" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-api \- salt-api
salt-api \- salt-api Command
.
.nr rst2man-indent-level 0
.
@ -65,6 +65,6 @@ Specify an alternative location for the salt master configuration file.
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2012, Thomas S. Hatch
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CALL" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-CALL" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-call \- salt-call Documentation
.
@ -178,6 +178,16 @@ Disable all colored output
.TP
.B \-\-force\-color
Force colored output
.sp
\fBNOTE:\fP
.INDENT 7.0
.INDENT 3.5
When using colored output the color codes are as follows:
.sp
\fBgreen\fP denotes success, \fBred\fP denotes failure, \fBblue\fP denotes
changes and success and \fByellow\fP denotes a expected future change in configuration.
.UNINDENT
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
@ -187,6 +197,6 @@ Force colored output
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CLOUD" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-CLOUD" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-cloud \- Salt Cloud Command
.
@ -72,7 +72,7 @@ must be defined in the specified profiles file.
.B \-m MAP, \-\-map=MAP
Specify a map file to use. If used without any other options, this option
will ensure that all of the mapped VMs are created. If VM names are
also passed as arguments, they will be used to filter the map file.
also passed as arguments, they will be used to filter the map file.
If the named VM already exists then it will be skipped.
.UNINDENT
.INDENT 0.0
@ -126,6 +126,21 @@ specified map.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-list\-providers
Display a list of configured providers.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-list\-profiles
New in version 2014.7.0.
.sp
Display a list of configured profiles. Pass in a cloud provider to view
the provider\(aqs associated profiles, such as \fBdigital_ocean\fP, or pass in
\fBall\fP to list all the configured profiles.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-list\-images
Display a list of images available in configured cloud providers.
Pass the cloud provider that available images are desired on, aka
@ -166,18 +181,11 @@ an executing python script with eval.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-text\-out
Print the output from the salt command in the same form the shell would.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-yaml\-out
Print the output from the salt command in yaml.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-json\-out
Print the output from the salt command in json.
.B \-\-out=OUTPUT, \-\-output=OUTPUT
Print the output from the salt\-cloud command using the specified outputter. The
builtins are \(aqraw\(aq, \(aqcompact\(aq, \(aqno_return\(aq, \(aqgrains\(aq, \(aqoverstatestage\(aq, \(aqpprint\(aq,
\(aqjson\(aq, \(aqnested\(aq, \(aqyaml\(aq, \(aqhighstate\(aq, \(aqquiet\(aq, \(aqkey\(aq, \(aqtxt\(aq, \(aqnewline_values_only\(aq,
\(aqvirt_query\(aq.
.UNINDENT
.INDENT 0.0
.TP
@ -186,7 +194,7 @@ Disable all colored output.
.UNINDENT
.SH EXAMPLES
.sp
To create 4 VMs named web1, web2, db1 and db2 from specified profiles:
To create 4 VMs named web1, web2, db1, and db2 from specified profiles:
.INDENT 0.0
.INDENT 3.5
.sp
@ -266,6 +274,6 @@ salt\-cloud \-m /path/to/cloud.map \-Q
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CP" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-CP" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-cp \- salt-cp Documentation
.
@ -158,6 +158,6 @@ file.
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-KEY" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-KEY" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-key \- salt-key Documentation
.
@ -31,8 +31,16 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt\-key [ options ]
.ft P
.fi
.UNINDENT
.UNINDENT
.SH DESCRIPTION
.sp
Salt\-key executes simple management of Salt server public keys used for
@ -136,6 +144,16 @@ Disable all colored output
.TP
.B \-\-force\-color
Force colored output
.sp
\fBNOTE:\fP
.INDENT 7.0
.INDENT 3.5
When using colored output the color codes are as follows:
.sp
\fBgreen\fP denotes success, \fBred\fP denotes failure, \fBblue\fP denotes
changes and success and \fByellow\fP denotes a expected future change in configuration.
.UNINDENT
.UNINDENT
.UNINDENT
.SS Actions
.INDENT 0.0
@ -214,14 +232,12 @@ Print all keys\(aq fingerprints.
.B \-\-gen\-keys=GEN_KEYS
Set a name to generate a keypair for use with salt
.UNINDENT
.INDENT 0.0
.TP
.B \-\-gen\-keys\-dir=GEN_KEYS_DIR
Set the directory to save the generated keypair. Only works
with \(aqgen_keys_dir\(aq option; default is the current directory.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-keysize=KEYSIZE
@ -230,78 +246,6 @@ the \(aq\-\-gen\-keys\(aq option, the key size must be 2048 or
higher, otherwise it will be rounded up to 2048. The
default is 2048.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-gen-signature
Generate the signature file named master_pubkey_signature for the
salt-masters public key. The signatur itself can be send to the
minions in auth-replies and enables the minions to verify
the salt-masters public-key cryptographically. This requires a new
signing-key-pair which can be auto-created with the --auto-create
parameter.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-signature-path
Target path for the signature file (must already exist)
.UNINDENT
.INDENT 0.0
.TP
.B \-\-auto-create
Auto-Create a signing key-pair if it does not yet exist
.UNINDENT
.INDENT 0.0
.TP
.B \-\-pub=PUB
The path to the public-key file to generate a signature for
.UNINDENT
.INDENT 0.0
.TP
.B \-\-priv=PRIV
The path to the private-key file to generate a signature with
.UNINDENT
Example which will auto-create a default master_sign.* key-pair and
a signature file named master_pubkey_signature for an already
existing master.pub key
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt-key --gen-signature --auto-create
.ft P
.fi
.UNINDENT
.UNINDENT
Example which will auto-create a new key-pair called signature.* and the
signature itself for an already existing master.pub
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt-key --gen-signature --auto-create --key-pair signature
.UNINDENT
.UNINDENT
.ft P
.fi
Example with specific pub- and private key-files which creates the signature for
the given public key
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt-key --gen-signature --pub /etc/salt/pki/master/master.pub --priv /root/signature.pem
.ft P
.fi
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
\fIsalt(7)\fP
@ -310,6 +254,6 @@ salt-key --gen-signature --pub /etc/salt/pki/master/master.pub --priv /root/sign
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MASTER" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-MASTER" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-master \- salt-master Documentation
.
@ -33,8 +33,16 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.sp
The Salt master daemon, used to control the Salt minions
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt\-master [ options ]
.ft P
.fi
.UNINDENT
.UNINDENT
.SH DESCRIPTION
.sp
The master daemon controls the Salt minions
@ -106,6 +114,6 @@ Logfile logging log level. One of \fBall\fP, \fBgarbage\fP, \fBtrace\fP,
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MINION" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-MINION" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-minion \- salt-minion Documentation
.
@ -33,8 +33,16 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.sp
The Salt minion daemon, receives commands from a remote Salt master.
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt\-minion [ options ]
.ft P
.fi
.UNINDENT
.UNINDENT
.SH DESCRIPTION
.sp
The Salt minion receives commands from the central Salt master and replies with
@ -107,6 +115,6 @@ Logfile logging log level. One of \fBall\fP, \fBgarbage\fP, \fBtrace\fP,
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-RUN" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-RUN" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-run \- salt-run Documentation
.
@ -114,6 +114,6 @@ Logfile logging log level. One of \fBall\fP, \fBgarbage\fP, \fBtrace\fP,
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SSH" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-SSH" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-ssh \- salt-ssh Documentation
.
@ -33,9 +33,14 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
salt\-ssh \(aq*\(aq [ options ] sys.doc
.sp
.nf
.ft C
salt\-ssh \(aq*\(aq [ options ] sys.doc
salt\-ssh \-E \(aq.*\(aq [ options ] sys.doc cmd
.ft P
.fi
.UNINDENT
.UNINDENT
.SH DESCRIPTION
@ -49,9 +54,24 @@ Execute a raw shell command.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-roster\-file
.B \-\-priv
Specify the SSH private key file to be used for authentication.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-roster
Define which roster system to use, this defines if a database backend,
scanner, or custom roster system is used. Default is the flat file roster.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-roster\-file
Define an alternative location for the default roster file location. The
default roster file is called \fBroster\fP and is found in the same directory
as the master config file.
.sp
New in version 2014.1.0.
.UNINDENT
.INDENT 0.0
.TP
@ -70,8 +90,14 @@ is 25.
.UNINDENT
.INDENT 0.0
.TP
.B \-i, \-\-ignore\-host\-keys
Ignore the ssh host keys which by default are honored and connections
would ask for approval.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-passwd
Set te default password to attempt to use when authenticating.
Set the default password to attempt to use when authenticating.
.UNINDENT
.INDENT 0.0
.TP
@ -222,6 +248,16 @@ Disable all colored output
.TP
.B \-\-force\-color
Force colored output
.sp
\fBNOTE:\fP
.INDENT 7.0
.INDENT 3.5
When using colored output the color codes are as follows:
.sp
\fBgreen\fP denotes success, \fBred\fP denotes failure, \fBblue\fP denotes
changes and success and \fByellow\fP denotes a expected future change in configuration.
.UNINDENT
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
@ -231,6 +267,6 @@ Force colored output
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SYNDIC" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT-SYNDIC" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-syndic \- salt-syndic Documentation
.
@ -34,8 +34,16 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
The Salt syndic daemon, a special minion that passes through commands from a
higher master
.SH SYNOPSIS
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
salt\-syndic [ options ]
.ft P
.fi
.UNINDENT
.UNINDENT
.SH DESCRIPTION
.sp
The Salt syndic daemon, a special minion that passes through commands from a
@ -108,6 +116,6 @@ Logfile logging log level. One of \fBall\fP, \fBgarbage\fP, \fBtrace\fP,
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-UNITY" "1" "September 13, 2014" "2014.7.0rc1-587-g80369db" "Salt"
.TH "SALT-UNITY" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt-unity \- salt-unity Command
.
@ -64,6 +64,6 @@ invokes that script.
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2014 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "1" "January 02, 2014" "2014.1.0" "Salt"
.TH "SALT" "1" "March 09, 2015" "2015.2.0rc1-133-g24fa806" "Salt"
.SH NAME
salt \- salt
.
@ -88,7 +88,7 @@ timeout and after all minions have returned then use the static option.
.INDENT 0.0
.TP
.B \-\-async
Instead of waiting for the job to run on minions only print the jod id of
Instead of waiting for the job to run on minions only print the job id of
the started execution and complete.
.UNINDENT
.INDENT 0.0
@ -97,8 +97,8 @@ the started execution and complete.
New in version 0.17.
.sp
Override the configured state_output value for minion output. Default:
full
Choose the format of the state output. The options are \fIfull\fP,
\fIterse\fP, \fImixed\fP, \fIchanges\fP, and \fIfilter\fP\&. Default: full
.UNINDENT
.INDENT 0.0
.TP
@ -115,6 +115,12 @@ print out extra data like the job id.
.UNINDENT
.INDENT 0.0
.TP
.B \-\-hide\-timeout
Instead of showing the return data for all minions. This option
prints only the online minions which could be reached.
.UNINDENT
.INDENT 0.0
.TP
.B \-b BATCH, \-\-batch\-size=BATCH
Instead of executing on all targeted minions at once, execute on a
progressive set of minions. This option takes an argument in the form of
@ -125,7 +131,9 @@ minions to execute on.
.TP
.B \-a EAUTH, \-\-auth=EAUTH
Pass in an external authentication medium to validate against. The
credentials will be prompted for. Can be used with the \-T option.
credentials will be prompted for. The options are \fIauto\fP,
\fIkeystone\fP, \fIldap\fP, \fIpam\fP, and \fIstormpath\fP\&. Can be used with the \-T
option.
.UNINDENT
.INDENT 0.0
.TP
@ -137,9 +145,13 @@ re\-authenticate.
.INDENT 0.0
.TP
.B \-\-return=RETURNER
Chose an alternative returner to call on the minion, if an alternative
returner is used then the return will not come back to the command line
but will be sent to the specified return system.
Choose an alternative returner to call on the minion, if an
alternative returner is used then the return will not come back to
the command line but will be sent to the specified return system.
The options are \fIcarbon\fP, \fIcassandra\fP, \fIcouchbase\fP, \fIcouchdb\fP,
\fIelasticsearch\fP, \fIetcd\fP, \fIhipchat\fP, \fIlocal\fP, \fIlocal_cache\fP,
\fImemcache\fP, \fImongo\fP, \fImysql\fP, \fIodbc\fP, \fIpostgres\fP, \fIredis\fP,
\fIsentry\fP, \fIslack\fP, \fIsms\fP, \fIsmtp\fP, \fIsqlite3\fP, \fIsyslog\fP, and \fIxmpp\fP\&.
.UNINDENT
.INDENT 0.0
.TP
@ -233,11 +245,6 @@ Make sure that the compound target is encapsulated in quotes.
.UNINDENT
.INDENT 0.0
.TP
.B \-X, \-\-exsel
Instead of using shell globs, use the return code of a function.
.UNINDENT
.INDENT 0.0
.TP
.B \-I, \-\-pillar
Instead of using shell globs to evaluate the target, use a pillar value to
identify targets. The syntax for the target is the pillar key followed by
@ -299,6 +306,16 @@ Disable all colored output
.TP
.B \-\-force\-color
Force colored output
.sp
\fBNOTE:\fP
.INDENT 7.0
.INDENT 3.5
When using colored output the color codes are as follows:
.sp
\fBgreen\fP denotes success, \fBred\fP denotes failure, \fBblue\fP denotes
changes and success and \fByellow\fP denotes a expected future change in configuration.
.UNINDENT
.UNINDENT
.UNINDENT
.SH SEE ALSO
.sp
@ -308,6 +325,6 @@ Force colored output
.SH AUTHOR
Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file
.SH COPYRIGHT
2013 SaltStack, Inc.
2015 SaltStack, Inc.
.\" Generated by docutils manpage writer.
.

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,8 @@ Misc Fixes/Additions
configuration. This change was necessitated upstream by the 7.0+ API.
- Add ``args`` argument to ``cmd.script_retcode`` to match ``cmd.script`` in
the :py:mod:`cmd module <salt.cmd.cmdmod>`. (:issue:`21122`)
- Fixed bug where TCP keepalive was not being sent on the defined interval on
the return port (4506) from minion to master. (:issue: `21465`)
Deprecations
============

View file

@ -130,6 +130,7 @@ class Master(parsers.MasterOptionParser):
self.master = salt.daemons.flo.IofloMaster(self.config)
self.daemonize_if_required()
self.set_pidfile()
salt.utils.process.notify_systemd()
def start(self):
'''

View file

@ -1391,8 +1391,7 @@ class LocalClient(object):
if not os.path.exists(os.path.join(self.opts['sock_dir'],
'publish_pull.ipc')):
log.error(
'Unable to connect to the publisher! '
'You do not have permissions to access '
'Unable to connect to the salt master publisher at '
'{0}'.format(self.opts['sock_dir'])
)
return {'jid': '0', 'minions': []}

View file

@ -22,6 +22,7 @@ import salt.transport
from salt.utils.error import raise_error
from salt.utils.event import tagify
from salt.utils.doc import strip_rst as _strip_rst
from salt.utils.lazy import verify_fun
# Import 3rd-party libs
import salt.ext.six as six
@ -72,9 +73,9 @@ class ClientFuncsDict(collections.MutableMapping):
}
pub_data = {}
# pull out pub_data if you have it
for k, v in six.iteritems(dict(kwargs)):
if k.startswith('__pub_'):
pub_data[k] = kwargs.pop(k)
for kwargs_key, kwargs_value in six.iteritems(kwargs):
if kwargs_key.startswith('__pub_'):
pub_data[kwargs_key] = kwargs.pop(kwargs_key)
async_pub = self.client._gen_async_pub(pub_data.get('__pub_jid'))
@ -109,17 +110,6 @@ class SyncClientMixin(object):
'''
return ClientFuncsDict(self)
def _verify_fun(self, fun):
'''
Check that the function passed really exists
'''
if not fun:
err = 'Must specify a function to run'
raise salt.exceptions.CommandExecutionError(err)
if fun not in self.functions:
err = 'Function {0!r} is unavailable'.format(fun)
raise salt.exceptions.CommandExecutionError(err)
def master_call(self, **kwargs):
'''
Execute a function through the master network interface.
@ -257,6 +247,7 @@ class SyncClientMixin(object):
'jid': jid,
'user': low.get('__user__', 'UNKNOWN'),
}
event = salt.utils.event.get_event(
'master',
self.opts['sock_dir'],
@ -267,25 +258,27 @@ class SyncClientMixin(object):
namespaced_event = salt.utils.event.NamespacedEvent(
event,
tag,
print_func=self.print_async_event if hasattr(self, 'print_async_event') else None
print_func=self.print_async_event
if hasattr(self, 'print_async_event')
else None
)
# TODO: document these, and test that they exist
# TODO: Other things to inject??
func_globals = {'__jid__': jid,
'__user__': data['user'],
'__tag__': tag,
# weak ref to avoid the Exception in interpreter teardown
# of event
# weak ref to avoid the Exception in interpreter
# teardown of event
'__jid_event__': weakref.proxy(namespaced_event),
}
func_globals['__jid_event__'].fire_event(data, 'new')
try:
self._verify_fun(fun)
verify_fun(self.functions, fun)
# Inject some useful globals to *all* the funciton's global namespace
# only once per module-- not per func
# Inject some useful globals to *all* the funciton's global
# namespace only once per module-- not per func
completed_funcs = []
for mod_name in six.iterkeys(self.functions):
mod, _ = mod_name.split('.', 1)
@ -295,23 +288,31 @@ class SyncClientMixin(object):
for global_key, value in six.iteritems(func_globals):
self.functions[mod_name].__globals__[global_key] = value
# There are some descrepencies of what a "low" structure is
# in the publisher world it is a dict including stuff such as jid,
# fun, arg (a list of args, with kwargs packed in). Historically
# this particular one has had no "arg" and just has had all the
# kwargs packed into the top level object. The plan is to move away
# from that since the caller knows what is an arg vs a kwarg, but
# while we make the transition we will load "kwargs" using format_call
# if there are no kwargs in the low object passed in
# There are some descrepencies of what a "low" structure is in the
# publisher world it is a dict including stuff such as jid, fun,
# arg (a list of args, with kwargs packed in). Historically this
# particular one has had no "arg" and just has had all the kwargs
# packed into the top level object. The plan is to move away from
# that since the caller knows what is an arg vs a kwarg, but while
# we make the transition we will load "kwargs" using format_call if
# there are no kwargs in the low object passed in
f_call = None
if 'args' not in low:
f_call = salt.utils.format_call(self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS)
f_call = salt.utils.format_call(
self.functions[fun],
low,
expected_extra_kws=CLIENT_INTERNAL_KEYWORDS
)
args = f_call.get('args', ())
else:
args = low['args']
if 'kwargs' not in low:
if f_call is None:
f_call = salt.utils.format_call(self.functions[fun], low, expected_extra_kws=CLIENT_INTERNAL_KEYWORDS)
f_call = salt.utils.format_call(
self.functions[fun],
low,
expected_extra_kws=CLIENT_INTERNAL_KEYWORDS
)
kwargs = f_call.get('kwargs', {})
# throw a warning for the badly formed low data if we found
@ -439,21 +440,17 @@ class AsyncClientMixin(object):
return
# some suffixes we don't want to print
if suffix in ('new', ):
if suffix in ('new',):
return
# TODO: clean up this event print out. We probably want something
# more general, since this will get *really* messy as
# people use more events that don't quite fit into this mold
if suffix == 'ret': # for "ret" just print out return
if isinstance(event['return'], dict):
outputter = event['return'].pop('outputter', None)
else:
outputter = None
salt.output.display_output(event['return'], outputter, self.opts)
elif isinstance(event, dict) and 'outputter' in event and event['outputter'] is not None:
print(self.outputters[event['outputter']](event['data']))
# otherwise fall back on basic printing
# Check if ouputter was passed in the return data. If this is the case,
# then the return data will be a dict two keys: 'data' and 'outputter'
if isinstance(event['return'], dict) \
and set(event['return']) == set(('data', 'outputter')):
event_data = event['return']['data']
outputter = event['return']['outputter']
else:
print('{tag}: {event}'.format(tag=suffix,
event=event))
event_data = event['return']
outputter = None
salt.output.display_output(event_data, outputter, self.opts)

View file

@ -1893,14 +1893,13 @@ def _dir_list_gitpython(repo, tgt_env):
tree = tree / repo['root']
except KeyError:
return ret
relpath = lambda path: os.path.relpath(path, repo['root'])
add_mountpoint = lambda path: os.path.join(repo['mountpoint'], path)
for blob in tree.traverse():
if not isinstance(blob, git.Tree):
continue
if repo['root']:
path = os.path.relpath(blob.path, repo['root'])
else:
path = blob.path
ret.add(os.path.join(repo['mountpoint'], path))
if isinstance(blob, git.Tree):
ret.add(add_mountpoint(relpath(blob.path)))
if repo['mountpoint']:
ret.add(repo['mountpoint'])
return ret
@ -1940,10 +1939,12 @@ def _dir_list_pygit2(repo, tgt_env):
blobs = []
if len(tree):
_traverse(tree, repo['repo'], blobs, repo['root'])
relpath = lambda path: os.path.relpath(path, repo['root'])
add_mountpoint = lambda path: os.path.join(repo['mountpoint'], path)
for blob in blobs:
if repo['root']:
blob = os.path.relpath(blob, repo['root'])
ret.add(os.path.join(repo['mountpoint'], blob))
ret.add(add_mountpoint(relpath(blob)))
if repo['mountpoint']:
ret.add(repo['mountpoint'])
return ret
@ -1976,10 +1977,12 @@ def _dir_list_dulwich(repo, tgt_env):
blobs = []
if len(tree):
_traverse(tree, repo['repo'], blobs, repo['root'])
relpath = lambda path: os.path.relpath(path, repo['root'])
add_mountpoint = lambda path: os.path.join(repo['mountpoint'], path)
for blob in blobs:
if repo['root']:
blob = os.path.relpath(blob, repo['root'])
ret.add(os.path.join(repo['mountpoint'], blob))
ret.add(add_mountpoint(relpath(blob)))
if repo['mountpoint']:
ret.add(repo['mountpoint'])
return ret

View file

@ -877,4 +877,6 @@ def _get_dir_list(load):
ret.add(os.path.join(repo['mountpoint'], relpath))
split = split[0].rsplit('/', 1)
repo['repo'].close()
if repo['mountpoint']:
ret.add(repo['mountpoint'])
return sorted(ret)

View file

@ -734,6 +734,8 @@ def _file_lists(load, form):
env_root
)
ret['files'].add(os.path.join(repo['mountpoint'], rel_fn))
if repo['mountpoint']:
ret['dirs'].add(repo['mountpoint'])
# Convert all compiled sets to lists
for key in ret:
ret[key] = sorted(ret[key])

View file

@ -486,9 +486,11 @@ def _virtual(osdata):
else:
# /proc/bus/pci does not exists, lspci will fail
if not os.path.exists('/proc/bus/pci'):
_cmds = (['dmidecode', 'dmesg'])
_cmds = ('dmidecode', 'dmesg', 'systemd-detect-virt', 'virt-what')
else:
_cmds = (['dmidecode', 'lspci', 'dmesg'])
_cmds = ('dmidecode', 'lspci', 'dmesg',
'systemd-detect-virt', 'virt-what')
failed_commands = set()
for command in _cmds:
args = []
@ -527,7 +529,35 @@ def _virtual(osdata):
grains['virtual'] = 'VirtualBox'
# Break out of the loop so the next log message is not issued
break
elif command == 'systemd-detect-virt':
if output in ('qemu', 'kvm', 'oracle', 'xen', 'bochs', 'chroot', 'uml', 'systemd-nspawn'):
grains['virtual'] = output
break
elif 'vmware' in output:
grains['virtual'] = 'VMWare'
break
elif 'microsoft' in output:
grains['virtual'] = 'VirtualPC'
break
elif 'lxc' in output:
grains['virtual'] = 'LXC'
break
elif 'systemd-nspawn' in output:
grains['virtual'] = 'LXC'
break
elif command == 'virt-what':
if output in ('kvm', 'qemu', 'uml', 'xen'):
grains['virtual'] = output
break
elif 'vmware' in output:
grains['virtual'] = 'VMWare'
break
elif 'parallels' in output:
grains['virtual'] = 'Parallels'
break
elif 'hyperv' in output:
grains['virtual'] = 'HyperV'
break
elif command == 'dmidecode' or command == 'dmesg':
# Product Name: VirtualBox
if 'Vendor: QEMU' in output:
@ -560,6 +590,8 @@ def _virtual(osdata):
# Manufacturer: Parallels Software International Inc.
elif 'Parallels Software' in output:
grains['virtual'] = 'Parallels'
elif 'Manufacturer: Google' in output:
grains['virtual'] = 'kvm'
# Break out of the loop, lspci parsing is not necessary
break
elif command == 'lspci':

View file

@ -28,6 +28,8 @@ from salt.ext.six.moves import range
from stat import S_IMODE
from stat import S_IMODE
# Import third party libs
try:
import zmq
@ -254,7 +256,8 @@ def load_args_and_kwargs(func, args, data=None):
# **kwargs not in argspec and parsed argument name not in
# list of positional arguments. This keyword argument is
# invalid.
invalid_kwargs.append('{0}'.format(arg))
for key, val in string_kwarg.iteritems():
invalid_kwargs.append('{0}={1}'.format(key, val))
continue
# if the arg is a dict with __kwarg__ == True, then its a kwarg
@ -268,7 +271,7 @@ def load_args_and_kwargs(func, args, data=None):
# **kwargs not in argspec and parsed argument name not in
# list of positional arguments. This keyword argument is
# invalid.
invalid_kwargs.append('{0}'.format(arg))
invalid_kwargs.append('{0}={1}'.format(key, val))
continue
else:

View file

@ -582,11 +582,10 @@ def _parse_interfaces(interface_files=None):
attr, valuestr = line.rstrip().split(None, 1)
if _attrmaps_contain_attr(attr):
_attr = DEBIAN_ATTR_TO_SALT_ATTR_MAP.get(attr, attr)
if '-' in _attr:
attrname = _attr.replace('-', '_')
if '-' in attr:
attrname = attr.replace('-', '_')
else:
attrname = _attr
attrname = attr
(valid, value, errmsg) = _validate_interface_option(
attr, valuestr, addrfam)
iface_dict[attrname] = value
@ -1201,12 +1200,14 @@ def _parse_settings_eth(opts, iface_type, enabled, iface):
if iface_type == 'bridge':
bridging = _parse_bridge_opts(opts, iface)
if bridging:
opts.pop('mode', None)
iface_data['inet']['bridging'] = bridging
iface_data['inet']['bridging_keys'] = sorted(bridging)
elif iface_type == 'bond':
bonding = _parse_settings_bond(opts, iface)
if bonding:
opts.pop('mode', None)
iface_data['inet']['bonding'] = bonding
iface_data['inet']['bonding']['slaves'] = opts['slaves']
iface_data['inet']['bonding_keys'] = sorted(bonding)
@ -1440,9 +1441,9 @@ def _write_file_ifaces(iface, data, **settings):
for adapter in adapters:
if 'type' in adapters[adapter] and adapters[adapter]['type'] == 'slave':
# Override values so the interfaces file is correct
adapters[adapter]['enabled'] = False
adapters[adapter]['data']['inet']['addrfam'] = 'inet'
adapters[adapter]['data']['inet']['proto'] = 'manual'
adapters[adapter]['data']['inet']['master'] = adapters[adapter]['master']
if 'type' in adapters[adapter] and adapters[adapter]['type'] == 'source':
tmp = source_template.render({'name': adapter, 'data': adapters[adapter]})

View file

@ -223,7 +223,12 @@ def blkid(device=None):
args = " " + device
ret = {}
for line in __salt__['cmd.run_stdout']('blkid' + args, python_shell=False).split('\n'):
blkid_result = __salt__['cmd.run_all']('blkid' + args, python_shell=False)
if blkid_result['retcode'] > 0:
return ret
for line in blkid_result['stdout'].splitlines():
if not line:
continue
comps = line.split()

View file

@ -190,7 +190,7 @@ def pull(cwd, opts=None, user=None, identity=None, repository=None):
cmd.append(opt)
if repository is not None:
cmd.append(repository)
return __salt__['cmd.run'](cmd, cwd=cwd, runas=user, python_shell=False, use_vt=True)
return __salt__['cmd.run'](cmd, cwd=cwd, runas=user, python_shell=False, use_vt=not utils.is_windows())
def update(cwd, rev, force=False, user=None):
@ -257,4 +257,4 @@ def clone(cwd, repository, opts=None, user=None, identity=None):
cmd.append('{0}'.format(opt))
if identity:
cmd.append(_ssh_flag(identity))
return __salt__['cmd.run'](cmd, runas=user, python_shell=False, use_vt=True)
return __salt__['cmd.run'](cmd, runas=user, python_shell=False, use_vt=not utils.is_windows())

View file

@ -30,6 +30,12 @@ from salt.ext.six import string_types
from salt.ext.six.moves.urllib.error import URLError
# pylint: enable=import-error,no-name-in-module
# Fix a nasty bug with Win32 Python not supporting all of the standard signals
try:
salt_SIGKILL = signal.SIGKILL
except AttributeError:
salt_SIGKILL = signal.SIGTERM
# Import salt libs
import salt
import salt.payload
@ -608,7 +614,9 @@ def kill_job(jid):
salt '*' saltutil.kill_job <job id>
'''
return signal_job(jid, signal.SIGKILL)
# Some OS's (Win32) don't have SIGKILL, so use salt_SIGKILL which is set to
# an appropriate value for the operating system this is running on.
return signal_job(jid, salt_SIGKILL)
def regen_keys():

View file

@ -706,7 +706,8 @@ def get_known_host(user, hostname, config=None):
return full
cmd = 'ssh-keygen -F "{0}" -f "{1}"'.format(hostname, full)
lines = __salt__['cmd.run'](cmd, python_shell=False).splitlines()
lines = __salt__['cmd.run'](cmd, ignore_retcode=True,
python_shell=False).splitlines()
known_hosts = list(_parse_openssh_output(lines))
return known_hosts[0] if known_hosts else None

View file

@ -374,8 +374,7 @@ def not_loaded():
'''
prov = providers()
ret = set()
loader = salt.loader._create_loader(__opts__, 'modules', 'module')
for mod_dir in loader.module_dirs:
for mod_dir in salt.loader._module_dirs(__opts__, 'modules', 'module'):
if not os.path.isabs(mod_dir):
continue
if not os.path.isdir(mod_dir):

View file

@ -4,14 +4,19 @@ Module for returning various status data about a minion.
These data can be useful for compiling into stats later,
or for problem solving if your minion is having problems.
.. versionadded:: 0.12.0
:depends: - pythoncom
- wmi
'''
from __future__ import absolute_import
import subprocess
import logging
import salt.utils
import salt.ext.six as six
import salt.utils.event
from salt.utils.network import host_to_ip as _host_to_ip
import os
import ctypes
@ -48,7 +53,9 @@ def __virtual__():
def cpuload():
'''
Return the processor load as a percentage.
.. versionadded:: Beryllium
Return the processor load as a percentage
CLI Example:
@ -57,38 +64,42 @@ def cpuload():
salt '*' status.cpu_load
'''
#pull in the information from WMIC
# Pull in the information from WMIC
cmd = list2cmdline(['wmic', 'cpu'])
info = __salt__['cmd.run'](cmd).split('\r\n')
#find the location of LoadPercentage
# Find the location of LoadPercentage
column = info[0].index('LoadPercentage')
#get the end of the number.
# Get the end of the number.
end = info[1].index(' ', column+1)
#return pull it out of the informatin and cast it to an int.
# Return pull it out of the informatin and cast it to an int
return int(info[1][column:end])
def diskusage(human_readable=False, path=None):
'''
return the disk usage for this minion
.. versionadded:: Beryllium
Return the disk usage for this minion
human_readable : False
If ``True``, usage will be in KB/MB/GB etc.
CLI Example:
.. code-block:: bash
salt '*' status.disk_usage path=c:/salt
'''
if not path:
path = 'c:/'
#Credit for the source and ideas for this function:
# Credit for the source and ideas for this function:
# http://code.activestate.com/recipes/577972-disk-usage/?in=user-4178764
_, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), ctypes.c_longlong()
_, total, free = \
ctypes.c_ulonglong(), ctypes.c_ulonglong(), ctypes.c_longlong()
if sys.version_info >= (3, ) or isinstance(path, six.text_type):
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExw
else:
@ -98,19 +109,26 @@ def diskusage(human_readable=False, path=None):
raise ctypes.WinError()
used = total.value - free.value
total_val = total.value
used_val = used
free_val = free.value
if human_readable:
tstr = _byte_calc(total.value)
ustr = _byte_calc(used)
fstr = _byte_calc(free.value)
return 'Total: {0}, Used: {1}, Free: {2}'.format(tstr, ustr, fstr)
else:
return {'total': total.value, 'used': used, 'free': free.value}
total_val = _byte_calc(total_val)
used_val = _byte_calc(used_val)
free_val = _byte_calc(free_val)
return {'total': total_val, 'used': used_val, 'free': free_val}
def procs(count=False):
'''
Return the process data
for quick use, the argument count tells you how many processes there are.
count : False
If ``True``, this function will simply return the number of processes.
.. versionadded:: Beryllium
CLI Example:
@ -137,20 +155,26 @@ def procs(count=False):
def saltmem(human_readable=False):
'''
Returns the amount of memory that salt is using.
.. versionadded:: Beryllium
human_readable: return the value in a nicely formated number.
Returns the amount of memory that salt is using
human_readable : False
return the value in a nicely formated number
CLI Example:
.. code-black:: bash
salt '*' status.salt_mem
salt '*' status.salt_mem human_readable
salt '*' status.salt_mem human_readable=True
'''
with salt.utils.winapi.Com():
wmi_obj = wmi.WMI()
result = wmi_obj.query('SELECT WorkingSet FROM Win32_PerfRawData_PerfProc_Process WHERE IDProcess={0}'.format(os.getpid()))
result = wmi_obj.query(
'SELECT WorkingSet FROM Win32_PerfRawData_PerfProc_Process '
'WHERE IDProcess={0}'.format(os.getpid())
)
mem = int(result[0].wmi_property('WorkingSet').value)
if human_readable:
return _byte_calc(mem)
@ -159,42 +183,46 @@ def saltmem(human_readable=False):
def uptime(human_readable=False):
'''
.. versionadded:: Beryllium
Return the system uptime for this machine in seconds
human_readable translates the seconds into something a little
easier to understand, but not necessarily useful to a machine.
human_readable : False
If ``True``, then the number of seconds will be translated into years,
months, days, etc.
CLI Example:
.. code-block:: bash
salt '*' status.uptime
salt '*' status.uptime human_readable
salt '*' status.uptime human_readable=True
'''
#open up a subprocess to get information from WMIC
# Open up a subprocess to get information from WMIC
cmd = list2cmdline(['net', 'stats', 'srv'])
outs = __salt__['cmd.run'](cmd)
#get the line that has when the computer started in it:
# Get the line that has when the computer started in it:
stats_line = ''
for line in outs.split('\r\n'):
if "Statistics since" in line:
stats_line = line
#extract the time string from the line and parse
#get string
# Extract the time string from the line and parse
#
# Get string
startup_time = stats_line[len('Statistics Since '):]
#convert to struct
# Convert to struct
startup_time = time.strptime(startup_time, '%d/%m/%Y %H:%M:%S')
#convert to seconds since epoch
# eonvert to seconds since epoch
startup_time = time.mktime(startup_time)
#subtract startup time from current time to get the uptime of the system.
# Subtract startup time from current time to get the uptime of the system
uptime = time.time() - startup_time
if human_readable:
#pull out the majority of the uptime tuple. h:m:s
# Pull out the majority of the uptime tuple. h:m:s
uptime = int(uptime)
seconds = uptime % 60
uptime /= 60
@ -203,14 +231,15 @@ def uptime(human_readable=False):
hours = uptime % 24
uptime /= 24
#translate the h:m:s from above into HH:MM:SS format.
# Translate the h:m:s from above into HH:MM:SS format.
ret = '{0:0>2}:{1:0>2}:{2:0>2}'.format(hours, minutes, seconds)
#If the minion has been on for days, add that in.
# If the minion has been on for days, add that in.
if uptime > 0:
ret = 'Days: {0} {1}'.format(uptime % 365, ret)
#if you have a Windows minion that has been up for years, my hat is off to you sir.
# If you have a Windows minion that has been up for years,
# my hat is off to you sir.
if uptime > 365:
ret = 'Years: {0} {1}'.format(uptime / 365, ret)
@ -260,7 +289,7 @@ def _byte_calc(val):
if val < 1024:
tstr = str(val)+'B'
elif val < 1038336:
tstr = str(val/1024)+'kB'
tstr = str(val/1024)+'KB'
elif val < 1073741824:
tstr = str(val/1038336)+'MB'
elif val < 1099511627776:
@ -268,3 +297,85 @@ def _byte_calc(val):
else:
tstr = str(val/1099511627776)+'TB'
return tstr
def master(master=None, connected=True):
'''
Fire an event if the minion gets disconnected from its master. This
function is meant to be run via a scheduled job from the minion. If
master_ip is an FQDN/Hostname, is must be resolvable to a valid IPv4
address.
CLI Example:
.. code-block:: bash
salt '*' status.master
'''
def _win_remotes_on(port):
'''
Windows specific helper function.
Returns set of ipv4 host addresses of remote established connections
on local or remote tcp port.
Parses output of shell 'netstat' to get connections
PS C:> netstat -n -p TCP
Active Connections
Proto Local Address Foreign Address State
TCP 10.1.1.26:3389 10.1.1.1:4505 ESTABLISHED
TCP 10.1.1.26:56862 10.1.1.10:49155 TIME_WAIT
TCP 10.1.1.26:56868 169.254.169.254:80 CLOSE_WAIT
TCP 127.0.0.1:49197 127.0.0.1:49198 ESTABLISHED
TCP 127.0.0.1:49198 127.0.0.1:49197 ESTABLISHED
'''
remotes = set()
try:
data = subprocess.check_output(['netstat', '-n', '-p', 'TCP'])
except subprocess.CalledProcessError:
log.error('Failed netstat')
raise
lines = data.split('\n')
for line in lines:
if 'ESTABLISHED' not in line:
continue
chunks = line.split()
remote_host, remote_port = chunks[2].rsplit(':', 1)
if int(remote_port) != port:
continue
remotes.add(remote_host)
return remotes
# the default publishing port
port = 4505
master_ip = None
if __salt__['config.get']('publish_port') != '':
port = int(__salt__['config.get']('publish_port'))
# Check if we have FQDN/hostname defined as master
# address and try resolving it first. _remote_port_tcp
# only works with IP-addresses.
if master is not None:
tmp_ip = _host_to_ip(master)
if tmp_ip is not None:
master_ip = tmp_ip
ips = _win_remotes_on(port)
if connected:
if master_ip not in ips:
event = salt.utils.event.get_event(
'minion', opts=__opts__, listen=False
)
event.fire_event({'master': master}, '__master_disconnected')
else:
if master_ip in ips:
event = salt.utils.event.get_event(
'minion', opts=__opts__, listen=False
)
event.fire_event({'master': master}, '__master_connected')

View file

@ -15,6 +15,7 @@ import salt.utils.args
import salt.utils.event
from salt.client import mixins
from salt.output import display_output
from salt.utils.lazy import verify_fun
log = logging.getLogger(__name__)
@ -131,16 +132,13 @@ class Runner(RunnerClient):
if self.opts.get('doc', False):
self.print_docs()
else:
low = {'fun': self.opts['fun']}
try:
low = {'fun': self.opts['fun']}
if low['fun'] in self.functions:
args, kwargs = salt.minion.load_args_and_kwargs(
self.functions[low['fun']],
salt.utils.args.parse_input(self.opts['arg']),
)
else:
print('\'{0}\' is not available.'.format(low['fun']))
return
verify_fun(self.functions, low['fun'])
args, kwargs = salt.minion.load_args_and_kwargs(
self.functions[low['fun']],
salt.utils.args.parse_input(self.opts['arg']),
)
low['args'] = args
low['kwargs'] = kwargs
@ -159,16 +157,15 @@ class Runner(RunnerClient):
# otherwise run it in the main process
async_pub = self._gen_async_pub()
ret = self._proc_function(self.opts['fun'],
low,
user,
async_pub['tag'],
async_pub['jid'],
False, # Don't daemonize
)
low,
user,
async_pub['tag'],
async_pub['jid'],
False) # Don't daemonize
except salt.exceptions.SaltException as exc:
ret = str(exc)
ret = '{0}'.format(exc)
if not self.opts.get('quiet', False):
print(ret)
display_output(ret, 'nested', self.opts)
return ret
log.debug('Runner return: {0}'.format(ret))
return ret

View file

@ -8,15 +8,13 @@ import logging
# Import salt libs
import salt.log
import salt.utils
import salt.utils.master
import salt.payload
from salt.ext.six import string_types
log = logging.getLogger(__name__)
DEPRECATION_WARNING = ("The 'minion' arg will be removed from "
"cache.py runner. Specify minion with 'tgt' arg!")
def grains(tgt=None, expr_form='glob', outputter=None, **kwargs):
'''
@ -30,10 +28,14 @@ def grains(tgt=None, expr_form='glob', outputter=None, **kwargs):
'''
deprecated_minion = kwargs.get('minion', None)
if tgt is None and deprecated_minion is None:
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
tgt = '*' # targat all minions for backward compatibility
elif tgt is None and isinstance(deprecated_minion, string_types):
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
salt.utils.warn_until(
'Boron',
'The \'minion\' argument to the cache.grains runner is '
'deprecated. Please specify the minion using the \'tgt\' '
'argument.'
)
tgt = deprecated_minion
elif tgt is None:
return {}
@ -43,6 +45,12 @@ def grains(tgt=None, expr_form='glob', outputter=None, **kwargs):
opts=__opts__)
cached_grains = pillar_util.get_minion_grains()
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the cache.grains runner has '
'been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': cached_grains}
else:
return cached_grains
@ -60,10 +68,14 @@ def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs):
'''
deprecated_minion = kwargs.get('minion', None)
if tgt is None and deprecated_minion is None:
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
tgt = '*' # targat all minions for backward compatibility
elif tgt is None and isinstance(deprecated_minion, string_types):
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
salt.utils.warn_until(
'Boron',
'The \'minion\' argument to the cache.pillar runner is '
'deprecated. Please specify the minion using the \'tgt\' '
'argument.'
)
tgt = deprecated_minion
elif tgt is None:
return {}
@ -75,6 +87,12 @@ def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs):
opts=__opts__)
cached_pillar = pillar_util.get_minion_pillar()
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the cache.pillar runner has '
'been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': cached_pillar}
else:
return cached_pillar
@ -92,10 +110,14 @@ def mine(tgt=None, expr_form='glob', outputter=None, **kwargs):
'''
deprecated_minion = kwargs.get('minion', None)
if tgt is None and deprecated_minion is None:
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
tgt = '*' # targat all minions for backward compatibility
elif tgt is None and isinstance(deprecated_minion, string_types):
log.warn("DEPRECATION WARNING: {0}".format(DEPRECATION_WARNING))
salt.utils.warn_until(
'Boron',
'The \'minion\' argument to the cache.mine runner is '
'deprecated. Please specify the minion using the \'tgt\' '
'argument.'
)
tgt = deprecated_minion
elif tgt is None:
return {}
@ -107,6 +129,12 @@ def mine(tgt=None, expr_form='glob', outputter=None, **kwargs):
opts=__opts__)
cached_mine = pillar_util.get_cached_mine_data()
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the cache.mine runner has '
'been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': cached_mine}
else:
return cached_mine

View file

@ -5,10 +5,11 @@ Directly manage the Salt fileserver plugins
from __future__ import absolute_import
# Import Salt libs
import salt.utils
import salt.fileserver
def envs(backend=None, sources=False, outputter='nested'):
def envs(backend=None, sources=False, outputter=None):
'''
Return the available fileserver environments. If no backend is provided,
then the environments for all configured backends will be returned.
@ -32,7 +33,6 @@ def envs(backend=None, sources=False, outputter='nested'):
.. code-block:: bash
salt-run fileserver.envs
salt-run fileserver.envs outputter=nested
salt-run fileserver.envs backend=roots,git
salt-run fileserver.envs git
'''
@ -40,12 +40,18 @@ def envs(backend=None, sources=False, outputter='nested'):
output = fileserver.envs(back=backend, sources=sources)
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the fileserver.envs runner has '
'been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': output}
else:
return output
def file_list(saltenv='base', backend=None, outputter='nested'):
def file_list(saltenv='base', backend=None, outputter=None):
'''
Return a list of files from the salt fileserver
@ -77,11 +83,18 @@ def file_list(saltenv='base', backend=None, outputter='nested'):
output = fileserver.file_list(load=load)
if outputter:
salt.output.display_output(output, outputter, opts=__opts__)
return output
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the fileserver.file_list runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': output}
else:
return output
def symlink_list(saltenv='base', backend=None, outputter='nested'):
def symlink_list(saltenv='base', backend=None, outputter=None):
'''
Return a list of symlinked files and dirs
@ -113,12 +126,18 @@ def symlink_list(saltenv='base', backend=None, outputter='nested'):
output = fileserver.symlink_list(load=load)
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the fileserver.symlink_list '
'runner has been deprecated. Please specify an outputter using '
'--out. See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': output}
else:
return output
def dir_list(saltenv='base', backend=None, outputter='nested'):
def dir_list(saltenv='base', backend=None, outputter=None):
'''
Return a list of directories in the given environment
@ -150,11 +169,18 @@ def dir_list(saltenv='base', backend=None, outputter='nested'):
output = fileserver.dir_list(load=load)
if outputter:
salt.output.display_output(output, outputter, opts=__opts__)
return output
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the fileserver.dir_list runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': output}
else:
return output
def empty_dir_list(saltenv='base', backend=None, outputter='nested'):
def empty_dir_list(saltenv='base', backend=None, outputter=None):
'''
.. versionadded:: 2015.2.0
@ -191,8 +217,15 @@ def empty_dir_list(saltenv='base', backend=None, outputter='nested'):
output = fileserver.file_list_emptydirs(load=load)
if outputter:
salt.output.display_output(output, outputter, opts=__opts__)
return output
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the fileserver.empty_dir_list '
'runner has been deprecated. Please specify an outputter using '
'--out. See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': output}
else:
return output
def update(backend=None):

View file

@ -61,6 +61,12 @@ def active(outputter=None, display_progress=False):
ret[jid]['Returned'].append(minion)
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the jobs.active runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': ret}
else:
return ret
@ -84,11 +90,6 @@ def lookup_jid(jid,
When set to `True`, adds the minions that did not return from the command.
Default: `False`.
outputter
The outputter to use. Default: `None`.
.. versionadded:: 2015.2.0
display_progress
Displays progress events when set to `True`. Default: `False`.
@ -111,6 +112,7 @@ def lookup_jid(jid,
data = mminion.returners['{0}.get_jid'.format(returner)](jid)
except TypeError:
return 'Requested returner could not be loaded. No JIDs could be retrieved.'
for minion in data:
if display_progress:
__jid_event__.fire_event({'message': minion}, 'progress')
@ -124,6 +126,25 @@ def lookup_jid(jid,
for minion_id in exp:
if minion_id not in data:
ret[minion_id] = 'Minion did not return'
# Once we remove the outputter argument in a couple releases, we still
# need to check to see if the 'out' key is present and use it to specify
# the correct outputter, so we get highstate output for highstate runs.
if outputter is None:
try:
# Check if the return data has an 'out' key. We'll use that as the
# outputter in the absence of one being passed on the CLI.
outputter = data[next(iter(data))].get('out')
except (StopIteration, AttributeError):
outputter = None
else:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the jobs.lookup_jid runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
if outputter:
return {'outputter': outputter, 'data': ret}
else:
@ -148,6 +169,12 @@ def list_job(jid, ext_source=None, outputter=None):
ret.update(_format_jid_instance(jid, job))
ret['Result'] = mminion.returners['{0}.get_jid'.format(returner)](jid)
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the jobs.list_job runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': ret}
else:
return ret
@ -249,6 +276,12 @@ def print_job(jid, ext_source=None, outputter=None):
return ret
ret[jid]['Result'] = mminion.returners['{0}.get_jid'.format(returner)](jid)
if outputter:
salt.utils.warn_until(
'Boron',
'The \'outputter\' argument to the jobs.print_job runner '
'has been deprecated. Please specify an outputter using --out. '
'See the output of \'salt-run -h\' for more information.'
)
return {'outputter': outputter, 'data': ret}
else:
return ret

View file

@ -26,11 +26,11 @@ Management of Keystone users
- password: R00T_4CC3SS
- email: admin@domain.com
- roles:
- admin: # tenants
- admin # roles
- service:
- admin
- Member
admin: # tenants
- admin # roles
service:
- admin
- Member
- require:
- keystone: Keystone tenants
- keystone: Keystone roles
@ -41,8 +41,8 @@ Management of Keystone users
- email: nova@domain.com
- tenant: service
- roles:
- service:
- admin
service:
- admin
- require:
- keystone: Keystone tenants
- keystone: Keystone roles
@ -53,8 +53,8 @@ Management of Keystone users
- email: demo@domain.com
- tenant: demo
- roles:
- demo:
- Member
demo:
- Member
- require:
- keystone: Keystone tenants
- keystone: Keystone roles
@ -173,11 +173,11 @@ def user_present(name,
ret['comment'] = 'User "{0}" has been updated'.format(name)
ret['changes']['Password'] = 'Updated'
if roles:
for tenant_role in roles[0]:
for tenant_role in roles:
args = dict({'user_name': name, 'tenant_name':
tenant_role, 'profile': profile}, **connection_args)
tenant_roles = __salt__['keystone.user_role_list'](**args)
for role in roles[0][tenant_role]:
for role in roles[tenant_role]:
if role not in tenant_roles:
if __opts__['test']:
ret['result'] = None
@ -185,7 +185,7 @@ def user_present(name,
ret['changes']['roles'].append(role)
else:
ret['changes']['roles'] = [role]
return ret
continue
addargs = dict({'user': name, 'role': role,
'tenant': tenant_role,
'profile': profile},
@ -195,6 +195,24 @@ def user_present(name,
ret['changes']['roles'].append(newrole)
else:
ret['changes']['roles'] = [newrole]
roles_to_remove = list(set(tenant_roles) - set(roles[tenant_role]))
for role in roles_to_remove:
if __opts__['test']:
ret['result'] = None
if 'roles' in ret['changes']:
ret['changes']['roles'].append(role)
else:
ret['changes']['roles'] = [role]
continue
addargs = dict({'user': name, 'role': role,
'tenant': tenant_role,
'profile': profile},
**connection_args)
oldrole = __salt__['keystone.user_role_remove'](**addargs)
if 'roles' in ret['changes']:
ret['changes']['roles'].append(oldrole)
else:
ret['changes']['roles'] = [oldrole]
else:
# Create that user!
if __opts__['test']:
@ -210,8 +228,8 @@ def user_present(name,
profile=profile,
**connection_args)
if roles:
for tenant_role in roles[0]:
for role in roles[0][tenant_role]:
for tenant_role in roles:
for role in roles[tenant_role]:
__salt__['keystone.user_role_add'](user=name,
role=role,
tenant=tenant_role,

View file

@ -172,6 +172,8 @@ def mounted(name,
device_list = []
if real_name in active:
if 'superopts' not in active[real_name]:
active[real_name]['superopts'] = []
if mount:
device_list.append(active[real_name]['device'])
device_list.append(os.path.realpath(device_list[0]))

View file

@ -91,11 +91,13 @@ all interfaces are ignored unless specified.
eth2:
network.managed:
- enabled: True
- type: slave
- master: bond0
eth3:
network.managed:
- enabled: True
- type: slave
- master: bond0
@ -111,18 +113,17 @@ all interfaces are ignored unless specified.
- type: bond
- ipaddr: 10.1.0.1
- netmask: 255.255.255.0
- mode: active-backup
- proto: static
- dns:
- 8.8.8.8
- 8.8.4.4
- ipv6:
- enabled: False
- use_in:
- network: eth2
- network: eth3
- slaves: eth2 eth3
- require:
- network: eth2
- network: eth3
- mode: 802.3ad
- miimon: 100
- arp_interval: 250
- downdelay: 200

View file

@ -73,10 +73,7 @@ def _enable(name, started, result=True, **kwargs):
'''
Enable the service
'''
ret = {'name': name,
'changes': {},
'result': result,
'comment': ''}
ret = {}
# is service available?
if not _available(name, ret):
@ -87,16 +84,14 @@ def _enable(name, started, result=True, **kwargs):
if started is True:
ret['comment'] = ('Enable is not available on this minion,'
' service {0} started').format(name)
return ret
elif started is None:
ret['comment'] = ('Enable is not available on this minion,'
' service {0} is in the desired state'
).format(name)
return ret
else:
ret['comment'] = ('Enable is not available on this minion,'
' service {0} is dead').format(name)
return ret
return ret
# Service can be enabled
if __salt__['service.enabled'](name, **kwargs):
@ -104,15 +99,13 @@ def _enable(name, started, result=True, **kwargs):
if started is True:
ret['comment'] = ('Service {0} is already enabled,'
' and is running').format(name)
return ret
elif started is None:
ret['comment'] = ('Service {0} is already enabled,'
' and is in the desired state').format(name)
return ret
else:
ret['comment'] = ('Service {0} is already enabled,'
' and is dead').format(name)
return ret
return ret
# Service needs to be enabled
if __opts__['test']:
@ -122,49 +115,40 @@ def _enable(name, started, result=True, **kwargs):
if __salt__['service.enable'](name, **kwargs):
# Service has been enabled
ret['changes'] = {}
ret['changes'][name] = True
if started is True:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been enabled,'
' and is running').format(name)
return ret
elif started is None:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been enabled,'
' and is in the desired state').format(name)
return ret
else:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been enabled,'
' and is dead').format(name)
return ret
return ret
# Service failed to be enabled
if started is True:
ret['changes'][name] = True
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to start at boot,'
' but the service is running').format(name)
return ret
elif started is None:
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to start at boot,'
' but the service was already running').format(name)
return ret
else:
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to start at boot,'
' and the service is dead').format(name)
return ret
return ret
def _disable(name, started, result=True, **kwargs):
'''
Disable the service
'''
ret = {'name': name,
'changes': {},
'result': result,
'comment': ''}
ret = {}
# is service available?
if not _available(name, ret):
@ -176,33 +160,28 @@ def _disable(name, started, result=True, **kwargs):
if started is True:
ret['comment'] = ('Disable is not available on this minion,'
' service {0} started').format(name)
return ret
elif started is None:
ret['comment'] = ('Disable is not available on this minion,'
' service {0} is in the desired state'
).format(name)
return ret
else:
ret['comment'] = ('Disable is not available on this minion,'
' service {0} is dead').format(name)
return ret
return ret
# Service can be disabled
if __salt__['service.disabled'](name):
# Service is disabled
if started is True:
ret['changes'][name] = True
ret['comment'] = ('Service {0} is already disabled,'
' and is running').format(name)
return ret
elif started is None:
ret['comment'] = ('Service {0} is already disabled,'
' and is in the desired state').format(name)
return ret
else:
ret['comment'] = ('Service {0} is already disabled,'
' and is dead').format(name)
return ret
return ret
# Service needs to be disabled
if __opts__['test']:
@ -212,40 +191,33 @@ def _disable(name, started, result=True, **kwargs):
if __salt__['service.disable'](name, **kwargs):
# Service has been disabled
ret['changes'] = {}
ret['changes'][name] = True
if started is True:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been disabled,'
' and is running').format(name)
return ret
elif started is None:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been disabled,'
' and is in the desired state').format(name)
return ret
else:
ret['changes'][name] = True
ret['comment'] = ('Service {0} has been disabled,'
' and is dead').format(name)
return ret
return ret
# Service failed to be disabled
ret['result'] = False
if started is True:
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to not start'
' at boot, and is running').format(name)
return ret
elif started is None:
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to not start'
' at boot, but the service was already running'
).format(name)
return ret
else:
ret['changes'][name] = True
ret['result'] = False
ret['comment'] = ('Failed when setting service {0} to not start'
' at boot, and the service is dead').format(name)
return ret
return ret
def _available(name, ret):
@ -280,11 +252,11 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs):
init_delay
Some services may not be truly available for a short period after their
startup script indicates to the system that they are. Provide an 'init_delay'
to specify that this state should wait an additional given number of seconds
after a service has started before returning. Useful for requisite states
wherein a dependent state might assume a service has started but is not yet
fully initialized.
startup script indicates to the system that they are. Provide an
'init_delay' to specify that this state should wait an additional given
number of seconds after a service has started before returning. Useful
for requisite states wherein a dependent state might assume a service
has started but is not yet fully initialized.
'''
ret = {'name': name,
'changes': {},
@ -303,9 +275,11 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs):
if __salt__['service.status'](name, sig):
ret['comment'] = 'The service {0} is already running'.format(name)
if enable is True:
return _enable(name, None, **kwargs)
ret.update(_enable(name, None, **kwargs))
return ret
elif enable is False:
return _disable(name, None, **kwargs)
ret.update(_disable(name, None, **kwargs))
return ret
else:
return ret
@ -315,31 +289,29 @@ def running(name, enable=None, sig=None, init_delay=None, **kwargs):
ret['comment'] = 'Service {0} is set to start'.format(name)
return ret
changes = {name: __salt__['service.start'](name)}
ret['changes'] = {name: __salt__['service.start'](name)}
if not changes[name]:
if not ret['changes'][name]:
ret['result'] = False
ret['comment'] = 'Service {0} failed to start'.format(name)
if enable is True:
return _enable(name, False, result=False, **kwargs)
ret.update(_enable(name, False, result=False, **kwargs))
elif enable is False:
return _disable(name, False, result=False, **kwargs)
else:
ret['result'] = False
ret['comment'] = 'Service {0} failed to start'.format(name)
return ret
ret.update(_disable(name, False, result=False, **kwargs))
else:
ret['comment'] = 'Started Service {0}'.format(name)
if enable is True:
ret.update(_enable(name, True, **kwargs))
elif enable is False:
ret.update(_disable(name, True, **kwargs))
if init_delay:
time.sleep(init_delay)
if enable is True:
return _enable(name, True, **kwargs)
elif enable is False:
return _disable(name, True, **kwargs)
else:
ret['changes'] = changes
ret['comment'] = 'Started Service {0}'.format(name)
if init_delay:
ret['changes'] = '{0}\nDelayed return for {1} seconds'.format(ret['commant'], init_delay)
return ret
ret['changes'] = (
'{0}\nDelayed return for {1} seconds'
.format(ret['commant'], init_delay)
)
return ret
def dead(name, enable=None, sig=None, **kwargs):
@ -374,11 +346,10 @@ def dead(name, enable=None, sig=None, **kwargs):
if not __salt__['service.status'](name, sig):
ret['comment'] = 'The service {0} is already dead'.format(name)
if enable is True:
return _enable(name, None, **kwargs)
ret.update(_enable(name, None, **kwargs))
elif enable is False:
return _disable(name, None, **kwargs)
else:
return ret
ret.update(_disable(name, None, **kwargs))
return ret
if __opts__['test']:
ret['result'] = None
@ -391,21 +362,16 @@ def dead(name, enable=None, sig=None, **kwargs):
ret['result'] = False
ret['comment'] = 'Service {0} failed to die'.format(name)
if enable is True:
return _enable(name, True, result=False)
ret.update(_enable(name, True, result=False, **kwargs))
elif enable is False:
return _disable(name, True, result=False)
else:
ret['result'] = False
ret['comment'] = 'Service {0} failed to die'.format(name)
return ret
ret.update(_disable(name, True, result=False, **kwargs))
else:
ret['comment'] = 'Service {0} was killed'.format(name)
if enable is True:
return _enable(name, False)
ret.update(_enable(name, False, **kwargs))
elif enable is False:
return _disable(name, False)
else:
ret['comment'] = 'Service {0} was killed'.format(name)
return ret
ret.update(_disable(name, False, **kwargs))
return ret
def enabled(name, **kwargs):
@ -418,7 +384,13 @@ def enabled(name, **kwargs):
name
The name of the init or rc script used to manage the service
'''
return _enable(name, None, **kwargs)
ret = {'name': name,
'changes': {},
'result': True,
'comment': ''}
ret.update(_enable(name, None, **kwargs))
return ret
def disabled(name, **kwargs):
@ -431,7 +403,13 @@ def disabled(name, **kwargs):
name
The name of the init or rc script used to manage the service
'''
return _disable(name, None, **kwargs)
ret = {'name': name,
'changes': {},
'result': True,
'comment': ''}
ret.update(_disable(name, None, **kwargs))
return ret
def mod_watch(name,

View file

@ -412,7 +412,7 @@ def absent(name,
fullkey = sshre.search(name)
# if it is {key} [comment]
if not fullkey:
key_and_comment = name.split()
key_and_comment = name.split(None, 1)
name = key_and_comment[0]
if len(key_and_comment) == 2:
comment = key_and_comment[1]

View file

@ -88,22 +88,16 @@ def present(
comment = 'Specify either "key" or "fingerprint", not both.'
ret['result'] = False
return dict(ret, comment=comment)
elif key:
if not enc:
comment = 'Required argument "enc" if using "key" argument.'
ret['result'] = False
return dict(ret, comment=comment)
result = __salt__['ssh.check_known_host'](user, name,
key=key,
config=config)
elif fingerprint:
result = __salt__['ssh.check_known_host'](user, name,
fingerprint=fingerprint,
config=config)
else:
comment = 'Arguments key or fingerprint required.'
elif key and not enc:
comment = 'Required argument "enc" if using "key" argument.'
ret['result'] = False
return dict(ret, comment=comment)
result = __salt__['ssh.check_known_host'](user, name,
key=key,
fingerprint=fingerprint,
config=config)
if result == 'exists':
comment = 'Host {0} is already in {1}'.format(name, config)
ret['result'] = True
@ -162,7 +156,7 @@ def absent(name, user=None, config=None):
'''
ret = {'name': name,
'changes': {},
'result': None if __opts__['test'] else True,
'result': True,
'comment': ''}
if not user:
@ -182,6 +176,7 @@ def absent(name, user=None, config=None):
if __opts__['test']:
comment = 'Key for {0} is set to be removed from {1}'.format(name,
config)
ret['result'] = None
return dict(ret, comment=comment)
rm_result = __salt__['ssh.rm_known_host'](user=user, hostname=name, config=config)

View file

@ -16,6 +16,9 @@ from __future__ import absolute_import
# Import python libs
import re
# Import salt libs
from salt.exceptions import CommandExecutionError
def __virtual__():
'''
@ -59,48 +62,67 @@ def present(name, value, config=None):
if not configured:
ret['result'] = None
ret['comment'] = (
'Sysctl option {0} might be changed, we failed to check config file at {1}.\n'
'The file is either unreadable, or missing.').format(name, config)
'Sysctl option {0} might be changed, we failed to check '
'config file at {1}. The file is either unreadable, or '
'missing.'.format(name, config)
)
return ret
if name in current and name not in configured:
if re.sub(' +|\t+', ' ', current[name]) != re.sub(' +|\t+', ' ', str(value)):
if re.sub(' +|\t+', ' ', current[name]) != \
re.sub(' +|\t+', ' ', str(value)):
ret['result'] = None
ret['comment'] = (
'Sysctl option {0} set to be changed to {1}'
).format(name, value)
'Sysctl option {0} set to be changed to {1}'
.format(name, value)
)
return ret
else:
ret['result'] = None
ret['comment'] = 'Sysctl value is currently set on the running system but not in a config file.\n'\
'Sysctl option {0} set to be changed to {1} in config file.'.format(name, value)
ret['comment'] = (
'Sysctl value is currently set on the running system but '
'not in a config file. Sysctl option {0} set to be '
'changed to {1} in config file.'.format(name, value)
)
return ret
elif name in configured and name not in current:
ret['result'] = None
ret['comment'] = 'Sysctl value {0} is present in configuration file but is not present in the running config.\n'\
'The value {0} is set to be changed to {1} '
ret['comment'] = (
'Sysctl value {0} is present in configuration file but is not '
'present in the running config. The value {0} is set to be '
'changed to {1}'.format(name, value)
)
return ret
elif name in configured and name in current:
if str(value).split() == __salt__['sysctl.get'](name).split():
ret['result'] = True
ret['comment'] = 'Sysctl value {0} = {1} is already set'.format(
name,
value
)
ret['comment'] = (
'Sysctl value {0} = {1} is already set'
.format(name, value)
)
return ret
# otherwise, we don't have it set anywhere and need to set it
ret['result'] = None
ret['comment'] = 'Sysctl option {0} set to be changed to {1}'.format(name, value)
ret['comment'] = (
'Sysctl option {0} would be changed to {1}'.format(name, value)
)
return ret
update = __salt__['sysctl.persist'](name, value, config)
try:
update = __salt__['sysctl.persist'](name, value, config)
except CommandExecutionError as exc:
ret['result'] = False
ret['comment'] = (
'Failed to set {0} to {1}: {2}'.format(name, value, exc)
)
return ret
if update == 'Updated':
ret['changes'] = {name: value}
ret['comment'] = 'Updated sysctl value {0} = {1}'.format(name, value)
elif update == 'Already set':
ret['comment'] = 'Sysctl value {0} = {1} is already set'.format(
name,
value
)
ret['comment'] = (
'Sysctl value {0} = {1} is already set'
.format(name, value)
)
return ret

View file

@ -30,6 +30,7 @@
{%endif%}{% if interface.provider %} provider {{interface.provider}}
{%endif%}{% if interface.unit %} unit {{interface.unit}}
{%endif%}{% if interface.options %} options {{interface.options}}
{%endif%}{% if interface.master %} bond_master {{interface.master}}
{%endif%}{% if interface.dns_nameservers %} dns-nameservers {%for item in interface.dns_nameservers %}{{item}} {%endfor%}
{%endif%}{% if interface.dns_search %} dns-search {% for item in interface.dns_search %}{{item}} {%endfor%}
{%endif%}{% if interface.ethtool %}{%for item in interface.ethtool_keys %} {{item}} {{interface.ethtool[item]}}

View file

@ -995,7 +995,7 @@ def deploy_script(host,
if not isinstance(opts, dict):
opts = {}
tmp_dir = '{0}-{1}'.format(tmp_dir, uuid.uuid4())
tmp_dir = '{0}-{1}'.format(tmp_dir.rstrip('/'), uuid.uuid4())
deploy_command = os.path.join(tmp_dir, 'deploy.sh')
if key_filename is not None and not os.path.isfile(key_filename):
raise SaltCloudConfigError(
@ -1048,10 +1048,10 @@ def deploy_script(host,
log.debug('Using {0} as the password'.format(password))
ssh_kwargs['password'] = password
if root_cmd('test -e \\"{0}\\"'.format(tmp_dir), tty, sudo,
if root_cmd('test -e \'{0}\''.format(tmp_dir), tty, sudo,
allow_failure=True, **ssh_kwargs):
ret = root_cmd(('sh -c "( mkdir -p \\"{0}\\" &&'
' chmod 700 \\"{0}\\" )"').format(tmp_dir),
ret = root_cmd(('sh -c "( mkdir -p \'{0}\' &&'
' chmod 700 \'{0}\' )"').format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
raise SaltCloudSystemExit(
@ -1063,7 +1063,7 @@ def deploy_script(host,
if len(comps) > 0:
if len(comps) > 1 or comps[0] != 'tmp':
ret = root_cmd(
'chown {0}. {1}'.format(username, tmp_dir),
'chown {0}. \'{1}\''.format(username, tmp_dir),
tty, sudo, **ssh_kwargs
)
if ret:
@ -1092,7 +1092,7 @@ def deploy_script(host,
continue
remote_dir = os.path.dirname(remote_file)
if remote_dir not in remote_dirs:
root_cmd('mkdir -p {0}'.format(remote_dir), tty, sudo, **ssh_kwargs)
root_cmd('mkdir -p \'{0}\''.format(remote_dir), tty, sudo, **ssh_kwargs)
remote_dirs.append(remote_dir)
sftp_file(
remote_file, kwargs=ssh_kwargs, local_file=local_file
@ -1102,7 +1102,7 @@ def deploy_script(host,
# Minion configuration
if minion_pem:
sftp_file('{0}/minion.pem'.format(tmp_dir), minion_pem, ssh_kwargs)
ret = root_cmd('chmod 600 {0}/minion.pem'.format(tmp_dir),
ret = root_cmd('chmod 600 \'{0}/minion.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
raise SaltCloudSystemExit(
@ -1135,7 +1135,7 @@ def deploy_script(host,
# Master configuration
if master_pem:
sftp_file('{0}/master.pem'.format(tmp_dir), master_pem, ssh_kwargs)
ret = root_cmd('chmod 600 {0}/master.pem'.format(tmp_dir),
ret = root_cmd('chmod 600 \'{0}/master.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
raise SaltCloudSystemExit(
@ -1166,14 +1166,14 @@ def deploy_script(host,
if preseed_minion_keys is not None:
# Create remote temp dir
ret = root_cmd(
'mkdir "{0}"'.format(preseed_minion_keys_tempdir),
'mkdir \'{0}\''.format(preseed_minion_keys_tempdir),
tty, sudo, **ssh_kwargs
)
if ret:
raise SaltCloudSystemExit(
'Cant create {0}'.format(preseed_minion_keys_tempdir))
ret = root_cmd(
'chmod 700 "{0}"'.format(preseed_minion_keys_tempdir),
'chmod 700 \'{0}\''.format(preseed_minion_keys_tempdir),
tty, sudo, **ssh_kwargs
)
if ret:
@ -1182,7 +1182,7 @@ def deploy_script(host,
preseed_minion_keys_tempdir))
if ssh_kwargs['username'] != 'root':
root_cmd(
'chown {0} "{1}"'.format(
'chown {0} \'{1}\''.format(
ssh_kwargs['username'], preseed_minion_keys_tempdir
),
tty, sudo, **ssh_kwargs
@ -1197,7 +1197,7 @@ def deploy_script(host,
if ssh_kwargs['username'] != 'root':
root_cmd(
'chown -R root "{0}"'.format(
'chown -R root \'{0}\''.format(
preseed_minion_keys_tempdir
),
tty, sudo, **ssh_kwargs
@ -1213,7 +1213,7 @@ def deploy_script(host,
# subshell fixes that
sftp_file('{0}/deploy.sh'.format(tmp_dir), script, ssh_kwargs)
ret = root_cmd(
('sh -c "( chmod +x \\"{0}/deploy.sh\\" )";'
('sh -c "( chmod +x \'{0}/deploy.sh\' )";'
'exit $?').format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
@ -1240,7 +1240,7 @@ def deploy_script(host,
# Run the deploy script
if script:
if 'bootstrap-salt' in script:
deploy_command += ' -c {0}'.format(tmp_dir)
deploy_command += ' -c \'{0}\''.format(tmp_dir)
if make_syndic is True:
deploy_command += ' -S'
if make_master is True:
@ -1250,7 +1250,7 @@ def deploy_script(host,
if keep_tmp is True:
deploy_command += ' -K'
if preseed_minion_keys is not None:
deploy_command += ' -k {0}'.format(
deploy_command += ' -k \'{0}\''.format(
preseed_minion_keys_tempdir
)
if script_args:
@ -1279,11 +1279,11 @@ def deploy_script(host,
ssh_kwargs
)
root_cmd(
'chmod +x {0}/environ-deploy-wrapper.sh'.format(tmp_dir),
'chmod +x \'{0}/environ-deploy-wrapper.sh\''.format(tmp_dir),
tty, sudo, **ssh_kwargs
)
# The deploy command is now our wrapper
deploy_command = '{0}/environ-deploy-wrapper.sh'.format(
deploy_command = '\'{0}/environ-deploy-wrapper.sh\''.format(
tmp_dir,
)
if root_cmd(deploy_command, tty, sudo, **ssh_kwargs) != 0:
@ -1296,12 +1296,12 @@ def deploy_script(host,
# Remove the deploy script
if not keep_tmp:
root_cmd('rm -f {0}/deploy.sh'.format(tmp_dir),
root_cmd('rm -f \'{0}/deploy.sh\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/deploy.sh'.format(tmp_dir))
if script_env:
root_cmd(
'rm -f {0}/environ-deploy-wrapper.sh'.format(
'rm -f \'{0}/environ-deploy-wrapper.sh\''.format(
tmp_dir
),
tty, sudo, **ssh_kwargs
@ -1319,39 +1319,39 @@ def deploy_script(host,
else:
# Remove minion configuration
if minion_pub:
root_cmd('rm -f {0}/minion.pub'.format(tmp_dir),
root_cmd('rm -f \'{0}/minion.pub\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/minion.pub'.format(tmp_dir))
if minion_pem:
root_cmd('rm -f {0}/minion.pem'.format(tmp_dir),
root_cmd('rm -f \'{0}/minion.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/minion.pem'.format(tmp_dir))
if minion_conf:
root_cmd('rm -f {0}/grains'.format(tmp_dir),
root_cmd('rm -f \'{0}/grains\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/grains'.format(tmp_dir))
root_cmd('rm -f {0}/minion'.format(tmp_dir),
root_cmd('rm -f \'{0}/minion\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/minion'.format(tmp_dir))
# Remove master configuration
if master_pub:
root_cmd('rm -f {0}/master.pub'.format(tmp_dir),
root_cmd('rm -f \'{0}/master.pub\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/master.pub'.format(tmp_dir))
if master_pem:
root_cmd('rm -f {0}/master.pem'.format(tmp_dir),
root_cmd('rm -f \'{0}/master.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/master.pem'.format(tmp_dir))
if master_conf:
root_cmd('rm -f {0}/master'.format(tmp_dir),
root_cmd('rm -f \'{0}/master\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
log.debug('Removed {0}/master'.format(tmp_dir))
# Remove pre-seed keys directory
if preseed_minion_keys is not None:
root_cmd(
'rm -rf {0}'.format(
'rm -rf \'{0}\''.format(
preseed_minion_keys_tempdir
), tty, sudo, **ssh_kwargs
)

View file

@ -4,10 +4,30 @@
from __future__ import absolute_import
import logging
import collections
import salt.exceptions
log = logging.getLogger(__name__)
def verify_fun(lazy_obj, fun):
'''
Check that the function passed really exists
'''
if not fun:
raise salt.exceptions.SaltInvocationError(
'Must specify a function to run!\n'
'ex: salt-run manage.up'
)
if fun not in lazy_obj:
try:
lazy_obj[fun]
except KeyError:
# Runner function not found in the LazyLoader object
raise salt.exceptions.CommandExecutionError(
'\'{0}\' is not available'.format(fun)
)
class LazyDict(collections.MutableMapping):
'''
A base class of dict which will lazily load keys once they are needed

View file

@ -29,12 +29,21 @@ try:
except ImportError:
pass
try:
import systemd.daemon
HAS_PYTHON_SYSTEMD = True
except ImportError:
HAS_PYTHON_SYSTEMD = False
# pylint: enable=import-error
def notify_systemd():
'''
Notify systemd that this process has started
'''
try:
import systemd.daemon
except ImportError:
return False
if systemd.daemon.booted():
try:
return systemd.daemon.notify('READY=1')
except SystemError:
# Daemon was not started by systemd
pass
def set_pidfile(pidfile, user):
@ -260,13 +269,6 @@ class ProcessManager(object):
# make sure to kill the subprocesses if the parent is killed
signal.signal(signal.SIGTERM, self.kill_children)
try:
if HAS_PYTHON_SYSTEMD and systemd.daemon.booted():
systemd.daemon.notify('READY=1')
except SystemError:
# Daemon wasn't started by systemd
pass
while True:
try:
# in case someone died while we were waiting...

View file

@ -589,8 +589,8 @@ class Schedule(object):
try:
os.unlink(proc_fn)
except OSError as exc:
if exc.errno == errno.EEXIST:
# EEXIST is OK because the file is gone and that's what
if exc.errno == errno.EEXIST or exc.errno == errno.ENOENT:
# EEXIST and ENOENT are OK because the file is gone and that's what
# we wanted
pass
else:

View file

@ -4,6 +4,7 @@
from __future__ import absolute_import
import os
import shutil
import textwrap
# Import Salt Testing libs
from salttesting import skipIf
@ -22,7 +23,7 @@ import salt.ext.six as six
class StateModuleTest(integration.ModuleCase,
integration.SaltReturnAssertsMixIn):
'''
Validate the test module
Validate the state module
'''
maxDiff = None
@ -144,17 +145,17 @@ class StateModuleTest(integration.ModuleCase,
ret = self.run_function('state.sls', mods='testappend.step-2')
self.assertSaltTrueReturn(ret)
self.assertMultiLineEqual('''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
self.assertMultiLineEqual(textwrap.dedent('''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
''', salt.utils.fopen(testfile, 'r').read())
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
'''), salt.utils.fopen(testfile, 'r').read())
# Re-append switching order
ret = self.run_function('state.sls', mods='testappend.step-2')
@ -163,17 +164,17 @@ fi
ret = self.run_function('state.sls', mods='testappend.step-1')
self.assertSaltTrueReturn(ret)
self.assertMultiLineEqual('''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
self.assertMultiLineEqual(textwrap.dedent('''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
''', salt.utils.fopen(testfile, 'r').read())
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
'''), salt.utils.fopen(testfile, 'r').read())
def test_issue_1876_syntax_error(self):
'''
@ -198,16 +199,16 @@ fi
)
def test_issue_1879_too_simple_contains_check(self):
contents = '''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
'''
contents = textwrap.dedent('''\
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
''')
testfile = os.path.join(integration.TMP, 'issue-1879')
# Delete if exiting
if os.path.isfile(testfile):
@ -386,15 +387,15 @@ fi
shutil.rmtree(venv_dir)
def test_template_invalid_items(self):
TEMPLATE = '''\
{0}:
- issue-2068-template-str
TEMPLATE = textwrap.dedent('''\
{0}:
- issue-2068-template-str
/tmp/test-template-invalid-items:
file:
- managed
- source: salt://testfile
'''
/tmp/test-template-invalid-items:
file:
- managed
- source: salt://testfile
''')
for item in ('include', 'exclude', 'extends'):
ret = self.run_function(
'state.template_str', [TEMPLATE.format(item)]

View file

@ -24,15 +24,49 @@ class ManageTest(integration.ShellCase):
ret = self.run_run_plus(fun='fileserver.dir_list')
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.dir_list',
args=['backend="roots"'])
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.dir_list',
args=['backend="[roots]"'])
self.assertIsInstance(ret['fun'], list)
def test_empty_dir_list(self):
'''
fileserver.empty_dir_list
'''
ret = self.run_run_plus(fun='fileserver.empty_dir_list')
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.empty_dir_list',
args=['backend="roots"'])
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.empty_dir_list',
args=['backend="[roots]"'])
self.assertIsInstance(ret['fun'], list)
def test_envs(self):
'''
fileserver.envs
'''
ret = self.run_run_plus(fun='fileserver.envs')
self.assertIsInstance(ret['fun'], dict)
self.assertIsInstance(ret['fun'], list)
ret = self.run_run_plus(fun='fileserver.envs', args=['backend="{0}"'.format(['root'])])
self.assertIsInstance(ret['fun'], dict)
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.envs',
args=['backend="roots"'])
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.envs',
args=['backend="[roots]"'])
self.assertIsInstance(ret['fun'], list)
def test_file_list(self):
'''
@ -41,6 +75,16 @@ class ManageTest(integration.ShellCase):
ret = self.run_run_plus(fun='fileserver.file_list')
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.file_list',
args=['backend="roots"'])
self.assertIsInstance(ret['fun'], list)
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.file_list',
args=['backend="[roots]"'])
self.assertIsInstance(ret['fun'], list)
def test_symlink_list(self):
'''
fileserver.symlink_list
@ -48,6 +92,16 @@ class ManageTest(integration.ShellCase):
ret = self.run_run_plus(fun='fileserver.symlink_list')
self.assertIsInstance(ret['fun'], dict)
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.symlink_list',
args=['backend="roots"'])
self.assertIsInstance(ret['fun'], dict)
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.symlink_list',
args=['backend="[roots]"'])
self.assertIsInstance(ret['fun'], dict)
def test_update(self):
'''
fileserver.update
@ -55,6 +109,16 @@ class ManageTest(integration.ShellCase):
ret = self.run_run_plus(fun='fileserver.update')
self.assertTrue(ret['fun'])
# Backend submitted as a string
ret = self.run_run_plus(fun='fileserver.update',
args=['backend="roots"'])
self.assertTrue(ret['fun'])
# Backend submitted as a list
ret = self.run_run_plus(fun='fileserver.update',
args=['backend="[roots]"'])
self.assertTrue(ret['fun'])
if __name__ == '__main__':
from integration import run_tests
run_tests(ManageTest)

View file

@ -145,7 +145,7 @@ class SSHKnownHostsStateTest(integration.ModuleCase,
# test again
ret = self.run_state('ssh_known_hosts.absent', test=True, **kwargs)
self.assertSaltNoneReturn(ret)
self.assertSaltTrueReturn(ret)
class SSHAuthStateTests(integration.ModuleCase,