Merge branch 'develop' of https://github.com/saltstack/salt into disable_lspci

* 'develop' of https://github.com/saltstack/salt: (57 commits)
  fixed a typo in the halite docs, reworded a sentence to clarify how halite is obtained
  Using the same technique as the python path checker to determine the correct md5 command. This improves the previous technique.
  OS X doesn't call md5sum by its full name. Instead, it is installed as simple 'md5'. Because we don't know what OS we're deploying to ahead of time, we need to check that condition for that in the shim script and account for it.
  Remove stale files in the docs dir. Refs #7984. Tested against a build and walk-through of the HTML docs.
  pip freeze output has comments sometimes: ignore
  Removing nsProcess plugin. Using ExecWait and a sleep 3s to stop salt-minion.
  Fix my typo
  Change assertEquals to assertEqual
  Use versionadded instead of note
  Reworked part of the halite docs to clarify the running of halite itself, created sections in prep for nginx/apache work.
  Reformatted according to Debian spec. Also added note to  declare that images in doc/_ext/images were created in-house, by Salt Stack.
  Forgot to add youtube.py.
  Initial commit of a top-level COPYING file to assist package maintainers.
  Stop shipping fonts in the docset. Start using free-fonts from Google and then fall-back to system fonts if those are not available.
  Fix for swapped vars in ssh-client auth.
  Still guess an ID always, but only cache if it's a proper minion
  Add note about upgrading minions for 0.17.1
  fix bad indent
  Kill some whitespace
  Lint fixes for execution module file.block
  ...

Conflicts:
	salt/grains/core.py
This commit is contained in:
Mike Place 2013-10-24 15:05:11 -06:00
commit c959512c4a
88 changed files with 1301 additions and 590 deletions

135
COPYING Normal file
View File

@ -0,0 +1,135 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: salt
Upstream-Contact: salt-users@googlegroups.com
Source: https://github.com/saltstack/salt
Files: *
Copyright: 2013 SaltStack Team
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License, Version 2.0 can be
found in the file
`/usr/share/common-licenses/Apache-2.0'.
Files: debian/*
Copyright: 2013 Joe Healy <joehealy@gmail.com>
2012 Michael Prokop <mika@debian.org>
2012 Christian Hofstaedtler <christian@hofstaedtler.name>
2012 Ulrich Dangel <mru@spamt.net>
2012 Corey Quinn <corey@sequestered.net>
2011 Aaron Toponce <aaron.toponce@gmail.com>
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License, Version 2.0 can be
found in the file
`/usr/share/common-licenses/Apache-2.0'.
Files: salt/auth/pam.py
Copyright: 2007 Chris AtLee <chris@atlee.ca>
License: MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Files: salt/utils/ipaddr.py
Copyright: 2007 Google Inc.
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License, Version 2.0 can be
found in the file
`/usr/share/common-licenses/Apache-2.0'.
Files: doc/_ext/youtube.py
Copyright: 2009 Chris Pickel <sfiera@gmail.com>
License: BSD-2-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
.
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: doc/_ext/images
Copyright: 2013 SaltStack Team
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License, Version 2.0 can be
found in the file
`/usr/share/common-licenses/Apache-2.0'.
.
Files in this directory were created in-house.

View File

@ -161,7 +161,7 @@
{%- endblock %}
{%- block extrahead %} {% endblock %}
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,800italic,300,800' rel='stylesheet' type='text/css'>
<script src="{{ pathto('_static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js', 1) }}"></script>
{%- block analytics %}

View File

@ -1,115 +1,3 @@
/* ==========================================================================
WEBFONTS
========================================================================== */
/*
Font: Nexa Light
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2010 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa Light';
src: url('../fonts/nexa-light.eot');
src: url('../fonts/nexa-light.eot?#iefix') format('embedded-opentype'),
url('../fonts/nexa-light.woff') format('woff'),
url('../fonts/nexa-light.ttf') format('truetype'),
url('../fonts/nexa-light.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}
/*
Font: Nexa Light Italic
Style: Italic
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2012 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa Light Italic';
src: url('../fonts/nexa-light-italic.eot');
src: url('../fonts/nexa-light-italic.eot?#iefix') format('embedded-opentype'),
url('../fonts/nexa-light-italic.woff') format('woff'),
url('../fonts/nexa-light-italic.ttf') format('truetype'),
url('../fonts/nexa-light-italic.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}
/*
Font: Nexa XBold
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2010 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa XBold';
src: url('../fonts/nexa-xbold.eot');
src: url('../fonts/nexa-xbold.eot?#iefix') format('embedded-opentype'),
url('../fonts/nexa-xbold.woff') format('woff'),
url('../fonts/nexa-xbold.ttf') format('truetype'),
url('../fonts/nexa-xbold.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}
/*
Font: Nexa XBold Italic
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2012 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa XBold Italic';
src: url('../fonts/nexa-xbold-italic.eot');
src: url('../fonts/nexa-xbold-italic.eot?#iefix') format('embedded-opentype'),
url('../fonts/nexa-xbold-italic.woff') format('woff'),
url('../fonts/nexa-xbold-italic.ttf') format('truetype'),
url('../fonts/nexa-xbold-italic.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}
/* ==========================================================================
@ -129,7 +17,7 @@ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockq
}
.navbar-inverse .brand, .navbar-inverse .nav > li > a {
color: #484c51;
font: 14px/24px 'Nexa Light';
font: 14px/24px 'Open Sans Light';
}
.navbar .nav li.currentNav {
background: url(../img/navCurrentArrow.png) center 32px no-repeat;
@ -145,7 +33,7 @@ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockq
}
.articleCredits {
padding-left: 12px;
font: 12px/24px 'Nexa Light';
font: 12px/24px 'Open Sans Light';
white-space: pre;
}
.fullwidth {
@ -167,7 +55,7 @@ body.index .success, body.index .clients {
.testimonialAuthor {
display: block;
margin-bottom: 30px;
font: 12px/24px 'Nexa XBold';
font: 12px/24px 'Open Sans Extrabold';
color: #aa2b39;
text-transform: uppercase;
}
@ -185,12 +73,12 @@ body.index .success, body.index .clients {
}
h2.homeSecTitles {
color: #8d9caa;
font-family: 'Nexa XBold Italic';
font-family: 'Open Sans Extrabold Italic';
text-transform: capitalize;
margin-bottom: 0;
}
.success h3 {
font: 18px/30px 'Nexa Light Italic'; color: #4f575b; margin: 25px 0;
font: 18px/30px 'Open Sans Light Italic'; color: #4f575b; margin: 25px 0;
}
.success img {
margin: 30px 10px 10px 80px;
@ -214,7 +102,7 @@ h2.homeSecTitles {
}
.carousel-caption p {
margin-top: 25px;
font: 16px/24px 'Nexa Light';
font: 16px/24px 'Open Sans Light';
color: #000;
display: none;
}
@ -230,11 +118,12 @@ h2.homeSecTitles {
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Nexa Light';
font-family: 'Open Sans Light';
font-weight: normal;
}
h2 {
font: 18px/28px 'Nexa XBold';
font: 18px/28px 'Open Sans Extrabold';
text-transform: uppercase;
color: #373e4b;
margin-bottom: 0;
@ -260,11 +149,11 @@ body.products .lede {
margin-top: 30px;
}
.lede h3 {
font: 24px/30px 'Nexa Light';
font: 24px/30px 'Open Sans Light';
color: #aa2b39;
}
.lede h4 {
font: 20px/30px 'Nexa Light Italic';
font: 20px/30px 'Open Sans Light Italic';
color: #373e4b;
}
body.services .lede h4 {
@ -275,7 +164,7 @@ body.services .lede {
margin-bottom: 30px;
}
body.about h1, body.services h1, body.contact h1 {
font: 20px/30px 'Nexa XBold Italic';
font: 20px/30px 'Open Sans Extrabold Italic';
color: #4f575b;
margin-top: 0;
}
@ -284,7 +173,7 @@ body.about h1, body.services h1, body.contact h1 {
}
body.about h6 {
margin: 0;
font-family: 'Nexa Light Italic';
font-family: 'Open Sans Light Italic';
text-transform: uppercase;
line-height: 80%;
margin-bottom: 10px;
@ -301,7 +190,7 @@ body.services table th, body.services table td {
}
body.services table td {
color: #373e4b;
font-family: 'Nexa Light Italic';
font-family: 'Open Sans Light Italic';
width: 206px;
}
body.services table tr:last-child th, body.services table tr:last-child td {
@ -327,7 +216,7 @@ body.services table td.tableCenter {
padding: 5px 0;
background: #aa2b39;
color: #FFF;
font-family: 'Nexa Light';
font-family: 'Open Sans Light';
text-shadow: none;
font-weight: normal;
border: none;
@ -378,7 +267,7 @@ footer {
}
footer p, footer a {
color: #FFF;
font: 12px 'Nexa Light';
font: 12px 'Open Sans Light';
}
footer a {
display:block;
@ -395,7 +284,7 @@ footer .row-fluid {
}
.footerCol h4 {
color: #FFF;
font: 14px/24px 'Nexa XBold';
font: 14px/24px 'Open Sans Extrabold';
text-transform: uppercase;
margin-bottom: 0;
}

View File

@ -1,26 +0,0 @@
/*
Font: Nexa Light Italic
Style: Italic
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2012 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa Light Italic';
src: url('nexa-light-italic.eot');
src: url('nexa-light-italic.eot?#iefix') format('embedded-opentype'),
url('nexa-light-italic.woff') format('woff'),
url('nexa-light-italic.ttf') format('truetype'),
url('nexa-light-italic.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 137 KiB

View File

@ -1,26 +0,0 @@
/*
Font: Nexa Light
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2010 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa Light';
src: url('nexa-light.eot');
src: url('nexa-light.eot?#iefix') format('embedded-opentype'),
url('nexa-light.woff') format('woff'),
url('nexa-light.ttf') format('truetype'),
url('nexa-light.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

View File

@ -1,26 +0,0 @@
/*
Font: Nexa XBold Italic
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2012 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa XBold Italic';
src: url('nexa-xbold-italic.eot');
src: url('nexa-xbold-italic.eot?#iefix') format('embedded-opentype'),
url('nexa-xbold-italic.woff') format('woff'),
url('nexa-xbold-italic.ttf') format('truetype'),
url('nexa-xbold-italic.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 137 KiB

View File

@ -1,26 +0,0 @@
/*
Font: Nexa XBold
Style: Regular
URL: http://www.youworkforthem.com/product.php?sku=T3972
Foundry: Fontfabric
Foundry: http://www.youworkforthem.com/designer/105/fontfabric
Copyright: Copyright (c) 2010 by Svetoslav Simov. All rights reserved.
Version: 1.1
Created: October 11, 2012
License: http://www.youworkforthem.com/font-license
License: The WebFont(s) listed in this document must follow the YouWorkForThem
WebFont license rules. All other parties are strictly restricted
from using the WebFonts(s) listed without a purchased license.
All details above must always remain unaltered and visible in your CSS.
*/
@font-face {
font-family: 'Nexa XBold';
src: url('nexa-xbold.eot');
src: url('nexa-xbold.eot?#iefix') format('embedded-opentype'),
url('nexa-xbold.woff') format('woff'),
url('nexa-xbold.ttf') format('truetype'),
url('nexa-xbold.svg#ywftsvg') format('svg');
font-weight: normal;
font-style: normal;
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,8 +1,8 @@
Developing Salt
===============
There is a great need for contributions to salt and patches are welcome! The goal
here is to make contributions clear, make sure there is a trail for where the code
There is a great need for contributions to salt and patches are welcome! The goal
here is to make contributions clear, make sure there is a trail for where the code
has come from, and most importantly, to give credit where credit is due!
There are a number of ways to contribute to salt development.
@ -14,8 +14,8 @@ Sending a GitHub pull request
This is the preferred method for contributions. Simply create a GitHub
fork, commit changes to the fork, and then open up a pull request.
The following is an example (from `Open Comparison Contributing Docs`_ )
of an efficient workflow for forking, cloning, branching, committing, and
The following is an example (from `Open Comparison Contributing Docs`_ )
of an efficient workflow for forking, cloning, branching, committing, and
sending a pull request for a GitHub repository.
First, make a local clone of your GitHub fork of the salt GitHub repo and make
@ -29,7 +29,7 @@ Then, create a new branch on your clone by entering the following commands:
Switched to a new branch 'fixed-broken-thing'
Choose a name for your branch that describes its purpose.
Choose a name for your branch that describes its purpose.
Now commit your changes to this new branch with the following command:
@ -51,8 +51,8 @@ Push your locally-committed changes back up to GitHub:
.. code-block:: bash
git push --set-upstream origin fixed-broken-thing
Now go look at your fork of the salt repo on the GitHub website. The new
Now go look at your fork of the salt repo on the GitHub website. The new
branch will now be listed under the "Source" tab where it says "Switch Branches".
Select the new branch from this list, and then click the "Pull request" button.
@ -62,7 +62,7 @@ to the pull request.
The repo managers will be notified of your pull request and it will be
reviewed. If a reviewer asks for changes, just make the changes locally in the
same local feature branch, push them to GitHub, then add a comment to the
discussion section of the pull request.
discussion section of the pull request.
.. _enable-travis-ci:
@ -81,7 +81,7 @@ Keeping Salt Forks in Sync
Salt is advancing quickly. It is therefore critical to pull upstream changes
from master into forks on a regular basis. Nothing is worse than putting in a
days of hard work into a pull request only to have it rejected because it has
diverged too far from master.
diverged too far from master.
To pull in upstream changes:
@ -187,7 +187,7 @@ Install Salt (and dependencies) into the virtualenv:
.. note:: Installing M2Crypto
``swig`` and ``libssl-dev`` are required to build M2Crypto. To fix
the error ``command 'swig' failed with exit status 1`` while installing M2Crypto,
the error ``command 'swig' failed with exit status 1`` while installing M2Crypto,
try installing it with the following command:
.. code-block:: bash
@ -226,7 +226,7 @@ Install Salt (and dependencies) into the virtualenv:
* `Fedora Linux`_ releases 11 and later
* `Amazon Linux`_
Developers using one of these systems should create the salt virtualenv using the
Developers using one of these systems should create the salt virtualenv using the
``--system-site-packages`` option to ensure that the correct modules are available.
.. _`RHEL`: https://www.redhat.com/products/enterprise-linux/
@ -383,7 +383,14 @@ Finally you use setup.py to run the tests with the following command:
./setup.py test
For greater control while running the tests, please try:
For greater control while running the tests, please try something like:
.. code-block:: bash
./tests/runtests.py -n integration.modules.virt -vv
./tests/runtests.py -n unit.modules.virt_test -vv
Also see the help for all options:
.. code-block:: bash
@ -431,3 +438,10 @@ Change to salt documentation directory, then:
.. code-block:: bash
make SPHINXBUILD=sphinx-1.0-build html
Once you've updated the documentation, you can run the following command to
launch a simple Python http server to see your changes:
.. code-block:: bash
cd _build/html; python -m SimpleHTTPServer

View File

@ -23,15 +23,20 @@ Major Features
Halite
------
The new Halite web GUI is now available, a great deal of work has been put into
Halite to make it fully event driven and amazingly fast. The Halite UI can be
started from within the Salt Master, or standalone, and does not require an
external database to run, it is very lightweight!
The new Halite web GUI is now available on PyPi, a great deal of work has
been put into Halite to make it fully event driven and amazingly fast. The
Halite UI can be started from within the Salt Master (after being installed
from PyPi), or standalone, and does not require an external database to run,
it is very lightweight!
This initial release of Halite is primarily the framework for the UI and the
communication systems making it easy to extend and build the UI up. It
presently supports watching the event bus and firing commands over Salt.
At this time Halite is not available as a package, but installation
documentation is available at:
http://docs.saltstack.com/topics/tutorials/halite.html
Halite is, like the rest of Salt, Open Source!
Much more will be coming in the future of Halite!

View File

@ -2,6 +2,13 @@
Salt 0.17.1 Release Notes
=========================
.. note::
THIS RELEASE IS NOT COMPATIBLE WITH PREVIOUS VERSIONS. If you update your
master to 0.17.1, you must update your minions as well. Sorry for the
inconvenience -- this is a result of one of the security fixes listed
below.
The 0.17.1 release comes with a number of improvements to salt-ssh, many
bugfixes, and a number of security updates.

View File

@ -0,0 +1,224 @@
=================================
Installing and Configuring Halite
=================================
In this tutorial we'll walk through installing and setting up Halite. As of
2013-10-12 a packaged version of Halite is not available, in addition the
current version of Halite is considered pre-alpha and is supported only in
Salt 0.17 or greater. Additional information is available on GitHub:
https://github.com/saltstack/halite
Installing Halite
=================
Before beginning this tutorial ensure that the salt-master is installed. To
install the salt-master please review the installation documentation:
http://docs.saltstack.com/topics/installation/index.html
.. note::
Halite only works with Salt versions greater than 0.17.
To begin the installation of Halite you'll need to install pip. The
Salt package, as well as the bootstrap do not install pip by default.
On CentOS:
.. code-block:: bash
$ yum install python-pip
On Debian:
.. code-block:: bash
$ apt-get install python-pip
Once you have pip installed, use it to install halite:
.. code-block:: bash
$ pip install -U halite
Depending on the webserver you want to run halite through, you'll need to
install that piece as well. On RHEL based distros use one of the following:
.. code-block:: bash
$ pip install cherrypy
.. code-block:: bash
$ pip install paste
.. code-block:: bash
$ yum install python-devel
$ yum install gcc
$ pip install gevent
On Debian based distributions:
.. code-block:: bash
$ pip install CherryPy
.. code-block:: bash
$ pip install paste
.. code-block:: bash
$ apt-get install gcc
$ apt-get install python-dev
$ pip install gevent
Configuring Halite Permissions
==============================
Configuring Halite access permissions is easy. By default you only need to
ensure that the @runner group is configured. In the /etc/salt/master file
uncomment and modify the following lines:
.. code-block:: yaml
external_auth:
pam:
testuser:
- .*
- '@runner'
.. note::
You cannot use the root user for pam login, it will fail to authenticate.
Halite uses the runner manage.status to get the status of minions so runner
permissions are required. As you can see in this example the root user has
been configured, if you aren't running Halite as the root user, you'll need
to modify this value. For example:
.. code-block:: yaml
external_auth:
pam:
mytestuser:
- .*
- '@runner'
- '@wheel'
Currently Halite allows, but does not require any wheel modules.
Configuring Halite settings
===========================
Once you've configured the permissions for Halite, you'll need to set up the
Halite settings in the /etc/salt/master file. Halite supports CherryPy, Paste
and Gevent out of the box.
To configure cherrypy add the following to the bottom of your /etc/salt/master file:
.. code-block: yaml
halite:
level: 'debug'
server: 'cherrypy'
host: '0.0.0.0'
port: '8080'
cors: False
tls: True
certpath: '/etc/pki/tls/certs/localhost.crt'
keypath: '/etc/pki/tls/certs/localhost.key'
pempath: '/etc/pki/tls/certs/localhost.pem'
If you wish to use paste:
.. code-block: yaml
halite:
level: 'debug'
server: 'paste'
host: '0.0.0.0'
port: '8080'
cors: False
tls: True
certpath: '/etc/pki/tls/certs/localhost.crt'
keypath: '/etc/pki/tls/certs/localhost.key'
pempath: '/etc/pki/tls/certs/localhost.pem'
To use gevent:
.. code-block: yaml
halite:
level: 'debug'
server: 'gevent'
host: '0.0.0.0'
port: '8080'
cors: False
tls: True
certpath: '/etc/pki/tls/certs/localhost.crt'
keypath: '/etc/pki/tls/certs/localhost.key'
pempath: '/etc/pki/tls/certs/localhost.pem'
The "cherrypy" and "gevent" servers require the certpath and keypath files
to run tls/ssl. The .crt file holds the public cert and the .key file holds
the private key. Whereas the "paste" server requires a single .pem file that
contains both the cert and key. This can be created simply by concatenating
the .crt and .key files.
If you want to use a self signed cert you can create one using the Salt.tls
module:
.. code-block:: bash
salt '*' tls.create_ca_signed_cert test localhost
When using self signed certs, browsers will need approval before accepting the
cert. If the web application page has been cached with a non https version of
the app then the browser cache will have to be cleared before it will
recognize and prompt to accept the self signed certificate.
Starting halite
===============
Once you've configured the halite section of your /etc/salt/master, you can
restart the salt-master service, and your halite instance will be available.
Depending on your configuration the instance will be available either at
http://localhost:8080/app, http://domain:8080/app, or
http://123.456.789.012:8080/app depending on how your system is configured.
.. note::
halite requires an HTML 5 compliant browser.
All logs relating to halite are logged to the default /var/log/salt/master file.
Running your halite instance through nginx
==========================================
Running your halite instance through apache
===========================================

View File

@ -6,15 +6,15 @@
# LSB header
### BEGIN INIT INFO
# Provides: salt-master
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt master control daemon
# Description: This is a daemon that controls the Salt minions.
# Provides: salt-master
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt master control daemon
# Description: This is a daemon that controls the Salt minions.
### END INIT INFO
@ -26,16 +26,6 @@
# processname: /usr/bin/salt-master
if [ -f /etc/default/salt ]; then
. /etc/default/salt
else
SALTMASTER=/usr/bin/salt-master
PYTHON=/usr/bin/python
fi
# Sanity checks.
[ -x $SALTMASTER ] || exit 0
DEBIAN_VERSION=/etc/debian_version
SUSE_RELEASE=/etc/SuSE-release
# Source function library.
@ -47,27 +37,35 @@ else
. /etc/rc.d/init.d/functions
fi
# Default values (can be overridden below)
SALTMASTER=/usr/bin/salt-master
PYTHON=/usr/bin/python
MASTER_ARGS=""
if [ -f /etc/default/salt ]; then
. /etc/default/salt
fi
SERVICE=salt-master
PROCESS=salt-master
CONFIG_ARGS=" "
RETVAL=0
start() {
echo -n $"Starting salt-master daemon: "
if [ -f $SUSE_RELEASE ]; then
startproc -f -p /var/run/$SERVICE.pid $SALTMASTER -d $CONFIG_ARGS
startproc -f -p /var/run/$SERVICE.pid $SALTMASTER -d $MASTER_ARGS
rc_status -v
elif [ -e $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
echo -n "already started, lock file found"
RETVAL=1
elif $PYTHON $SALTMASTER -d >& /dev/null; then
elif $PYTHON $SALTMASTER -d $MASTER_ARGS >& /dev/null; then
echo -n "OK"
RETVAL=0
fi
else
daemon --check $SERVICE $SALTMASTER -d $CONFIG_ARGS
daemon --check $SERVICE $SALTMASTER -d $MASTER_ARGS
fi
RETVAL=$?
echo
@ -100,7 +98,6 @@ restart() {
start
}
# See how we were called.
case "$1" in
start|stop|restart)
@ -129,11 +126,7 @@ case "$1" in
;;
reload)
echo "can't reload configuration, you have to restart it"
if [ -f $SUSE_RELEASE ]; then
rc_status -v
else
RETVAL=$?
fi
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
@ -141,4 +134,3 @@ case "$1" in
;;
esac
exit $RETVAL

View File

@ -6,15 +6,16 @@
# LSB header
### BEGIN INIT INFO
# Provides: salt-minion
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt minion daemon
# Description: This is the Salt minion daemon that can be controlled by the Salt master.
# Provides: salt-minion
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt minion daemon
# Description: This is the Salt minion daemon that can be controlled by the
# Salt master.
### END INIT INFO
@ -26,16 +27,6 @@
# processname: /usr/bin/salt-minion
if [ -f /etc/default/salt ]; then
. /etc/default/salt
else
SALTMINION=/usr/bin/salt-minion
PYTHON=/usr/bin/python
fi
# Sanity checks.
[ -x $SALTMINION ] || exit 0
DEBIAN_VERSION=/etc/debian_version
SUSE_RELEASE=/etc/SuSE-release
# Source function library.
@ -47,22 +38,30 @@ else
. /etc/rc.d/init.d/functions
fi
# Default values (can be overridden below)
SALTMINION=/usr/bin/salt-minion
PYTHON=/usr/bin/python
MINION_ARGS=""
if [ -f /etc/default/salt ]; then
. /etc/default/salt
fi
SERVICE=salt-minion
PROCESS=salt-minion
CONFIG_ARGS=" "
RETVAL=0
start() {
echo -n $"Starting salt-minion daemon: "
if [ -f $SUSE_RELEASE ]; then
startproc -f -p /var/run/$SERVICE.pid $SALTMINION -d $CONFIG_ARGS
startproc -f -p /var/run/$SERVICE.pid $SALTMINION -d $MINION_ARGS
rc_status -v
elif [ -e $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
echo -n "already started, lock file found"
RETVAL=1
elif $PYTHON $SALTMINION -d >& /dev/null; then
elif $PYTHON $SALTMINION -d $MINION_ARGS >& /dev/null; then
echo -n "OK"
RETVAL=0
fi
@ -71,7 +70,7 @@ start() {
RETVAL=$?
echo -n "already running"
else
daemon --check $SERVICE $SALTMINION -d $CONFIG_ARGS
daemon --check $SERVICE $SALTMINION -d $MINION_ARGS
RETVAL=$?
fi
fi
@ -133,11 +132,7 @@ case "$1" in
;;
reload)
echo "can't reload configuration, you have to restart it"
if [ -f $SUSE_RELEASE ]; then
rc_status -v
else
RETVAL=$?
fi
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"

View File

@ -6,36 +6,27 @@
# LSB header
### BEGIN INIT INFO
# Provides: salt-syndic
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt syndic master-minion passthrough daemon
# Description: This is a the Salt syndic daemon that enables Salt master-minion remote control passthrough.
# Provides: salt-syndic
# Required-Start: $local_fs $remote_fs $network $named $time
# Should-Start: $time ypbind smtp
# Required-Stop: $local_fs $remote_fs $network $named $time
# Should-Stop: ypbind smtp
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: Salt syndic master-minion passthrough daemon
# Description: This is a the Salt syndic daemon that enables Salt master-minion
# remote control passthrough.
### END INIT INFO
# chkconfig header
# chkconfig: 345 99 99
# chkconfig: - 99 99
# description: This is a the Salt syndic daemon that enables Salt master-minion remote control passthrough.
#
# processname: /usr/bin/salt-syndic
if [ -f /etc/default/salt ]; then
. /etc/default/salt
else
SALTSYNDIC=/usr/bin/salt-syndic
PYTHON=/usr/bin/python
fi
# Sanity checks.
[ -x $SALTSYNDIC ] || exit 0
DEBIAN_VERSION=/etc/debian_version
SUSE_RELEASE=/etc/SuSE-release
# Source function library.
@ -47,27 +38,35 @@ else
. /etc/rc.d/init.d/functions
fi
# Default values (can be overridden below)
SALTSYNDIC=/usr/bin/salt-syndic
PYTHON=/usr/bin/python
SYNDIC_ARGS=""
if [ -f /etc/default/salt ]; then
. /etc/default/salt
fi
SERVICE=salt-syndic
PROCESS=salt-syndic
CONFIG_ARGS=" "
RETVAL=0
start() {
echo -n $"Starting salt-syndic daemon: "
if [ -f $SUSE_RELEASE ]; then
startproc -f -p /var/run/$SERVICE.pid $SALTSYNDIC -d $CONFIG_ARGS
startproc -f -p /var/run/$SERVICE.pid $SALTSYNDIC -d $SYNDIC_ARGS
rc_status -v
elif [ -e $DEBIAN_VERSION ]; then
if [ -f $LOCKFILE ]; then
echo -n "already started, lock file found"
RETVAL=1
elif $PYTHON $SALTSYNDIC -d >& /dev/null; then
elif $PYTHON $SALTSYNDIC -d $SYNDIC_ARGS >& /dev/null; then
echo -n "OK"
RETVAL=0
fi
else
daemon --check $SERVICE $SALTSYNDIC -d $CONFIG_ARGS
daemon --check $SERVICE $SALTSYNDIC -d $SYNDIC_ARGS
fi
RETVAL=$?
echo
@ -123,18 +122,16 @@ case "$1" in
RETVAL=$?
fi
;;
reload)
condrestart)
[ -f $LOCKFILE ] && restart || :
;;
reload)
echo "can't reload configuration, you have to restart it"
if [ -f $SUSE_RELEASE ]; then
rc_status -v
else
RETVAL=$?
fi
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
exit 1
;;
esac
exit $RETVAL

View File

@ -16,7 +16,7 @@
#
Name: salt
Version: 0.17.0
Version: 0.17.1
Release: 0
Summary: A parallel remote execution system
License: Apache-2.0
@ -31,10 +31,8 @@ Source5: %{name}-syndic.service
Source6: %{name}-minion.service
Source7: %{name}.logrotate
Source8: %{name}.SuSEfirewall2
%if 0%{?sles_version}
BuildRequires: python
Requires: python
%endif
#for building
BuildRequires: python-devel
BuildRequires: logrotate
BuildRequires: python-Jinja2
@ -42,18 +40,32 @@ BuildRequires: python-M2Crypto
BuildRequires: python-PyYAML
BuildRequires: python-msgpack-python
BuildRequires: python-pycrypto
BuildRequires: python-pyzmq >= 2.1.9
BuildRequires: unzip
Requires: logrotate
Requires: python-Jinja2
Requires: python-PyYAML
Requires: python-Sphinx
Requires(pre): %fillup_prereq
Requires(pre): %insserv_prereq
BuildRequires: python-pyzmq
%if 0%{?sles_version}
BuildRequires: python
Requires: python
%endif
%if 0%{?suse_version} >= 1210
BuildRequires: systemd
%{?systemd_requires}
%endif
#for testing
BuildRequires: python-xml
BuildRequires: python-unittest2
BuildRequires: python-salt-testing
BuildRequires: python-mock
BuildRequires: python-pip
Requires: logrotate
Requires: python-Jinja2
Requires: python-PyYAML
Requires: python-xml
Requires(pre): %fillup_prereq
%if 0%{?suse_version} < 1210
Requires(pre): %insserv_prereq
%endif
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%if 0%{?suse_version} && 0%{?suse_version} <= 1110
%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
@ -61,16 +73,6 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildArch: noarch
%endif
## Disabled for now python-mock issues
%if 0%{?suse_version} != 1220 && 0%{?suse_version} != 1230
BuildRequires: python-unittest2
BuildRequires: python-salt-testing
BuildRequires: python-xml
BuildRequires: python-mock
BuildRequires: python-pip
BuildRequires: git
%endif
%description
Salt is a distributed remote execution system used to execute commands and
query data. It was developed in order to bring the best solutions found in
@ -83,8 +85,7 @@ servers, handle them quickly and through a simple and manageable interface.
Summary: Management component for salt, a parallel remote execution system
Group: System/Monitoring
Requires: %{name} = %{version}
Requires: zeromq >= 3.2
Requires: python-pyzmq >= 2.10
Requires: python-pyzmq
Requires: python-M2Crypto
Requires: python-msgpack-python
Requires: python-pycrypto
@ -96,8 +97,11 @@ Requires: dmidecode
%endif
%endif
Recommends: python-halite
Requires(pre): %fillup_prereq
%if 0%{?suse_version} < 1210
Requires(pre): %insserv_prereq
%endif
Requires(pre): %fillup_prereq
%description master
The Salt master is the central server to which all minions connect.
@ -108,13 +112,14 @@ than serially.
Summary: Client component for salt, a parallel remote execution system
Group: System/Monitoring
Requires: %{name} = %{version}
Requires: zeromq >= 3.2
Requires: python-pyzmq >= 2.10
Requires: python-pyzmq
Requires: python-M2Crypto
Requires: python-msgpack-python
Requires: python-pycrypto
Requires(pre): %fillup_prereq
%if 0%{?suse_version} < 1210
Requires(pre): %insserv_prereq
%endif
Requires(pre): %fillup_prereq
%description minion
Salt minion is queried and controlled from the master.
@ -125,8 +130,10 @@ Summary: Syndic component for salt, a parallel remote execution system
Group: System/Monitoring
Requires: %{name} = %{version}
Requires: %{name}-master = %{version}
Requires(pre): %fillup_prereq
%if 0%{?suse_version} < 1210
Requires(pre): %insserv_prereq
%endif
Requires(pre): %fillup_prereq
%description syndic
Salt syndic is the master-of-masters for salt
@ -137,9 +144,13 @@ the management of multiple masters at a time..
Summary: Ssh component for salt, a parallel remote execution system
Group: System/Monitoring
Requires: %{name} = %{version}
Requires: sshpass
Requires(pre): %fillup_prereq
BuildRequires: python-markupsafe
Requires: python-markupsafe
Recommends: sshpass
%if 0%{?suse_version} < 1210
Requires(pre): %insserv_prereq
%endif
Requires(pre): %fillup_prereq
%description ssh
Salt ssh is a master running without zmq.
@ -154,10 +165,12 @@ python setup.py build
%install
python setup.py install --prefix=%{_prefix} --root=%{buildroot}
##missing directories
## create missing directories
mkdir -p %{buildroot}%{_sysconfdir}/salt/master.d
mkdir -p %{buildroot}%{_sysconfdir}/salt/minion.d
%if 0%{?suse_version} < 1210
mkdir -p %{buildroot}%{_sysconfdir}/init.d
%endif
mkdir -p %{buildroot}%{_localstatedir}/log/salt
mkdir -p %{buildroot}/%{_sysconfdir}/logrotate.d/
mkdir -p %{buildroot}/%{_sbindir}
@ -165,92 +178,102 @@ mkdir -p %{buildroot}/var/log/salt
mkdir -p %{buildroot}/srv/salt
mkdir -p %{buildroot}/srv/pillar
#
##init scripts
## install init scripts
%if 0%{?_unitdir:1}
install -Dpm 0644 %{SOURCE4} %{buildroot}%_unitdir/salt-master.service
install -Dpm 0644 %{SOURCE5} %{buildroot}%_unitdir/salt-syndic.service
install -Dpm 0644 %{SOURCE6} %{buildroot}%_unitdir/salt-minion.service
%else
install -Dpm 0755 %{SOURCE1} %{buildroot}%{_initddir}/salt-master
install -Dpm 0755 %{SOURCE2} %{buildroot}%{_initddir}/salt-syndic
install -Dpm 0755 %{SOURCE3} %{buildroot}%{_initddir}/salt-minion
ln -sf %{_initddir}/salt-master %{buildroot}%{_sbindir}/rcsalt-master
ln -sf %{_initddir}/salt-syndic %{buildroot}%{_sbindir}/rcsalt-syndic
ln -sf %{_initddir}/salt-minion %{buildroot}%{_sbindir}/rcsalt-minion
%if 0%{?_unitdir:1}
install -Dpm 0644 %{SOURCE4} %{buildroot}%_unitdir/salt-master.service
install -Dpm 0644 %{SOURCE5} %{buildroot}%_unitdir/salt-syndic.service
install -Dpm 0644 %{SOURCE6} %{buildroot}%_unitdir/salt-minion.service
%endif
#
##config files
## install config files
install -Dpm 0644 conf/minion %{buildroot}%{_sysconfdir}/salt/minion
install -Dpm 0644 conf/master %{buildroot}%{_sysconfdir}/salt/master
#
##logrotate file
## install logrotate file
install -Dpm 0644 %{SOURCE7} %{buildroot}%{_sysconfdir}/logrotate.d/salt
#
##SuSEfirewall2 file
## install SuSEfirewall2 rules
install -Dpm 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/salt
%if 0%{?suse_version} != 1220 && 0%{?suse_version} != 1230
%check
#export only_local_network=False
%{__python} setup.py test --runtests-opts=-u
%endif
%preun -n salt-syndic
%stop_on_removal salt-syndic
%if 0%{?_unitdir:1}
%service_del_preun salt-syndic.service
%else
%stop_on_removal salt-syndic
%endif
%post -n salt-syndic
%fillup_and_insserv
%if 0%{?_unitdir:1}
%service_add_post salt-syndic.service
%fillup_only
%else
%fillup_and_insserv
%endif
%postun -n salt-syndic
%restart_on_update salt-syndic
%if 0%{?_unitdir:1}
%service_del_postun salt-syndic.service
%endif
%else
%insserv_cleanup
%restart_on_update salt-syndic
%endif
%preun -n salt-master
%stop_on_removal salt-master
%if 0%{?_unitdir:1}
%service_del_preun salt-master.service
%else
%stop_on_removal salt-master
%endif
%post -n salt-master
%fillup_and_insserv
%if 0%{?_unitdir:1}
%service_add_post salt-master.service
%fillup_only
%else
%fillup_and_insserv
%endif
%postun -n salt-master
%restart_on_update salt-master
%if 0%{?_unitdir:1}
%service_del_postun salt-master.service
%endif
%else
%restart_on_update salt-master
%insserv_cleanup
%endif
%preun -n salt-minion
%stop_on_removal salt-minion
%if 0%{?_unitdir:1}
%service_del_preun salt-minion.service
%else
%stop_on_removal salt-minion
%endif
%post -n salt-minion
%fillup_and_insserv
%if 0%{?_unitdir:1}
%service_add_post salt-minion.service
%fillup_only
%else
%fillup_and_insserv
%endif
%postun -n salt-minion
%restart_on_update salt-minion
%if 0%{?_unitdir:1}
%service_del_postun salt-minion.service
%endif
%else
%insserv_cleanup
%restart_on_update salt-minion
%endif
%files -n salt-ssh
%defattr(-,root,root)
@ -261,22 +284,24 @@ install -Dpm 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2
%defattr(-,root,root)
%{_bindir}/salt-syndic
%{_mandir}/man1/salt-syndic.1.gz
%{_sbindir}/rcsalt-syndic
%{_sysconfdir}/init.d/salt-syndic
%if 0%{?_unitdir:1}
%_unitdir/salt-syndic.service
%else
%{_sbindir}/rcsalt-syndic
%{_sysconfdir}/init.d/salt-syndic
%endif
%files -n salt-minion
%defattr(-,root,root)
%{_bindir}/salt-minion
%{_mandir}/man1/salt-minion.1.gz
%{_sbindir}/rcsalt-minion
%config(noreplace) %{_sysconfdir}/init.d/salt-minion
%attr(0644, root, root) %config(noreplace) %{_sysconfdir}/salt/minion
%{_sysconfdir}/salt/minion.d
%if 0%{?_unitdir:1}
%_unitdir/salt-minion.service
%else
%{_sbindir}/rcsalt-minion
%config(noreplace) %{_sysconfdir}/init.d/salt-minion
%endif
%files -n salt-master
@ -291,8 +316,6 @@ install -Dpm 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2
%{_mandir}/man1/salt-cp.1.gz
%{_mandir}/man1/salt-key.1.gz
%{_mandir}/man1/salt-run.1.gz
%{_sbindir}/rcsalt-master
%config(noreplace) %{_sysconfdir}/init.d/salt-master
%config(noreplace) %{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/salt
%attr(0644, root, root) %config(noreplace) %{_sysconfdir}/salt/master
%{_sysconfdir}/salt/master.d
@ -300,6 +323,9 @@ install -Dpm 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2
%dir /srv/pillar
%if 0%{?_unitdir:1}
%_unitdir/salt-master.service
%else
%{_sbindir}/rcsalt-master
%config(noreplace) %{_sysconfdir}/init.d/salt-master
%endif
%files

View File

@ -12,7 +12,6 @@
!include "nsDialogs.nsh"
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!include "nsProcess.nsh"; using plugin nsProcess
Var Dialog
Var Label
@ -127,9 +126,8 @@ ShowUnInstDetails show
Section "MainSection" SEC01
Exec "sc stop salt-minion" ;stopping service before upgrading
${nsProcess::CloseProcess} "salt-minion.exe" $R0
${nsProcess::Unload}
ExecWait "net stop salt-minion" ;stopping service before upgrading
Sleep 3000
SetOutPath "$INSTDIR\"
SetOverwrite try
CreateDirectory $INSTDIR\conf\pki\minion
@ -155,7 +153,7 @@ SectionEnd
Function .onInstSuccess
Exec "nssm.exe install salt-minion $INSTDIR\salt-minion.exe -c $INSTDIR\conf -l quiet"
RMDir /R "$INSTDIR\var\cache\salt" ; removing cache from old version
Exec "sc start salt-minion"
ExecWait "net start salt-minion"
FunctionEnd
Function un.onUninstSuccess
@ -191,8 +189,8 @@ Function .onInit
FunctionEnd
Section Uninstall
Exec "sc stop salt-minion"
Exec "sc delete salt-minion"
ExecWait "net stop salt-minion"
ExecWait "sc delete salt-minion"
Delete "$INSTDIR\uninst.exe"
Delete "$INSTDIR\nssm.exe"
Delete "$INSTDIR\python*"

View File

@ -59,6 +59,23 @@ SSH_SHIM = '''/bin/sh << 'EOF'
fi
done
SALT=/tmp/.salt/salt-call
if [ {{2}} == 'md5' ]
then
for md5_candidate in \\
md5sum \\
md5 ;
do
if [ $(which $md5_candidate 2>/dev/null) ]
then
SUMCHECK=$(which $md5_candidate)
break
fi
done
else
SUMCHECK={{2}}
fi
if [ -f $SALT ]
then
if [ $(cat /tmp/.salt/version) != {0} ]
@ -80,7 +97,7 @@ SSH_SHIM = '''/bin/sh << 'EOF'
fi
if [ -f /tmp/.salt/salt-thin.tgz ]
then
[ $({{2}}sum /tmp/.salt/salt-thin.tgz | cut -f1 -d' ') = {{3}} ] && {{0}} tar xzvf /tmp/.salt/salt-thin.tgz -C /tmp/.salt
[ $($SUMCHECK /tmp/.salt/salt-thin.tgz | cut -f1 -d' ') = {{3}} ] && {{0}} tar xzvf /tmp/.salt/salt-thin.tgz -C /tmp/.salt
else
install -m 0700 -d /tmp/.salt
echo "{1}"
@ -170,7 +187,7 @@ class SSH(object):
if deploy.startswith(('n', 'N')):
return ret
target['passwd'] = getpass.getpass(
'Password for {0}@{1}:'.format(host, target['user'])
'Password for {0}@{1}:'.format(target['user'], host)
)
return self._key_deploy_run(host, target, True)
return ret

View File

@ -664,7 +664,7 @@ def syndic_config(master_config_path,
return opts
def get_id(root_dir=None):
def get_id(root_dir=None, minion_id=False):
'''
Guess the id of the minion.
@ -704,11 +704,12 @@ def get_id(root_dir=None):
fqdn = socket.getfqdn()
if fqdn != 'localhost':
log.info('Found minion id from getfqdn(): {0}'.format(fqdn))
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(fqdn)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'.format(exc))
if minion_id:
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(fqdn)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'.format(exc))
return fqdn, False
# Check /etc/hostname
@ -720,11 +721,12 @@ def get_id(root_dir=None):
'This file should not contain any whitespace.')
else:
if name != 'localhost':
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'.format(exc))
if minion_id:
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'.format(exc))
return name, False
except (IOError, OSError):
pass
@ -740,12 +742,13 @@ def get_id(root_dir=None):
if name != 'localhost':
log.info('Found minion id in hosts file: {0}'
.format(name))
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'
.format(exc))
if minion_id:
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'
.format(exc))
return name, False
except (IOError, OSError):
pass
@ -766,12 +769,13 @@ def get_id(root_dir=None):
if name != 'localhost':
log.info('Found minion id in hosts file: {0}'
.format(name))
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'
.format(exc))
if minion_id:
try:
with salt.utils.fopen(id_cache, 'w') as idf:
idf.write(name)
except (IOError, OSError) as exc:
log.error('Could not cache minion ID: {0}'
.format(exc))
return name, False
except IndexError:
pass # could not split line (malformed entry?)
@ -830,8 +834,9 @@ def apply_minion_config(overrides=None,
# No ID provided. Will getfqdn save us?
using_ip_for_id = False
if opts['id'] is None and minion_id:
opts['id'], using_ip_for_id = get_id(opts['root_dir'])
if opts['id'] is None:
opts['id'], using_ip_for_id = get_id(opts['root_dir'],
minion_id=minion_id)
# it does not make sense to append a domain to an IP based id
if not using_ip_for_id and 'append_domain' in opts:

View File

@ -141,14 +141,21 @@ def _linux_gpu_data():
'The `lspci` binary is not available on the system. GPU grains '
'will not be available.'
)
return {}
return {}
<<<<<<< HEAD
elif __opts__.get('enable_gpu_grains', None) is False:
log.info(
'Skipping lspci call because enable_gpu_grains was set to False in the config. '
'GPU grains will not be available.'
)
return {}
elif __opts__.get('enable_gpu_grains', None) is False:
log.info(
'Skipping lspci call because enable_gpu_grains was set to False in the config. '
'GPU grains will not be available.'
)
return {}
# dominant gpu vendors to search for (MUST be lowercase for matching below)
known_vendors = ['nvidia', 'amd', 'ati', 'intel']

View File

@ -276,7 +276,6 @@ class MasterMinion(object):
self.mk_rend = rend
self.mk_matcher = matcher
self.gen_modules()
self.grains_cache = self.opts['grains']
def gen_modules(self):
'''
@ -502,6 +501,7 @@ class Minion(object):
self.opts,
self.functions,
self.returners)
self.grains_cache = self.opts['grains']
def __prep_mod_opts(self):
'''
@ -930,7 +930,6 @@ class Minion(object):
}
})
@property
def master_pub(self):
'''
@ -1160,13 +1159,13 @@ class Minion(object):
if self.opts['grains_refresh_every']: # If exists and is not zero. In minutes, not seconds!
if self.opts['grains_refresh_every'] > 1:
log.debug(
"Enabling the grains refresher. Will run every {0} minutes.".format\
(self.opts['grains_refresh_every'])
'Enabling the grains refresher. Will run every {0} minutes.'.format(
self.opts['grains_refresh_every'])
)
else: # Clean up minute vs. minutes in log message
log.debug(
"Enabling the grains refresher. Will run every {0} minute.".format\
(self.opts['grains_refresh_every'])
'Enabling the grains refresher. Will run every {0} minute.'.format(
self.opts['grains_refresh_every'])
)
self._refresh_grains_watcher(

View File

@ -384,11 +384,10 @@ def install(name=None,
if pkg_params is None or len(pkg_params) == 0:
return {}
elif pkg_type == 'file':
cmd = 'dpkg -i {confold} {verify} {pkg}'.format(
confold='--force-confold',
verify='--force-bad-verify' if skip_verify else '',
pkg=' '.join(pkg_params),
)
cmd = ['dpkg', '-i', '--force-confold']
if skip_verify:
cmd.append('--force-bad-verify')
cmd.extend(pkg_params)
elif pkg_type == 'repository':
if pkgs is None and kwargs.get('version') and len(pkg_params) == 1:
# Only use the 'version' param if 'name' was not specified as a

View File

@ -142,3 +142,42 @@ def inodeusage(args=None):
log.warn("Problem parsing inode usage information")
ret = {}
return ret
def percent(args=None):
'''
Return partion information for volumes mounted on this minion
CLI Example::
salt '*' disk.percent /var
'''
if __grains__['kernel'] == 'Linux':
cmd = 'df -P'
elif __grains__['kernel'] == 'OpenBSD':
cmd = 'df -kP'
else:
cmd = 'df'
ret = {}
out = __salt__['cmd.run'](cmd).splitlines()
for line in out:
if not line:
continue
if line.startswith('Filesystem'):
continue
comps = line.split()
while not comps[1].isdigit():
comps[0] = '{0} {1}'.format(comps[0], comps[1])
comps.pop(1)
try:
if __grains__['kernel'] == 'Darwin':
ret[comps[8]] = comps[4]
else:
ret[comps[5]] = comps[4]
except IndexError:
log.warn("Problem parsing disk usage information")
ret = {}
if args:
return ret[args]
else:
return ret

View File

@ -40,6 +40,7 @@ except ImportError:
import salt.utils
import salt.utils.find
import salt.utils.filebuffer
import salt.utils.atomicfile
from salt.exceptions import CommandExecutionError, SaltInvocationError
import salt._compat
@ -989,6 +990,154 @@ def replace(path,
return has_changes
def blockreplace(path,
marker_start='#-- start managed zone --',
marker_end='#-- end managed zone --',
content='',
append_if_not_found=False,
backup='.bak',
dry_run=False,
show_changes=True,
):
'''
Replace content of a text block in a file, delimited by line markers
.. versionadded:: 0.18.0
A block of content delimited by comments can help you manage several lines entries without
worrying about old entries removal.
Note: this function will store two copies of the file in-memory
(the original version and the edited version) in order to detect changes
and only edit the targeted file if necessary.
:param path: Filesystem path to the file to be edited
:param marker_start: The line content identifying a line as the start of
the content block. Note that the whole line containing this marker will
be considered, so whitespaces or extra content before or after the
marker is included in final output
:param marker_end: The line content identifying a line as the end of
the content block. Note that the whole line containing this marker will
be considered, so whitespaces or extra content before or after the
marker is included in final output
:param content: The content to be used between the two lines identified by
marker_start and marker_stop.
:param append_if_not_found: False by default, if markers are not found and
set to True then the markers and content will be appended to the file
:param backup: The file extension to use for a backup of the file if any
edit is made. Set to ``False`` to skip making a backup.
:param dry_run: Don't make any edits to the file
:param show_changes: Output a unified diff of the old file and the new
file. If ``False`` return a boolean if any changes were made.
:rtype: bool or str
CLI Example:
.. code-block:: bash
salt '*' file.blockreplace /etc/hosts '#-- start managed zone foobar : DO NOT EDIT --' \
'#-- end managed zone foobar --' $'10.0.1.1 foo.foobar\n10.0.1.2 bar.foobar' True
'''
if not os.path.exists(path):
raise SaltInvocationError("File not found: %s", path)
if not salt.utils.istextfile(path):
raise SaltInvocationError(
"Cannot perform string replacements on a binary file: %s", path)
# Search the file; track if any changes have been made for the return val
has_changes = False
orig_file = []
new_file = []
in_block = False
old_content = ''
done = False
# we do not use in_place editing to avoid file attrs modifications when
# no changes are required and to avoid any file access on a partially
# written file.
# we could also use salt.utils.filebuffer.BufferedReader
for line in fileinput.input(path,
inplace=False, backup=False,
bufsize=1, mode='rb'):
result = line
if marker_start in line:
# managed block start found, start recording
in_block = True
else:
if in_block:
if marker_end in line:
# end of block detected
in_block = False
# push new block content in file
for cline in content.split("\n"):
new_file.append(cline+"\n")
done = True
else:
# remove old content, but keep a trace
old_content += line
result = None
# else: we are not in the marked block, keep saving things
orig_file.append(line)
if result is not None:
new_file.append(result)
# end for. If we are here without block managment we maybe have some problems,
# or we need to initialise the marked block
if in_block:
# unterminated block => bad, always fail
raise CommandExecutionError("Unterminated marked block. End of file reached before marker_end.")
if not done:
if append_if_not_found:
# add the markers and content at the end of file
new_file.append(marker_start + '\n')
new_file.append(content + '\n')
new_file.append(marker_end + '\n')
done = True
else:
raise CommandExecutionError("Cannot edit marked block. Markers were not found in file.")
if done:
diff = ''.join(difflib.unified_diff(orig_file, new_file))
has_changes = diff is not ''
if has_changes and not dry_run:
# changes detected
# backup old content
if backup is not False:
shutil.copy2(path, '{0}{1}'.format(path, backup))
# backup file attrs
perms = {}
perms['user'] = get_user(path)
perms['group'] = get_group(path)
perms['mode'] = __salt__['config.manage_mode'](get_mode(path))
# write new content in the file while avoiding partial reads
f = salt.utils.atomicfile.atomic_open(path, 'wb')
for line in new_file:
f.write(line)
f.close()
# this may have overwritten file attrs
check_perms(path,
None,
perms['user'],
perms['group'],
perms['mode'])
if show_changes:
return diff
return has_changes
def search(path,
pattern,
flags=0,
@ -2523,12 +2672,11 @@ def mknod(name,
def list_backups(path, limit=None):
'''
.. note::
This function will be available in version 0.17.0.
Lists the previous versions of a file backed up using Salt's :doc:`file
state backup </ref/states/backup_mode>` system.
.. versionadded:: 0.17.0
path
The path on the minion to check for backups
limit
@ -2579,12 +2727,11 @@ list_backup = list_backups
def restore_backup(path, backup_id):
'''
.. note::
This function will be available in version 0.17.0.
Restore a previous version of a file that was backed up using Salt's
:doc:`file state backup </ref/states/backup_mode>` system.
.. versionadded:: 0.17.0
path
The path on the minion to check for backups
backup_id
@ -2639,12 +2786,11 @@ def restore_backup(path, backup_id):
def delete_backup(path, backup_id):
'''
.. note::
This function will be available in version 0.17.0.
Restore a previous version of a file that was backed up using Salt's
:doc:`file state backup </ref/states/backup_mode>` system.
.. versionadded:: 0.17.0
path
The path on the minion to check for backups
backup_id

View File

@ -3,6 +3,10 @@
Module to provide MySQL compatibility to salt.
:depends: - MySQLdb Python module
.. note::
On CentOS 5 (and possibly RHEL 5) both MySQL-python and python26-mysqldb need to be installed.
:configuration: In order to connect to MySQL, certain configuration is required
in /etc/salt/minion on the relevant minions. Some sample configs might look
like::
@ -30,13 +34,11 @@ import time
import logging
import re
import sys
import shlex
# Import salt libs
import salt.utils
#import shlex which should be distributed with Python
import shlex
# Import third party libs
try:
import MySQLdb
@ -187,7 +189,7 @@ def _grant_to_tokens(grant):
continue
if phrase == 'grants':
if token[-1:] == ',' or exploded_grant[position_tracker+1] == 'ON': # Read-ahead
if token.endswith(',') or exploded_grant[position_tracker+1] == 'ON': # Read-ahead
cleaned_token = token.rstrip(',')
if multiword_statement:
multiword_statement.append(cleaned_token)
@ -208,14 +210,10 @@ def _grant_to_tokens(grant):
position_tracker += 1
return {
'user': user,
'host': host,
'grant': grant_tokens,
'database': database,
}
return dict(user=user,
host=host,
grant=grant_tokens,
database=database)
def query(database, query, **connection_args):
@ -968,6 +966,15 @@ def user_remove(user,
return False
def tokenize_grant(grant):
'''
External wrapper function
:param grant:
:return: dict
'''
return _grant_to_tokens(grant)
# Maintenance
def db_check(name,
table=None,
@ -1142,9 +1149,6 @@ def grant_exists(grant,
salt '*' mysql.grant_exists 'SELECT,INSERT,UPDATE,...' 'database.*' 'frank' 'localhost'
'''
# TODO: This function is a bit tricky, since it requires the ordering to
# be exactly the same. Perhaps should be replaced/reworked with a
# better/cleaner solution.
target = __grant_generate(
grant, database, user, host, grant_option, escape
)
@ -1154,17 +1158,18 @@ def grant_exists(grant,
for grant in grants:
try:
target_tokens = None
if not target_tokens: # Avoid the overhead of re-calc in loop
if not target_tokens: # Avoid the overhead of re-calc in loop
target_tokens = _grant_to_tokens(target)
grant_tokens = _grant_to_tokens(grant)
if grant_tokens['user'] == target_tokens['user'] and \
grant_tokens['database'] == target_tokens['database'] and \
grant_tokens['host'] == target_tokens['host']:
if set(grant_tokens['grant']) == set(target_tokens['grant']):
return True
grant_tokens['database'] == target_tokens['database'] and \
grant_tokens['host'] == target_tokens['host'] and \
set(grant_tokens['grant']) == set(target_tokens['grant']):
log.debug(grant_tokens)
log.debug(target_tokens)
return True
except Exception as exc: # Fallback to strict parsing
log.debug("OH NO CAUGHT EXCEPTION: {0}".format(exc))
if grants is not False and target in grants:
log.debug('Grant exists.')
return True
@ -1173,7 +1178,6 @@ def grant_exists(grant,
return False
def grant_add(grant,
database,
user,

View File

@ -428,7 +428,7 @@ def list_(profile=None):
def server_list(profile=None):
'''
Return detailed information for an active server
Return list of active servers
CLI Example:
@ -443,6 +443,12 @@ def server_list(profile=None):
'id': item.id,
'name': item.name,
'status': item.status,
'accessIPv4': item.accessIPv4,
'accessIPv6': item.accessIPv6,
'flavor': {'id': item.flavor['id'],
'links': item.flavor['links']},
'image': {'id': item.image['id'],
'links': item.image['links']},
}
return ret
@ -455,45 +461,43 @@ def show(server_id, profile=None):
return server_show(server_id, profile)
def server_show(server_id, profile=None):
def server_list_detailed(profile=None):
'''
Return detailed information for an active server
Return detailed list of active servers
CLI Example:
.. code-block:: bash
salt '*' nova.show
salt '*' nova.server_list_detailed
'''
nt_ks = _auth(profile)
ret = {}
for item in nt_ks.servers.list():
if item.id == server_id:
ret[item.name] = {
'OS-EXT-SRV-ATTR': {},
'OS-EXT-STS': {},
'accessIPv4': item.accessIPv4,
'accessIPv6': item.accessIPv6,
'addresses': item.addresses,
'config_drive': item.config_drive,
'created': item.created,
'flavor': {'id': item.flavor['id'],
'links': item.flavor['links']},
'hostId': item.hostId,
'id': item.id,
'image': {'id': item.image['id'],
'links': item.image['links']},
'key_name': item.key_name,
'links': item.links,
'metadata': item.metadata,
'name': item.name,
'progress': item.progress,
'security_groups': item.security_groups,
'status': item.status,
'tenant_id': item.tenant_id,
'updated': item.updated,
'user_id': item.user_id,
}
ret[item.name] = {
'OS-EXT-SRV-ATTR': {},
'OS-EXT-STS': {},
'accessIPv4': item.accessIPv4,
'accessIPv6': item.accessIPv6,
'addresses': item.addresses,
'config_drive': item.config_drive,
'created': item.created,
'flavor': {'id': item.flavor['id'],
'links': item.flavor['links']},
'hostId': item.hostId,
'id': item.id,
'image': {'id': item.image['id'],
'links': item.image['links']},
'key_name': item.key_name,
'links': item.links,
'metadata': item.metadata,
'name': item.name,
'progress': item.progress,
'status': item.status,
'tenant_id': item.tenant_id,
'updated': item.updated,
'user_id': item.user_id,
}
if hasattr(item.__dict__, 'OS-DCF:diskConfig'):
ret[item.name]['OS-DCF'] = {
'diskConfig': item.__dict__['OS-DCF:diskConfig']
@ -510,6 +514,27 @@ def server_show(server_id, profile=None):
ret[item.name]['OS-EXT-STS']['task_state'] = item.__dict__['OS-EXT-STS:task_state']
if hasattr(item.__dict__, 'OS-EXT-STS:vm_state'):
ret[item.name]['OS-EXT-STS']['vm_state'] = item.__dict__['OS-EXT-STS:vm_state']
if hasattr(item.__dict__, 'security_groups'):
ret[item.name]['security_groups'] = item.__dict__['security_groups']
return ret
def server_show(server_id, profile=None):
'''
Return detailed information for an active server
CLI Example:
.. code-block:: bash
salt '*' nova.server_show <server_id>
'''
ret = {}
server_list = server_list_detailed(profile)
for item in server_list:
id_ = server_list[item]['id']
if str(id_) == server_id:
ret[server_list[item]['name']] = server_list[item]
return ret

View File

@ -767,8 +767,9 @@ def list_(prefix=None,
raise CommandExecutionError(result['stderr'])
for line in result['stdout'].splitlines():
if line.startswith('-f'):
if line.startswith('-f') or line.startswith('#'):
# ignore -f line as it contains --find-links directory
# ignore comment lines
continue
elif line.startswith('-e'):
line = line.split('-e ')[1]

View File

@ -267,13 +267,13 @@ def do(cmdline=None, runas=None):
.. code-block:: bash
salt '*' rbenv.do "gem list bundler"
salt '*' rbenv.do "gem list bundler" deploy
salt '*' rbenv.do 'gem list bundler'
salt '*' rbenv.do 'gem list bundler' deploy
'''
path = _rbenv_path(runas)
result = __salt__['cmd.run_all'](
"env PATH={0}/shims:$PATH {1}".format(path, cmdline),
'env PATH={0}/shims:$PATH {1}'.format(path, cmdline),
runas=runas
)

View File

@ -60,6 +60,12 @@ def __virtual__():
# Disable on these platforms, specific service modules exist:
if __grains__['os'] in ('Ubuntu', 'Linaro', 'elementary OS'):
return __virtualname__
elif __grains__['os'] in ('Debian', 'Raspbian'):
debian_initctl = '/sbin/initctl'
if os.path.isfile(debian_initctl):
initctl_version = salt.modules.cmdmod._run_quiet(debian_initctl + ' version')
if 'upstart' in initctl_version:
return 'service'
return False

View File

@ -129,8 +129,11 @@ def ext_pillar(pillar,
if not os.path.isdir(path):
log.error('Virtualenv {} not a directory!'.format(path))
return {}
# load the virtualenv
sys.path.append(virtualenv.path_locations(env)[1] + '/site-packages/')
# load the virtualenv first
sys.path.insert(0,
os.path.join(
virtualenv.path_locations(env)[1],
'site-packages'))
# load the django project
sys.path.append(project_path)

View File

@ -18,7 +18,7 @@ import salt.key
import salt.client
import salt.output
FINGERPRINT_REGEX = re.compile(r"[a-f0-9]{2}:"*15 + r"[a-f0-9]{2}")
FINGERPRINT_REGEX = re.compile(r'^([a-f0-9]{2}:){15}([a-f0-9]{2})$')
def status(output=True):

View File

@ -2214,7 +2214,7 @@ class BaseHighState(object):
statefiles = fnmatch.filter(self.avail[env], sls_match)
if not statefiles:
# No matching sls file was found! Output an error
log.error(
all_errors.append(
'No matching sls found for \'{0}\' in env \'{1}\''
.format(sls_match, env)
)

View File

@ -1776,6 +1776,121 @@ def replace(name,
return ret
def blockreplace(name,
marker_start='#-- start managed zone --',
marker_end='#-- end managed zone --',
content='',
append_if_not_found=False,
backup='.bak',
show_changes=True):
'''
Maintain an edit in a file in a zone delimited by two line markers
.. versionadded:: 0.18.0
A block of content delimited by comments can help you manage several lines
entries without worrying about old entries removal. This can help you maintaining
an unmanaged file containing manual edits.
Note: this function will store two copies of the file in-memory
(the original version and the edited version) in order to detect changes
and only edit the targeted file if necessary.
:param name: Filesystem path to the file to be edited
:param marker_start: The line content identifying a line as the start of
the content block. Note that the whole line containing this marker will
be considered, so whitespaces or extra content before or after the
marker is included in final output
:param marker_end: The line content identifying a line as the end of
the content block. Note that the whole line containing this marker will
be considered, so whitespaces or extra content before or after the
marker is included in final output.
Note: you can use file.accumulated and target this state. All accumulated
datas dictionnaries content will be added as new lines in the content.
:param content: The content to be used between the two lines identified by
marker_start and marker_stop.
:param append_if_not_found: False by default, if markers are not found and
set to True then the markers and content will be appended to the file
:param backup: The file extension to use for a backup of the file if any
edit is made. Set to ``False`` to skip making a backup.
:param dry_run: Don't make any edits to the file
:param show_changes: Output a unified diff of the old file and the new
file. If ``False`` return a boolean if any changes were made.
:rtype: bool or str
Exemple of usage with an accumulator and with a variable::
{% set myvar = 42 %}
hosts-config-block-{{ myvar }}:
file.blockreplace:
- name: /etc/hosts
- marker_start: "# START managed zone {{ myvar }} -DO-NOT-EDIT-"
- marker_end: "# END managed zone {{ myvar }} --"
- content: 'First line of content'
- append_if_not_found: True
- backup: '.bak'
- show_changes: True
hosts-config-block-{{ myvar }}-accumulated1:
file.accumulated:
- filename: /etc/hosts
- name: my-accumulator-{{ myvar }}
- text: "text 2"
- require_in:
- file: foobar-config-block-{{ myvar }}
hosts-config-block-{{ myvar }}-accumulated2:
file.accumulated:
- filename: /etc/hosts
- name: my-accumulator-{{ myvar }}
- text: |
text 3
text 4
- require_in:
- file: foobar-config-block-{{ myvar }}
will generate and maintain a block of content in ``/etc/hosts``::
# START managed zone 42 -DO-NOT-EDIT-
First line of content
text 2
text 3
text 4
# END managed zone 42 --
'''
ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
check_res, check_msg = _check_file(name)
if not check_res:
return _error(ret, check_msg)
if name in _ACCUMULATORS:
accumulator = _ACCUMULATORS[name]
for acc, acc_content in accumulator.iteritems():
for line in acc_content:
if content == '':
content = line
else:
content += "\n" + line
changes = __salt__['file.blockreplace'](name,
marker_start,
marker_end,
content=content,
append_if_not_found=append_if_not_found,
backup=backup,
dry_run=__opts__['test'],
show_changes=show_changes)
if changes:
ret['changes'] = changes
ret['comment'] = 'Changes were made'
else:
ret['comment'] = 'No changes were made'
ret['result'] = True
return ret
def sed(name,
before,
after,
@ -2548,7 +2663,8 @@ def rename(name, source, force=False, makedirs=False):
def accumulated(name, filename, text, **kwargs):
'''
Prepare accumulator which can be used in template in file.managed state.
Accumulator dictionary becomes available in template.
Accumulator dictionary becomes available in template. It can also be used
in file.blockreplace.
name
Accumulator name

View File

@ -69,6 +69,7 @@ def present(name,
host='localhost',
grant_option=False,
escape=True,
revoke_first=False,
**connection_args):
'''
Ensure that the grant is present with the specified properties
@ -93,6 +94,22 @@ def present(name,
escape
Defines if the database value gets escaped or not. default: True
revoke_first
By default, MySQL will not do anything if you issue a command to grant
privileges that are more restrictive than what's already in place. This
effectively means that you cannot downgrade permissions without first
revoking permissions applied to a db.table/user pair first.
To have Salt forcibly revoke perms before applying a new grant, enable
the 'revoke_first options.
WARNING: This will *remove* permissions for a database before attempting to apply
new permissions. There is no guarantee that new permissions will be applied correctly
which can leave your database security in an unknown and potentially dangerous state.
Use with caution!
default: False
'''
comment = 'Grant {0} on {1} to {2}@{3} is already present'
ret = {'name': name,
@ -111,6 +128,19 @@ def present(name,
ret['comment'] = err
ret['result'] = False
return ret
if revoke_first:
# for each grant, break into tokens and see if its on the same user/db as ours. (there is probably only one)
for user_grant in __salt__['mysql.user_grants'](user, host, **connection_args):
if __salt__['mysql.tokenize_grant'](user_grant)['database'].replace('`', '')\
== database.replace('`', ''):
grant_to_revoke = ','.join(__salt__['mysql.tokenize_grant'](user_grant)['grant']).rstrip(',')
__salt__['mysql.grant_revoke'](grant_to_revoke,
database,
user,
host=host,
grant_option=grant_option,
escape=escape,
connection_args=connection_args) # Probably needs some ordering love
# The grant is not present, make it!
if __opts__['test']:

View File

@ -3,7 +3,7 @@
Control of entries in SSH authorized_key files.
===============================================
The information stored in a user's ssh authorized key file can be easily
The information stored in a user's SSH authorized key file can be easily
controlled via the ssh_auth state. Defaults can be set by the enc, options,
and comment keys. These defaults can be overridden by including them in the
name.
@ -116,19 +116,19 @@ def present(
config='.ssh/authorized_keys',
**kwargs):
'''
Verifies that the specified ssh key is present for the specified user
Verifies that the specified SSH key is present for the specified user
name
The ssh key to manage
The SSH key to manage
user
The user who owns the ssh authorized keys file to modify
The user who owns the SSH authorized keys file to modify
enc
Defines what type of key is being used, can be ecdsa ssh-rsa, ssh-dss
Defines what type of key is being used; can be ecdsa, ssh-rsa or ssh-dss
comment
The comment to be placed with the ssh public key
The comment to be placed with the SSH public key
source
The source file for the key(s). Can contain any number of public keys,
@ -237,15 +237,29 @@ def present(
return ret
def absent(name, user, config='.ssh/authorized_keys'):
def absent(name,
user,
enc='ssh-rsa',
comment='',
options=None,
config='.ssh/authorized_keys'):
'''
Verifies that the specified ssh key is absent
Verifies that the specified SSH key is absent
name
The ssh key to manage
The SSH key to manage
user
The user who owns the ssh authorized keys file to modify
The user who owns the SSH authorized keys file to modify
enc
Defines what type of key is being used; can be ecdsa, ssh-rsa or ssh-dss
comment
The comment to be placed with the SSH public key
options
The options passed to the key, pass a list object
config
The location of the authorized keys file relative to the user's home
@ -263,9 +277,9 @@ def absent(name, user, config='.ssh/authorized_keys'):
check = __salt__['ssh.check_key'](
user,
name,
'',
'',
[],
enc,
comment,
options or [],
config)
if check == 'update' or check == 'exists':
ret['result'] = None

View File

@ -220,7 +220,7 @@ def daemonize(redirect_out=True):
# not cleanly redirected and the parent process dies when the
# multiprocessing process attempts to access stdout or err.
if redirect_out:
dev_null = open('/dev/null', 'rw')
dev_null = open('/dev/null', 'w')
os.dup2(dev_null.fileno(), sys.stdin.fileno())
os.dup2(dev_null.fileno(), sys.stdout.fileno())
os.dup2(dev_null.fileno(), sys.stderr.fileno())

View File

@ -13,7 +13,8 @@ def mac(addr):
'''
valid = re.compile(r'''
(^([0-9A-F]{1,2}[-]){5}([0-9A-F]{1,2})$
|^([0-9A-F]{1,2}[:]){5}([0-9A-F]{1,2})$)
|^([0-9A-F]{1,2}[:]){5}([0-9A-F]{1,2})$
|^([0-9A-F]{1,2}[.]){5}([0-9A-F]{1,2})$)
''',
re.VERBOSE | re.IGNORECASE)
return valid.match(addr) is not None

View File

@ -69,7 +69,7 @@ class CMDModuleTest(integration.ModuleCase):
environment2 = os.environ.copy()
self.assertEquals(environment, environment2)
self.assertEqual(environment, environment2)
getpwnam_mock.assert_called_with('foobar')
loads_mock.assert_called_with('{}')

View File

@ -134,7 +134,7 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
)
changes = ret.values()[0]['changes']
self.assertEquals('<show_diff=False>', changes['diff'])
self.assertEqual('<show_diff=False>', changes['diff'])
def test_directory(self):
'''

View File

@ -282,21 +282,21 @@ class ConfigTestCase(TestCase):
)
syndic_opts.update(salt.minion.resolve_dns(syndic_opts))
# id & pki dir are shared & so configured on the minion side
self.assertEquals(syndic_opts['id'], 'minion')
self.assertEquals(syndic_opts['pki_dir'], '/tmp/salttest/pki')
self.assertEqual(syndic_opts['id'], 'minion')
self.assertEqual(syndic_opts['pki_dir'], '/tmp/salttest/pki')
# the rest is configured master side
self.assertEquals(syndic_opts['master_uri'], 'tcp://127.0.0.1:54506')
self.assertEquals(syndic_opts['master_port'], 54506)
self.assertEquals(syndic_opts['master_ip'], '127.0.0.1')
self.assertEquals(syndic_opts['master'], 'localhost')
self.assertEquals(syndic_opts['sock_dir'], '/tmp/salttest/minion_sock')
self.assertEquals(syndic_opts['cachedir'], '/tmp/salttest/cachedir')
self.assertEquals(syndic_opts['log_file'], '/tmp/salttest/osyndic.log')
self.assertEquals(syndic_opts['pidfile'], '/tmp/salttest/osyndic.pid')
self.assertEqual(syndic_opts['master_uri'], 'tcp://127.0.0.1:54506')
self.assertEqual(syndic_opts['master_port'], 54506)
self.assertEqual(syndic_opts['master_ip'], '127.0.0.1')
self.assertEqual(syndic_opts['master'], 'localhost')
self.assertEqual(syndic_opts['sock_dir'], '/tmp/salttest/minion_sock')
self.assertEqual(syndic_opts['cachedir'], '/tmp/salttest/cachedir')
self.assertEqual(syndic_opts['log_file'], '/tmp/salttest/osyndic.log')
self.assertEqual(syndic_opts['pidfile'], '/tmp/salttest/osyndic.pid')
# Show that the options of localclient that repub to local master
# are not merged with syndic ones
self.assertEquals(syndic_opts['_master_conf_file'], minion_config_path)
self.assertEquals(syndic_opts['_minion_conf_file'], syndic_conf_path)
self.assertEqual(syndic_opts['_master_conf_file'], minion_config_path)
self.assertEqual(syndic_opts['_minion_conf_file'], syndic_conf_path)
def test_check_dns_deprecation_warning(self):
helium_version = SaltStackVersion.from_name('Helium')

View File

@ -6,17 +6,20 @@ import textwrap
# Import Salt Testing libs
from salttesting import TestCase
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import MagicMock
ensure_in_syspath('../../')
# Import Salt libs
from salt.modules import file as filemod
from salt.modules import cmdmod
from salt.exceptions import CommandExecutionError, SaltInvocationError
filemod.__salt__ = {
'cmd.run': cmdmod.run,
'cmd.run_all': cmdmod.run_all
}
filemod.__opts__ = {'test': False}
SED_CONTENT = """test
some
@ -101,6 +104,140 @@ class FileReplaceTestCase(TestCase):
def test_re_int_flags(self):
filemod.replace(self.tfile.name, r'Etiam', 'Salticus', flags=10)
class FileBlockReplaceTestCase(TestCase):
MULTILINE_STRING = textwrap.dedent('''\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam rhoncus
enim ac bibendum vulputate. Etiam nibh velit, placerat ac auctor in,
lacinia a turpis. Nulla elit elit, ornare in sodales eu, aliquam sit
amet nisl.
Fusce ac vehicula lectus. Vivamus justo nunc, pulvinar in ornare nec,
sollicitudin id sem. Pellentesque sed ipsum dapibus, dapibus elit id,
malesuada nisi.
first part of start line // START BLOCK : part of start line not removed
to be removed
first part of end line // END BLOCK : part of end line not removed
#-- START BLOCK UNFINISHED
#-- START BLOCK 1
old content part 1
old content part 2
#-- END BLOCK 1
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
venenatis tellus eget massa facilisis, in auctor ante aliquet. Sed nec
cursus metus. Curabitur massa urna, vehicula id porttitor sed, lobortis
quis leo.
''')
def setUp(self):
self.tfile = tempfile.NamedTemporaryFile(delete=False,prefix='blockrepltmp')
self.tfile.write(self.MULTILINE_STRING)
self.tfile.close()
manage_mode_mock = MagicMock()
filemod.__salt__['config.manage_mode'] = manage_mode_mock
def tearDown(self):
os.remove(self.tfile.name)
def test_replace_multiline(self):
new_multiline_content = "Who's that then?\nWell, how'd you become king, then?\nWe found them. I'm not a witch.\nWe shall say 'Ni' again to you, if you do not appease us."
filemod.blockreplace(self.tfile.name, '#-- START BLOCK 1', '#-- END BLOCK 1', new_multiline_content, backup=False)
with open(self.tfile.name, 'rb') as fp:
filecontent=fp.read()
self.assertIn('#-- START BLOCK 1'+"\n"+new_multiline_content+"\n"+'#-- END BLOCK 1', filecontent)
self.assertNotIn('old content part 1', filecontent)
self.assertNotIn('old content part 2', filecontent)
def test_replace_append(self):
new_content = "Well, I didn't vote for you."
self.assertRaises(
CommandExecutionError,
filemod.blockreplace,
self.tfile.name,
'#-- START BLOCK 2',
'#-- END BLOCK 2',
new_content,
append_if_not_found=False,
backup=False
)
with open(self.tfile.name, 'rb') as fp:
self.assertNotIn('#-- START BLOCK 2'+"\n"+new_content+"\n"+'#-- END BLOCK 2', fp.read())
filemod.blockreplace(self.tfile.name, '#-- START BLOCK 2', '#-- END BLOCK 2', new_content, backup=False,append_if_not_found=True)
with open(self.tfile.name, 'rb') as fp:
self.assertIn('#-- START BLOCK 2'+"\n"+new_content+"\n"+'#-- END BLOCK 2', fp.read())
def test_replace_partial_marked_lines(self):
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 1', backup=False)
with open(self.tfile.name, 'rb') as fp:
filecontent=fp.read()
self.assertIn('new content 1', filecontent)
self.assertNotIn('to be removed', filecontent)
self.assertIn('first part of start line', filecontent)
self.assertIn('first part of end line', filecontent)
self.assertIn('part of start line not removed', filecontent)
self.assertIn('part of end line not removed', filecontent)
def test_backup(self):
fext = '.bak'
bak_file = '{0}{1}'.format(self.tfile.name, fext)
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 2', backup=fext)
self.assertTrue(os.path.exists(bak_file))
os.unlink(bak_file)
self.assertFalse(os.path.exists(bak_file))
fext = '.bak'
bak_file = '{0}{1}'.format(self.tfile.name, fext)
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 3', backup=False)
self.assertFalse(os.path.exists(bak_file))
def test_no_modifications(self):
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 4', backup=False)
before_ctime = os.stat(self.tfile.name).st_mtime
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 4', backup=False)
after_ctime = os.stat(self.tfile.name).st_mtime
self.assertEqual(before_ctime, after_ctime)
def test_dry_run(self):
before_ctime = os.stat(self.tfile.name).st_mtime
filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 5', dry_run=True)
after_ctime = os.stat(self.tfile.name).st_mtime
self.assertEqual(before_ctime, after_ctime)
def test_show_changes(self):
ret = filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 6', backup=False, show_changes=True)
self.assertTrue(ret.startswith('---')) # looks like a diff
ret = filemod.blockreplace(self.tfile.name, '// START BLOCK', '// END BLOCK', 'new content 7', backup=False, show_changes=False)
self.assertIsInstance(ret, bool)
def test_unfinished_block_exception(self):
self.assertRaises(
CommandExecutionError,
filemod.blockreplace,
self.tfile.name,
'#-- START BLOCK UNFINISHED',
'#-- END BLOCK UNFINISHED',
'foobar',
backup=False
)
class FileModuleTestCase(TestCase):
def test_sed_limit_escaped(self):
@ -116,7 +253,7 @@ class FileModuleTestCase(TestCase):
filemod.sed(path, before, after, limit=limit)
with open(path, 'rb') as newfile:
self.assertEquals(
self.assertEqual(
SED_CONTENT.replace(before, ''),
newfile.read()
)
@ -149,4 +286,4 @@ class FileModuleTestCase(TestCase):
if __name__ == '__main__':
from integration import run_tests
run_tests(FileModuleTestCase, FileReplaceTestCase, needs_daemon=False)
run_tests(FileModuleTestCase, FileReplaceTestCase, FileBlockReplaceTestCase, needs_daemon=False)

View File

@ -29,7 +29,7 @@ class PostgresTestCase(TestCase):
postgres._run_psql('echo "hi"')
cmd = SALT_STUB['cmd.run_all']
self.assertEquals('postgres', cmd.call_args[1]['runas'])
self.assertEqual('postgres', cmd.call_args[1]['runas'])
if __name__ == '__main__':

View File

@ -39,16 +39,16 @@ class TestFileState(TestCase):
}
filestate.serialize('/tmp', dataset)
self.assertEquals(yaml.load(returner.returned), dataset)
self.assertEqual(yaml.load(returner.returned), dataset)
filestate.serialize('/tmp', dataset, formatter="yaml")
self.assertEquals(yaml.load(returner.returned), dataset)
self.assertEqual(yaml.load(returner.returned), dataset)
filestate.serialize('/tmp', dataset, formatter="json")
self.assertEquals(json.loads(returner.returned), dataset)
self.assertEqual(json.loads(returner.returned), dataset)
filestate.serialize('/tmp', dataset, formatter="python")
self.assertEquals(returner.returned, pprint.pformat(dataset))
self.assertEqual(returner.returned, pprint.pformat(dataset))
def test_contents_and_contents_pillar(self):
def returner(contents, *args, **kwargs):
@ -63,7 +63,7 @@ class TestFileState(TestCase):
filestate.__salt__['config.manage_mode'] = manage_mode_mock
ret = filestate.managed('/tmp/foo', contents='hi', contents_pillar='foo:bar')
self.assertEquals(False, ret['result'])
self.assertEqual(False, ret['result'])
def test_contents_pillar_adds_newline(self):
# make sure the newline
@ -105,10 +105,10 @@ class TestFileState(TestCase):
pillar_mock.assert_called_once_with(pillar_path)
# make sure no errors are returned
self.assertEquals(None, ret)
self.assertEqual(None, ret)
# make sure the value is correct
self.assertEquals(expected, returner.returned[1][-1])
self.assertEqual(expected, returner.returned[1][-1])
if __name__ == '__main__':
from integration import run_tests

View File

@ -292,7 +292,7 @@ class TestCustomExtensions(TestCase):
}
env = Environment(extensions=[SerializerExtension])
rendered = env.from_string('{{ dataset|json }}').render(dataset=dataset)
self.assertEquals(dataset, json.loads(rendered))
self.assertEqual(dataset, json.loads(rendered))
def test_serialize_yaml(self):
dataset = {
@ -303,7 +303,7 @@ class TestCustomExtensions(TestCase):
}
env = Environment(extensions=[SerializerExtension])
rendered = env.from_string('{{ dataset|yaml }}').render(dataset=dataset)
self.assertEquals(dataset, yaml.load(rendered))
self.assertEqual(dataset, yaml.load(rendered))
def test_serialize_python(self):
dataset = {
@ -314,16 +314,16 @@ class TestCustomExtensions(TestCase):
}
env = Environment(extensions=[SerializerExtension])
rendered = env.from_string('{{ dataset|python }}').render(dataset=dataset)
self.assertEquals(rendered, pprint.pformat(dataset))
self.assertEqual(rendered, pprint.pformat(dataset))
def test_load_yaml(self):
env = Environment(extensions=[SerializerExtension])
rendered = env.from_string('{% set document = "{foo: it works}"|load_yaml %}{{ document.foo }}').render()
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
rendered = env.from_string('{% set document = document|load_yaml %}'
'{{ document.foo }}').render(document="{foo: it works}")
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
with self.assertRaises(exceptions.TemplateRuntimeError):
env.from_string('{% set document = document|load_yaml %}'
@ -337,13 +337,13 @@ class TestCustomExtensions(TestCase):
'{{ docu.foo }}'
rendered = env.from_string(source).render(bar="barred")
self.assertEquals(rendered, u"barred, it works")
self.assertEqual(rendered, u"barred, it works")
source = '{{ bar }}, {% load_json as docu %}{"foo": "it works", "{{ bar }}": "baz"}{% endload %}' + \
'{{ docu.foo }}'
rendered = env.from_string(source).render(bar="barred")
self.assertEquals(rendered, u"barred, it works")
self.assertEqual(rendered, u"barred, it works")
with self.assertRaises(exceptions.TemplateSyntaxError):
env.from_string('{% load_yamle as document %}{foo, bar: it works}{% endload %}').render()
@ -356,11 +356,11 @@ class TestCustomExtensions(TestCase):
env = Environment(extensions=[SerializerExtension])
rendered = env.from_string('{% set document = \'{"foo": "it works"}\'|load_json %}'
'{{ document.foo }}').render()
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
rendered = env.from_string('{% set document = document|load_json %}'
'{{ document.foo }}').render(document='{"foo": "it works"}')
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
# bad quotes
with self.assertRaises(exceptions.TemplateRuntimeError):
@ -374,7 +374,7 @@ class TestCustomExtensions(TestCase):
loader = DictLoader({'foo': '{bar: "my god is blue", foo: [1, 2, 3]}'})
env = Environment(extensions=[SerializerExtension], loader=loader)
rendered = env.from_string('{% import_yaml "foo" as doc %}{{ doc.bar }}').render()
self.assertEquals(rendered, u"my god is blue")
self.assertEqual(rendered, u"my god is blue")
with self.assertRaises(exceptions.TemplateNotFound):
env.from_string('{% import_yaml "does not exists" as doc %}').render()
@ -383,7 +383,7 @@ class TestCustomExtensions(TestCase):
loader = DictLoader({'foo': '{"bar": "my god is blue", "foo": [1, 2, 3]}'})
env = Environment(extensions=[SerializerExtension], loader=loader)
rendered = env.from_string('{% import_json "foo" as doc %}{{ doc.bar }}').render()
self.assertEquals(rendered, u"my god is blue")
self.assertEqual(rendered, u"my god is blue")
with self.assertRaises(exceptions.TemplateNotFound):
env.from_string('{% import_json "does not exists" as doc %}').render()
@ -420,22 +420,22 @@ class TestCustomExtensions(TestCase):
env = Environment(extensions=[SerializerExtension], loader=loader)
rendered = env.get_template('main1').render()
self.assertEquals(rendered, u"my god is blue")
self.assertEqual(rendered, u"my god is blue")
rendered = env.get_template('main2').render()
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
rendered = env.get_template('main3').render().strip()
self.assertEquals(rendered, u"my god is blue")
self.assertEqual(rendered, u"my god is blue")
rendered = env.get_template('main4').render().strip()
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
rendered = env.get_template('main5').render().strip()
self.assertEquals(rendered, u"my god is blue")
self.assertEqual(rendered, u"my god is blue")
rendered = env.get_template('main6').render().strip()
self.assertEquals(rendered, u"it works")
self.assertEqual(rendered, u"it works")
# def test_print(self):
# env = Environment(extensions=[SerializerExtension])