mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 17:33:54 +00:00
Merge pull request #22900 from basepi/merge-forward-develop
Merge forward from 2015.2 to develop
This commit is contained in:
commit
3565816876
@ -102,6 +102,7 @@ disable=R,
|
|||||||
W0631,
|
W0631,
|
||||||
W0704,
|
W0704,
|
||||||
W1202,
|
W1202,
|
||||||
|
W1307,
|
||||||
F0220,
|
F0220,
|
||||||
F0401,
|
F0401,
|
||||||
E8501,
|
E8501,
|
||||||
@ -116,6 +117,7 @@ disable=R,
|
|||||||
E8129,
|
E8129,
|
||||||
E8131,
|
E8131,
|
||||||
E8265,
|
E8265,
|
||||||
|
E8266,
|
||||||
E8402,
|
E8402,
|
||||||
E8731
|
E8731
|
||||||
|
|
||||||
@ -151,9 +153,11 @@ disable=R,
|
|||||||
# F0220 (unresolved-interface)
|
# F0220 (unresolved-interface)
|
||||||
# F0401 (import-error)
|
# F0401 (import-error)
|
||||||
# W1202 (logging-format-interpolation) Use % formatting in logging functions but pass the % parameters as arguments
|
# W1202 (logging-format-interpolation) Use % formatting in logging functions but pass the % parameters as arguments
|
||||||
|
# W1307 (invalid-format-index) Using invalid lookup key '%s' in format specifier "0['%s']"
|
||||||
#
|
#
|
||||||
# E812* All PEP8 E12*
|
# E812* All PEP8 E12*
|
||||||
# E8265 PEP8 E265 - block comment should start with "# "
|
# E8265 PEP8 E265 - block comment should start with "# "
|
||||||
|
# E8266 PEP8 E266 - too many leading '#' for block comment
|
||||||
# E8501 PEP8 line too long
|
# E8501 PEP8 line too long
|
||||||
# E8402 module level import not at top of file
|
# E8402 module level import not at top of file
|
||||||
# E8731 do not assign a lambda expression, use a def
|
# E8731 do not assign a lambda expression, use a def
|
||||||
|
@ -20,6 +20,10 @@ minion exe>` should match the contents of the corresponding md5 file.
|
|||||||
|
|
||||||
.. admonition:: Download here
|
.. admonition:: Download here
|
||||||
|
|
||||||
|
* 2014.7.5
|
||||||
|
* `Salt-Minion-2014.7.5-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-x86-Setup.exe.md5>`__
|
||||||
|
* `Salt-Minion-2014.7.5-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.5-AMD64-Setup.exe.md5>`__
|
||||||
|
|
||||||
* 2014.7.4
|
* 2014.7.4
|
||||||
* `Salt-Minion-2014.7.4-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe.md5>`__
|
* `Salt-Minion-2014.7.4-x86-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-x86-Setup.exe.md5>`__
|
||||||
* `Salt-Minion-2014.7.4-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe.md5>`__
|
* `Salt-Minion-2014.7.4-AMD64-Setup.exe <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe>`__ | `md5 <http://docs.saltstack.com/downloads/Salt-Minion-2014.7.4-AMD64-Setup.exe.md5>`__
|
||||||
@ -35,9 +39,7 @@ minion exe>` should match the contents of the corresponding md5 file.
|
|||||||
* 2014.7.0
|
* 2014.7.0
|
||||||
* Salt-Minion-2014.7.0-1-win32-Setup.exe | md5
|
* Salt-Minion-2014.7.0-1-win32-Setup.exe | md5
|
||||||
* Salt-Minion-2014.7.0-AMD64-Setup.exe | md5
|
* Salt-Minion-2014.7.0-AMD64-Setup.exe | md5
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The 2014.7.0 installers have been removed because of a regression. Please use the 2014.7.1 release instead.
|
The 2014.7.0 installers have been removed because of a regression. Please use the 2014.7.1 release instead.
|
||||||
|
|
||||||
* 2014.1.13
|
* 2014.1.13
|
||||||
@ -135,7 +137,7 @@ minion exe>` should match the contents of the corresponding md5 file.
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The executables above will install all dependencies that the Salt minion
|
The executables above will install dependencies that the Salt minion
|
||||||
requires.
|
requires.
|
||||||
|
|
||||||
The 64bit installer has been tested on Windows 7 64bit and Windows Server
|
The 64bit installer has been tested on Windows 7 64bit and Windows Server
|
||||||
@ -163,7 +165,7 @@ line. The options `/master` and `/minion-name` allow for configuring the master
|
|||||||
hostname and minion name, respectively. Here's an example of using the silent
|
hostname and minion name, respectively. Here's an example of using the silent
|
||||||
installer:
|
installer:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bat
|
||||||
|
|
||||||
Salt-Minion-0.17.0-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname
|
Salt-Minion-0.17.0-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname
|
||||||
|
|
||||||
@ -171,142 +173,305 @@ installer:
|
|||||||
Setting up a Windows build environment
|
Setting up a Windows build environment
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
1. Install the Microsoft Visual C++ 2008 SP1 Redistributable, `vcredist_x86`_
|
This document will explain how to set up a development environment for salt on
|
||||||
or `vcredist_x64`_.
|
Windows. The development environment allows you to work with the source code to
|
||||||
|
customize or fix bugs. It will also allow you to build your own installation.
|
||||||
|
|
||||||
2. Install `msysgit`_
|
The Easy Way
|
||||||
|
------------
|
||||||
|
|
||||||
3. Clone the Salt git repository from GitHub
|
Prerequisite Software
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code-block:: bash
|
To do this the easy way you only need to install `Git for Windows <https://github.com/msysgit/msysgit/releases/download/Git-1.9.5-preview20150319/Git-1.9.5-preview20150319.exe/>`_.
|
||||||
|
|
||||||
git clone https://github.com/saltstack/salt.git
|
Create the Build Environment
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
4. Install the latest point release of `Python 2.7`_ for the architecture you
|
1. Clone the `Salt-Windows-Dev <https://github.com/saltstack/salt-windows-dev/>`_
|
||||||
wish to target
|
repo from github.
|
||||||
|
|
||||||
5. Add ``C:\\Python27`` and ``C:\\Python27\\Scripts`` to your system path
|
Open a command line and type:
|
||||||
|
|
||||||
6. Download and run the Setuptools bootstrap - `ez_setup.py`_
|
.. code-block:: bat
|
||||||
|
|
||||||
.. code-block:: bash
|
git clone https://github.com/saltstack/salt-windows-dev
|
||||||
|
|
||||||
python ez_setup.py
|
2. Build the Python Environment
|
||||||
|
|
||||||
7. Install Pip
|
Go into the salt-windows-dev directory. Right-click the file named
|
||||||
|
**dev_env.ps1** and select **Run with PowerShell**
|
||||||
|
|
||||||
.. code-block:: bash
|
If you get an error, you may need to change the execution policy.
|
||||||
|
|
||||||
easy_install pip
|
Open a powershell window and type the following:
|
||||||
|
|
||||||
8. Install the latest point release of `OpenSSL for Windows`_
|
.. code-block:: powershell
|
||||||
|
|
||||||
#. During setup, choose first option to install in Windows system
|
Set-ExecutionPolicy RemoteSigned
|
||||||
directory
|
|
||||||
|
|
||||||
9. Install the latest point release of `M2Crypto`_
|
This will download and install Python with all the dependencies needed to
|
||||||
|
develop and build salt.
|
||||||
|
|
||||||
#. In general, be sure to download installers targeted at py2.7 for your
|
3. Build the Salt Environment
|
||||||
chosen architecture
|
|
||||||
|
|
||||||
10. Install the latest point release of `pycrypto`_
|
Right-click on the file named **dev_env_salt.ps1** and select **Run with
|
||||||
|
Powershell**
|
||||||
|
|
||||||
11. Install the latest point release of `pywin32`_
|
This will clone salt into ``C:\Salt-Dev\salt`` and set it to the 2015.2
|
||||||
|
branch. You could optionally run the command from a powershell window with a
|
||||||
|
``-Version`` switch to pull a different version. For example:
|
||||||
|
|
||||||
12. Install the latest point release of `Cython`_
|
.. code-block:: powershell
|
||||||
|
|
||||||
13. Install the latest point release of `jinja2`_
|
dev_env_salt.ps1 -Version '2014.7'
|
||||||
|
|
||||||
14. Install the latest point release of `msgpack`_
|
To view a list of available branches and tags, open a command prompt in your
|
||||||
|
`C:\Salt-Dev\salt` directory and type:
|
||||||
|
|
||||||
15. Install psutil
|
.. code-block:: bat
|
||||||
|
|
||||||
.. code-block:: bash
|
git branch -a
|
||||||
|
git tag -n
|
||||||
easy_install psutil
|
|
||||||
|
|
||||||
16. Install pyzmq
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
easy_install pyzmq
|
|
||||||
|
|
||||||
17. Install PyYAML
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
easy_install pyyaml
|
|
||||||
|
|
||||||
18. Install bbfreeze
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
easy_install bbfreeze
|
|
||||||
|
|
||||||
19. Install wmi
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install wmi
|
|
||||||
|
|
||||||
20. Install requests
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install requests
|
|
||||||
|
|
||||||
21. Install markupsafe
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install markupsafe
|
|
||||||
|
|
||||||
22. Install six
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install six
|
|
||||||
|
|
||||||
23. Install esky
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install esky
|
|
||||||
|
|
||||||
24. Install certifi
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pip install certifi
|
|
||||||
|
|
||||||
25. Install Salt
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
cd salt
|
|
||||||
python setup.py install
|
|
||||||
|
|
||||||
26. Build a frozen binary distribution of Salt
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python setup.py bdist_esky
|
|
||||||
|
|
||||||
A zip file has been created in the ``dist/`` folder, containing a frozen copy
|
|
||||||
of Python and the dependency libraries, along with Windows executables for each
|
|
||||||
of the Salt scripts.
|
|
||||||
|
|
||||||
|
|
||||||
Building the installer
|
The Hard Way
|
||||||
======================
|
------------
|
||||||
|
|
||||||
The Salt Windows installer is built with the open-source NSIS compiler. The
|
Prerequisite Software
|
||||||
source for the installer is found in the pkg directory of the Salt repo here:
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
:blob:`pkg/windows/installer/Salt-Minion-Setup.nsi`. To create the installer,
|
|
||||||
extract the frozen archive from ``dist/`` into ``pkg/windows/buildenv/`` and
|
|
||||||
run NSIS.
|
|
||||||
|
|
||||||
The NSIS installer can be found here: http://nsis.sourceforge.net/Main_Page
|
Install the following software:
|
||||||
|
|
||||||
|
1. `Git for Windows <https://github.com/msysgit/msysgit/releases/download/Git-1.9.5-preview20150319/Git-1.9.5-preview20150319.exe/>`_
|
||||||
|
2. `Nullsoft Installer <http://downloads.sourceforge.net/project/nsis/NSIS%203%20Pre-release/3.0b1/nsis-3.0b1-setup.exe/>`_
|
||||||
|
|
||||||
|
Download the Prerequisite zip file for your CPU architecture from the
|
||||||
|
SaltStack download site:
|
||||||
|
|
||||||
|
* `Salt32.zip <http://docs.saltstack.com/downloads/windows-deps/Salt32.zip/>`_
|
||||||
|
* `Salt64.zip <http://docs.saltstack.com/downloads/windows-deps/Salt64.zip/>`_
|
||||||
|
|
||||||
|
These files contain all sofware required to build and develop salt. Unzip the
|
||||||
|
contents of the file to ``C:\Salt-Dev\temp``.
|
||||||
|
|
||||||
|
Create the Build Environment
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
1. Build the Python Environment
|
||||||
|
|
||||||
|
* Install Python:
|
||||||
|
|
||||||
|
Browse to the ``C:\Salt-Dev\temp`` directory and find the Python
|
||||||
|
installation file for your CPU Architecture under the corresponding
|
||||||
|
subfolder. Double-click the file to install python.
|
||||||
|
|
||||||
|
Make sure the following are in your **PATH** environment variable:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
C:\Python27
|
||||||
|
C:\Python27\Scripts
|
||||||
|
|
||||||
|
* Install Pip
|
||||||
|
|
||||||
|
Open a command prompt and navigate to ``C:\Salt-Dev\temp``
|
||||||
|
Run the following command:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
python get-pip.py
|
||||||
|
|
||||||
|
* Easy Install compiled binaries.
|
||||||
|
|
||||||
|
M2Crypto, PyCrypto, and PyWin32 need to be installed using Easy Install.
|
||||||
|
Open a command prompt and navigate to ``C:\Salt-Dev\temp\<cpuarch>``.
|
||||||
|
Run the following commands:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
easy_install -Z <M2Crypto file name>
|
||||||
|
easy_install -Z <PyCrypto file name>
|
||||||
|
easy_install -Z <PyWin32 file name>
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
You can type the first part of the file name and then press the tab key
|
||||||
|
to auto-complete the name of the file.
|
||||||
|
|
||||||
|
* Pip Install Additional Prerequisites
|
||||||
|
|
||||||
|
All remaining prerequisites need to be pip installed. These prerequisites
|
||||||
|
are as follow:
|
||||||
|
|
||||||
|
* MarkupSafe
|
||||||
|
* Jinja
|
||||||
|
* MsgPack
|
||||||
|
* PSUtil
|
||||||
|
* PyYAML
|
||||||
|
* PyZMQ
|
||||||
|
* WMI
|
||||||
|
* Requests
|
||||||
|
* Certifi
|
||||||
|
|
||||||
|
Open a command prompt and navigate to ``C:\Salt-Dev\temp``. Run the following
|
||||||
|
commands:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
pip install <cpuarch>\<MarkupSafe file name>
|
||||||
|
pip install <Jinja file name>
|
||||||
|
pip install <cpuarch>\<MsgPack file name>
|
||||||
|
pip install <cpuarch>\<psutil file name>
|
||||||
|
pip install <cpuarch>\<PyYAML file name>
|
||||||
|
pip install <cpuarch>\<pyzmq file name>
|
||||||
|
pip install <WMI file name>
|
||||||
|
pip install <requests file name>
|
||||||
|
pip install <certifi file name>
|
||||||
|
|
||||||
|
2. Build the Salt Environment
|
||||||
|
|
||||||
|
* Clone Salt
|
||||||
|
|
||||||
|
Open a command prompt and navigate to ``C:\Salt-Dev``. Run the following command
|
||||||
|
to clone salt:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
git clone https://github.com/saltstack/salt
|
||||||
|
|
||||||
|
* Checkout Branch
|
||||||
|
|
||||||
|
Checkout the branch or tag of salt you want to work on or build. Open a
|
||||||
|
command prompt and navigate to ``C:\Salt-Dev\salt``. Get a list of
|
||||||
|
available tags and branches by running the following commands:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
git fetch --all
|
||||||
|
|
||||||
|
To view a list of available branches:
|
||||||
|
git branch -a
|
||||||
|
|
||||||
|
To view a list of availabel tags:
|
||||||
|
git tag -n
|
||||||
|
|
||||||
|
Checkout the branch or tag by typing the following command:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
git checkout <branch/tag name>
|
||||||
|
|
||||||
|
* Clean the Environment
|
||||||
|
|
||||||
|
When switching between branches residual files can be left behind that
|
||||||
|
will interfere with the functionality of salt. Therefore, after you check
|
||||||
|
out the branch you want to work on, type the following commands to clean
|
||||||
|
the salt environment:
|
||||||
|
|
||||||
|
.. code-block: bat
|
||||||
|
|
||||||
|
git clean -fxd
|
||||||
|
git reset --hard HEAD
|
||||||
|
|
||||||
|
|
||||||
|
Developing with Salt
|
||||||
|
====================
|
||||||
|
There are two ways to develop with salt. You can run salt's setup.py each time
|
||||||
|
you make a change to source code or you can use the setup tools develop mode.
|
||||||
|
|
||||||
|
|
||||||
|
Configure the Minion
|
||||||
|
--------------------
|
||||||
|
Both methods require that the minion configuration be in the ``C:\salt``
|
||||||
|
directory. Copy the conf and var directories from ``C:\Salt-Dev\salt\pkg\
|
||||||
|
windows\buildenv`` to ``C:\salt``. Now go into the ``C:\salt\conf`` directory
|
||||||
|
and edit the file name ``minion`` (no extension). You need to configure the
|
||||||
|
master and id parameters in this file. Edit the following lines:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
master: <ip or name of your master>
|
||||||
|
id: <name of your minion>
|
||||||
|
|
||||||
|
Setup.py Method
|
||||||
|
---------------
|
||||||
|
Go into the ``C:\Salt-Dev\salt`` directory from a cmd prompt and type:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
python setup.py install --force
|
||||||
|
|
||||||
|
This will install python into your python installation at ``C:\Python27``.
|
||||||
|
Everytime you make an edit to your source code, you'll have to stop the minion,
|
||||||
|
run the setup, and start the minion.
|
||||||
|
|
||||||
|
To start the salt-minion go into ``C:\Python27\Scripts`` from a cmd prompt and
|
||||||
|
type:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
salt-minion
|
||||||
|
|
||||||
|
For debug mode type:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
salt-minion -l debug
|
||||||
|
|
||||||
|
To stop the minion press Ctrl+C.
|
||||||
|
|
||||||
|
|
||||||
|
Setup Tools Develop Mode (Preferred Method)
|
||||||
|
-------------------------------------------
|
||||||
|
To use the Setup Tools Develop Mode go into ``C:\Salt-Dev\salt`` from a cmd
|
||||||
|
prompt and type:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
pip install -e .
|
||||||
|
|
||||||
|
This will install pointers to your source code that resides at
|
||||||
|
``C:\Salt-Dev\salt``. When you edit your source code you only have to restart
|
||||||
|
the minion.
|
||||||
|
|
||||||
|
|
||||||
|
Build the windows installer
|
||||||
|
===========================
|
||||||
|
This is the method of building the installer as of version 2014.7.4.
|
||||||
|
|
||||||
|
Clean the Environment
|
||||||
|
---------------------
|
||||||
|
Make sure you don't have any leftover salt files from previous versions of salt
|
||||||
|
in your Python directory.
|
||||||
|
|
||||||
|
1. Remove all files that start with salt in the ``C:\Python27\Scripts``
|
||||||
|
directory
|
||||||
|
|
||||||
|
2. Remove all files and directorys that start with salt in the
|
||||||
|
``C:\Python27\Lib\site-packages`` directory
|
||||||
|
|
||||||
|
Install Salt
|
||||||
|
------------
|
||||||
|
Install salt using salt's setup.py. From the ``C:\Salt-Dev\salt`` directory
|
||||||
|
type the following command:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
python setup.py install --force
|
||||||
|
|
||||||
|
Build the Installer
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
From cmd prompt go into the ``C:\Salt-Dev\salt\pkg\windows`` directory. Type
|
||||||
|
the following command for the branch or tag of salt you're building:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
BuildSalt.bat <branch or tag>
|
||||||
|
|
||||||
|
This will copy python with salt installed to the ``buildenv\bin`` directory,
|
||||||
|
make it portable, and then create the windows installer . The .exe for the
|
||||||
|
windows installer will be placed in the ``installer`` directory.
|
||||||
|
|
||||||
|
|
||||||
Testing the Salt minion
|
Testing the Salt minion
|
||||||
@ -361,7 +526,7 @@ salt, including all dependencies:
|
|||||||
|
|
||||||
This script is not up to date. Please use the installer found above
|
This script is not up to date. Please use the installer found above
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: powershell
|
||||||
|
|
||||||
# (All in one line.)
|
# (All in one line.)
|
||||||
|
|
||||||
@ -381,12 +546,10 @@ Packages management under Windows 2003
|
|||||||
|
|
||||||
On windows Server 2003, you need to install optional component "wmi windows
|
On windows Server 2003, you need to install optional component "wmi windows
|
||||||
installer provider" to have full list of installed packages. If you don't have
|
installer provider" to have full list of installed packages. If you don't have
|
||||||
this, salt-minion can't report some installed packages.
|
this, salt-minion can't report some installed softwares.
|
||||||
|
|
||||||
|
|
||||||
.. _http://csa-net.dk/salt: http://csa-net.dk/salt
|
.. _http://csa-net.dk/salt: http://csa-net.dk/salt
|
||||||
.. _vcredist_x86: http://www.microsoft.com/en-us/download/details.aspx?id=5582
|
|
||||||
.. _vcredist_x64: http://www.microsoft.com/en-us/download/details.aspx?id=2092
|
|
||||||
.. _msysgit: http://code.google.com/p/msysgit/downloads/list?can=3
|
.. _msysgit: http://code.google.com/p/msysgit/downloads/list?can=3
|
||||||
.. _Python 2.7: http://www.python.org/downloads
|
.. _Python 2.7: http://www.python.org/downloads
|
||||||
.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
|
.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
|
||||||
@ -397,3 +560,4 @@ this, salt-minion can't report some installed packages.
|
|||||||
.. _Cython: http://www.lfd.uci.edu/~gohlke/pythonlibs/#cython
|
.. _Cython: http://www.lfd.uci.edu/~gohlke/pythonlibs/#cython
|
||||||
.. _jinja2: http://www.lfd.uci.edu/~gohlke/pythonlibs/#jinja2
|
.. _jinja2: http://www.lfd.uci.edu/~gohlke/pythonlibs/#jinja2
|
||||||
.. _msgpack: http://www.lfd.uci.edu/~gohlke/pythonlibs/#msgpack
|
.. _msgpack: http://www.lfd.uci.edu/~gohlke/pythonlibs/#msgpack
|
||||||
|
|
||||||
|
@ -59,14 +59,13 @@ be used to install it:
|
|||||||
If pygit2_ is not packaged for the platform on which the Master is running, the
|
If pygit2_ is not packaged for the platform on which the Master is running, the
|
||||||
pygit2_ website has installation instructions here__. Keep in mind however that
|
pygit2_ website has installation instructions here__. Keep in mind however that
|
||||||
following these instructions will install libgit2 and pygit2_ without system
|
following these instructions will install libgit2 and pygit2_ without system
|
||||||
packages. Also, while this is not explicitly mentioned in the pygit2_
|
packages. Additionally, keep in mind that :ref:`SSH authentication in pygit2
|
||||||
installation instructions, libssh2 development headers must be installed before
|
<pygit2-authentication-ssh>` requires libssh2_ (*not* libssh) development
|
||||||
building libgit2 in order to enable access to SSH-protected git repositories.
|
libraries to be present before libgit2 is built. On some distros (debian based)
|
||||||
Luckily, these are available in most distros' repositories, usually as either
|
``pkg-config`` is also required to link libgit2 with libssh2.
|
||||||
``libssh2-devel`` or ``libssh2-dev``, depending on platform. On some distros
|
|
||||||
(debian based) ``pkg-config`` is also required to link libgit2 with libssh2.
|
|
||||||
|
|
||||||
.. __: http://www.pygit2.org/install.html
|
.. __: http://www.pygit2.org/install.html
|
||||||
|
.. _libssh2: http://www.libssh2.org/
|
||||||
|
|
||||||
GitPython
|
GitPython
|
||||||
---------
|
---------
|
||||||
@ -544,6 +543,8 @@ an ``insecure_auth`` parameter:
|
|||||||
- password: mypassword
|
- password: mypassword
|
||||||
- insecure_auth: True
|
- insecure_auth: True
|
||||||
|
|
||||||
|
.. _pygit2-authentication-ssh:
|
||||||
|
|
||||||
SSH
|
SSH
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ Var MinionName_State
|
|||||||
!define MUI_ABORTWARNING
|
!define MUI_ABORTWARNING
|
||||||
!define MUI_ICON "salt.ico"
|
!define MUI_ICON "salt.ico"
|
||||||
!define MUI_UNICON "salt.ico"
|
!define MUI_UNICON "salt.ico"
|
||||||
|
!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
|
||||||
|
|
||||||
; Welcome page
|
; Welcome page
|
||||||
!insertmacro MUI_PAGE_WELCOME
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
BIN
pkg/windows/installer/panel.bmp
Normal file
BIN
pkg/windows/installer/panel.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
@ -291,10 +291,13 @@ class Shell(object):
|
|||||||
ret = self._run_cmd(cmd)
|
ret = self._run_cmd(cmd)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def send(self, local, remote):
|
def send(self, local, remote, makedirs=False):
|
||||||
'''
|
'''
|
||||||
scp a file or files to a remote system
|
scp a file or files to a remote system
|
||||||
'''
|
'''
|
||||||
|
if makedirs:
|
||||||
|
self.exec_cmd('mkdir -p {0}'.format(os.path.dirname(remote)))
|
||||||
|
|
||||||
cmd = '{0} {1}:{2}'.format(local, self.host, remote)
|
cmd = '{0} {1}:{2}'.format(local, self.host, remote)
|
||||||
cmd = self._cmd_str(cmd, ssh='scp')
|
cmd = self._cmd_str(cmd, ssh='scp')
|
||||||
|
|
||||||
|
@ -6,18 +6,39 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
# Import salt libs
|
# Import salt libs
|
||||||
import salt.client.ssh
|
import salt.client.ssh
|
||||||
|
import logging
|
||||||
|
from salt.exceptions import CommandExecutionError
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_file(path, dest, saltenv='base'):
|
def get_file(path,
|
||||||
|
dest,
|
||||||
|
saltenv='base',
|
||||||
|
makedirs=False,
|
||||||
|
template=None,
|
||||||
|
gzip=None):
|
||||||
'''
|
'''
|
||||||
Send a file from the master to the location in specified
|
Send a file from the master to the location in specified
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
gzip compression is not supported in the salt-ssh version of
|
||||||
|
cp.get_file. The argument is only accepted for interface compatibility.
|
||||||
'''
|
'''
|
||||||
|
if gzip is not None:
|
||||||
|
log.warning('The gzip argument to cp.get_file in salt-ssh is '
|
||||||
|
'unsupported')
|
||||||
|
|
||||||
|
if template is not None:
|
||||||
|
(path, dest) = _render_filenames(path, dest, saltenv, template)
|
||||||
|
|
||||||
src = __context__['fileclient'].cache_file(path, saltenv)
|
src = __context__['fileclient'].cache_file(path, saltenv)
|
||||||
single = salt.client.ssh.Single(
|
single = salt.client.ssh.Single(
|
||||||
__opts__,
|
__opts__,
|
||||||
'',
|
'',
|
||||||
**__salt__.kwargs)
|
**__salt__.kwargs)
|
||||||
ret = single.shell.send(src, dest)
|
ret = single.shell.send(src, dest, makedirs)
|
||||||
return not ret[2]
|
return not ret[2]
|
||||||
|
|
||||||
|
|
||||||
@ -74,3 +95,56 @@ def list_master_symlinks(saltenv='base', prefix=''):
|
|||||||
List all of the symlinks stored on the master
|
List all of the symlinks stored on the master
|
||||||
'''
|
'''
|
||||||
return __context__['fileclient'].symlink_list(saltenv, prefix)
|
return __context__['fileclient'].symlink_list(saltenv, prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def _render_filenames(path, dest, saltenv, template):
|
||||||
|
'''
|
||||||
|
Process markup in the :param:`path` and :param:`dest` variables (NOT the
|
||||||
|
files under the paths they ultimately point to) according to the markup
|
||||||
|
format provided by :param:`template`.
|
||||||
|
'''
|
||||||
|
if not template:
|
||||||
|
return (path, dest)
|
||||||
|
|
||||||
|
# render the path as a template using path_template_engine as the engine
|
||||||
|
if template not in salt.utils.templates.TEMPLATE_REGISTRY:
|
||||||
|
raise CommandExecutionError(
|
||||||
|
'Attempted to render file paths with unavailable engine '
|
||||||
|
'{0}'.format(template)
|
||||||
|
)
|
||||||
|
|
||||||
|
kwargs = {}
|
||||||
|
kwargs['salt'] = __salt__
|
||||||
|
kwargs['pillar'] = __pillar__
|
||||||
|
kwargs['grains'] = __grains__
|
||||||
|
kwargs['opts'] = __opts__
|
||||||
|
kwargs['saltenv'] = saltenv
|
||||||
|
|
||||||
|
def _render(contents):
|
||||||
|
'''
|
||||||
|
Render :param:`contents` into a literal pathname by writing it to a
|
||||||
|
temp file, rendering that file, and returning the result.
|
||||||
|
'''
|
||||||
|
# write out path to temp file
|
||||||
|
tmp_path_fn = salt.utils.mkstemp()
|
||||||
|
with salt.utils.fopen(tmp_path_fn, 'w+') as fp_:
|
||||||
|
fp_.write(contents)
|
||||||
|
data = salt.utils.templates.TEMPLATE_REGISTRY[template](
|
||||||
|
tmp_path_fn,
|
||||||
|
to_str=True,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
salt.utils.safe_rm(tmp_path_fn)
|
||||||
|
if not data['result']:
|
||||||
|
# Failed to render the template
|
||||||
|
raise CommandExecutionError(
|
||||||
|
'Failed to render file path with error: {0}'.format(
|
||||||
|
data['data']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return data['data']
|
||||||
|
|
||||||
|
path = _render(path)
|
||||||
|
dest = _render(dest)
|
||||||
|
return (path, dest)
|
||||||
|
@ -2083,7 +2083,7 @@ def create(vm_=None, call=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
node_data = conn.create_node(**kwargs) # pylint: disable=W0142
|
node_data = conn.create_node(**kwargs)
|
||||||
except Exception as exc: # pylint: disable=W0703
|
except Exception as exc: # pylint: disable=W0703
|
||||||
log.error(
|
log.error(
|
||||||
'Error creating {0} on GCE\n\n'
|
'Error creating {0} on GCE\n\n'
|
||||||
@ -2179,7 +2179,6 @@ def create(vm_=None, call=None):
|
|||||||
transport=__opts__['transport']
|
transport=__opts__['transport']
|
||||||
)
|
)
|
||||||
|
|
||||||
# pylint: disable=W0142
|
|
||||||
deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)
|
deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)
|
||||||
if deployed:
|
if deployed:
|
||||||
log.info('Salt installed on {0}'.format(vm_['name']))
|
log.info('Salt installed on {0}'.format(vm_['name']))
|
||||||
|
@ -573,6 +573,8 @@ def list_nodes(call=None):
|
|||||||
ret[node]['public_ips'] = nodes[node]['primaryIpAddress']
|
ret[node]['public_ips'] = nodes[node]['primaryIpAddress']
|
||||||
if 'primaryBackendIpAddress' in nodes[node]:
|
if 'primaryBackendIpAddress' in nodes[node]:
|
||||||
ret[node]['private_ips'] = nodes[node]['primaryBackendIpAddress']
|
ret[node]['private_ips'] = nodes[node]['primaryBackendIpAddress']
|
||||||
|
if 'status' in nodes[node]:
|
||||||
|
ret[node]['state'] = str(nodes[node]['status']['name'])
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ def _verify_auth(repo):
|
|||||||
'''
|
'''
|
||||||
Helper function to log errors about missing auth parameters
|
Helper function to log errors about missing auth parameters
|
||||||
'''
|
'''
|
||||||
log.error(
|
log.critical(
|
||||||
'Incomplete authentication information for remote {0}. Missing '
|
'Incomplete authentication information for remote {0}. Missing '
|
||||||
'parameters: {1}'.format(remote_url, ', '.join(missing))
|
'parameters: {1}'.format(remote_url, ', '.join(missing))
|
||||||
)
|
)
|
||||||
@ -600,9 +600,9 @@ def _verify_auth(repo):
|
|||||||
user = address.split('@')[0]
|
user = address.split('@')[0]
|
||||||
if user == address:
|
if user == address:
|
||||||
# No '@' sign == no user. This is a problem.
|
# No '@' sign == no user. This is a problem.
|
||||||
log.error(
|
log.critical(
|
||||||
'Password / keypair specified for remote {0}, but remote '
|
'Keypair specified for remote {0}, but remote URL is missing '
|
||||||
'URL is missing a username'.format(repo['url'])
|
'a username'.format(repo['url'])
|
||||||
)
|
)
|
||||||
_failhard()
|
_failhard()
|
||||||
|
|
||||||
@ -625,7 +625,7 @@ def _verify_auth(repo):
|
|||||||
return True
|
return True
|
||||||
if password_ok:
|
if password_ok:
|
||||||
if transport == 'http' and not repo['insecure_auth']:
|
if transport == 'http' and not repo['insecure_auth']:
|
||||||
log.error(
|
log.critical(
|
||||||
'Invalid configuration for gitfs remote {0}. '
|
'Invalid configuration for gitfs remote {0}. '
|
||||||
'Authentication is disabled by default on http remotes. '
|
'Authentication is disabled by default on http remotes. '
|
||||||
'Either set gitfs_insecure_auth to True in the master '
|
'Either set gitfs_insecure_auth to True in the master '
|
||||||
@ -641,7 +641,7 @@ def _verify_auth(repo):
|
|||||||
missing_auth = [x for x in required_params if not bool(repo[x])]
|
missing_auth = [x for x in required_params if not bool(repo[x])]
|
||||||
_incomplete_auth(repo['url'], missing_auth)
|
_incomplete_auth(repo['url'], missing_auth)
|
||||||
else:
|
else:
|
||||||
log.error(
|
log.critical(
|
||||||
'Invalid configuration for remote {0}. Unsupported transport '
|
'Invalid configuration for remote {0}. Unsupported transport '
|
||||||
'{1!r}.'.format(repo['url'], transport)
|
'{1!r}.'.format(repo['url'], transport)
|
||||||
)
|
)
|
||||||
@ -705,7 +705,7 @@ def init():
|
|||||||
six.iteritems(salt.utils.repack_dictlist(remote[repo_url]))]
|
six.iteritems(salt.utils.repack_dictlist(remote[repo_url]))]
|
||||||
)
|
)
|
||||||
if not per_remote_conf:
|
if not per_remote_conf:
|
||||||
log.error(
|
log.critical(
|
||||||
'Invalid per-remote configuration for gitfs remote {0}. '
|
'Invalid per-remote configuration for gitfs remote {0}. '
|
||||||
'If no per-remote parameters are being specified, there '
|
'If no per-remote parameters are being specified, there '
|
||||||
'may be a trailing colon after the URL, which should be '
|
'may be a trailing colon after the URL, which should be '
|
||||||
@ -816,7 +816,7 @@ def init():
|
|||||||
'{0}'.format(exc))
|
'{0}'.format(exc))
|
||||||
if provider == 'gitpython':
|
if provider == 'gitpython':
|
||||||
msg += ' Perhaps git is not available.'
|
msg += ' Perhaps git is not available.'
|
||||||
log.error(msg, exc_info_on_loglevel=logging.DEBUG)
|
log.critical(msg, exc_info_on_loglevel=logging.DEBUG)
|
||||||
_failhard()
|
_failhard()
|
||||||
|
|
||||||
if new_remote:
|
if new_remote:
|
||||||
@ -1152,7 +1152,21 @@ def update():
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
# No credentials configured for this repo
|
# No credentials configured for this repo
|
||||||
pass
|
pass
|
||||||
fetch = origin.fetch()
|
try:
|
||||||
|
fetch = origin.fetch()
|
||||||
|
except pygit2.errors.GitError as exc:
|
||||||
|
# Using exc.__str__() here to avoid deprecation warning
|
||||||
|
# when referencing exc.message
|
||||||
|
if 'unsupported url protocol' in exc.__str__().lower() \
|
||||||
|
and isinstance(repo.get('credentials'),
|
||||||
|
pygit2.Keypair):
|
||||||
|
log.error(
|
||||||
|
'Unable to fetch SSH-based gitfs remote {0}. '
|
||||||
|
'libgit2 must be compiled with libssh2 to support '
|
||||||
|
'SSH authentication.'.format(repo['url'])
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
raise
|
||||||
try:
|
try:
|
||||||
# pygit2.Remote.fetch() returns a dict in pygit2 < 0.21.0
|
# pygit2.Remote.fetch() returns a dict in pygit2 < 0.21.0
|
||||||
received_objects = fetch['received_objects']
|
received_objects = fetch['received_objects']
|
||||||
@ -1160,10 +1174,16 @@ def update():
|
|||||||
# pygit2.Remote.fetch() returns a class instance in
|
# pygit2.Remote.fetch() returns a class instance in
|
||||||
# pygit2 >= 0.21.0
|
# pygit2 >= 0.21.0
|
||||||
received_objects = fetch.received_objects
|
received_objects = fetch.received_objects
|
||||||
log.debug(
|
if received_objects != 0:
|
||||||
'gitfs received {0} objects for remote {1}'
|
log.debug(
|
||||||
.format(received_objects, repo['url'])
|
'gitfs received {0} objects for remote {1}'
|
||||||
)
|
.format(received_objects, repo['url'])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
log.debug(
|
||||||
|
'gitfs remote {0} is up-to-date'
|
||||||
|
.format(repo['url'])
|
||||||
|
)
|
||||||
# Clean up any stale refs
|
# Clean up any stale refs
|
||||||
refs_post = repo['repo'].listall_references()
|
refs_post = repo['repo'].listall_references()
|
||||||
cleaned = _clean_stale(repo['repo'], refs_post)
|
cleaned = _clean_stale(repo['repo'], refs_post)
|
||||||
@ -1180,14 +1200,14 @@ def update():
|
|||||||
try:
|
try:
|
||||||
refs_post = client.fetch(path, repo['repo'])
|
refs_post = client.fetch(path, repo['repo'])
|
||||||
except dulwich.errors.NotGitRepository:
|
except dulwich.errors.NotGitRepository:
|
||||||
log.critical(
|
log.error(
|
||||||
'Dulwich does not recognize remote {0} as a valid '
|
'Dulwich does not recognize remote {0} as a valid '
|
||||||
'remote URL. Perhaps it is missing \'.git\' at the '
|
'remote URL. Perhaps it is missing \'.git\' at the '
|
||||||
'end.'.format(repo['url'])
|
'end.'.format(repo['url'])
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log.critical(
|
log.error(
|
||||||
'Local repository cachedir {0!r} (corresponding '
|
'Local repository cachedir {0!r} (corresponding '
|
||||||
'remote: {1}) has been corrupted. Salt will now '
|
'remote: {1}) has been corrupted. Salt will now '
|
||||||
'attempt to remove the local checkout to allow it to '
|
'attempt to remove the local checkout to allow it to '
|
||||||
@ -1198,7 +1218,7 @@ def update():
|
|||||||
try:
|
try:
|
||||||
salt.utils.rm_rf(repo['cachedir'])
|
salt.utils.rm_rf(repo['cachedir'])
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
log.critical(
|
log.error(
|
||||||
'Unable to remove {0!r}: {1}'
|
'Unable to remove {0!r}: {1}'
|
||||||
.format(repo['cachedir'], exc)
|
.format(repo['cachedir'], exc)
|
||||||
)
|
)
|
||||||
@ -1626,7 +1646,7 @@ def _file_lists(load, form):
|
|||||||
try:
|
try:
|
||||||
os.makedirs(list_cachedir)
|
os.makedirs(list_cachedir)
|
||||||
except os.error:
|
except os.error:
|
||||||
log.critical('Unable to make cachedir {0}'.format(list_cachedir))
|
log.error('Unable to make cachedir {0}'.format(list_cachedir))
|
||||||
return []
|
return []
|
||||||
list_cache = os.path.join(
|
list_cache = os.path.join(
|
||||||
list_cachedir,
|
list_cachedir,
|
||||||
|
@ -203,7 +203,7 @@ def cql_query(query, contact_points=None, port=None, cql_user=None, cql_pass=Non
|
|||||||
if results:
|
if results:
|
||||||
for result in results:
|
for result in results:
|
||||||
values = {}
|
values = {}
|
||||||
for key, value in result.iteritems():
|
for key, value in six.iteritems(result):
|
||||||
# Salt won't return dictionaries with odd types like uuid.UUID
|
# Salt won't return dictionaries with odd types like uuid.UUID
|
||||||
if not isinstance(value, six.text_type):
|
if not isinstance(value, six.text_type):
|
||||||
value = str(value)
|
value = str(value)
|
||||||
|
@ -48,7 +48,7 @@ def load():
|
|||||||
datastore_path = os.path.join(__opts__['cachedir'], 'datastore')
|
datastore_path = os.path.join(__opts__['cachedir'], 'datastore')
|
||||||
fn_ = salt.utils.fopen(datastore_path, 'rb')
|
fn_ = salt.utils.fopen(datastore_path, 'rb')
|
||||||
return serial.load(fn_)
|
return serial.load(fn_)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError, NameError):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ def dump(new_data):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except (IOError, OSError):
|
except (IOError, OSError, NameError):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -1696,7 +1696,7 @@ def replace(path,
|
|||||||
raise CommandExecutionError("Exception: {0}".format(exc))
|
raise CommandExecutionError("Exception: {0}".format(exc))
|
||||||
|
|
||||||
if not found and (append_if_not_found or prepend_if_not_found):
|
if not found and (append_if_not_found or prepend_if_not_found):
|
||||||
if None == not_found_content:
|
if not_found_content is None:
|
||||||
not_found_content = repl
|
not_found_content = repl
|
||||||
if prepend_if_not_found:
|
if prepend_if_not_found:
|
||||||
new_file.insert(0, not_found_content + '\n')
|
new_file.insert(0, not_found_content + '\n')
|
||||||
|
@ -587,7 +587,11 @@ def find_cached_job(jid):
|
|||||||
buf = fp_.read()
|
buf = fp_.read()
|
||||||
fp_.close()
|
fp_.close()
|
||||||
if buf:
|
if buf:
|
||||||
data = serial.loads(buf)
|
try:
|
||||||
|
data = serial.loads(buf)
|
||||||
|
except NameError:
|
||||||
|
# msgpack error in salt-ssh
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if not isinstance(data, dict):
|
if not isinstance(data, dict):
|
||||||
|
@ -736,7 +736,7 @@ def bootstrap(directory='.',
|
|||||||
with salt.utils.fopen(b_py) as fic:
|
with salt.utils.fopen(b_py) as fic:
|
||||||
content = fic.read()
|
content = fic.read()
|
||||||
if (
|
if (
|
||||||
(False != test_release)
|
(test_release is not False)
|
||||||
and ' --accept-buildout-test-releases' in content
|
and ' --accept-buildout-test-releases' in content
|
||||||
):
|
):
|
||||||
bootstrap_args += ' --accept-buildout-test-releases'
|
bootstrap_args += ' --accept-buildout-test-releases'
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import absolute_import, print_function
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import distutils.version
|
import distutils.version # pylint: disable=no-name-in-module
|
||||||
|
|
||||||
__virtualname__ = 'rest_tornado'
|
__virtualname__ = 'rest_tornado'
|
||||||
|
|
||||||
|
@ -26,12 +26,12 @@ returns a list of key/value pairs for all of the EC2 tags assigned to
|
|||||||
the instance.
|
the instance.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
# Import python libs
|
# Import python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion # pylint: disable=no-name-in-module
|
||||||
|
|
||||||
# Import AWS Boto libs
|
# Import AWS Boto libs
|
||||||
try:
|
try:
|
||||||
|
@ -457,7 +457,7 @@ def ext_pillar(minion_id, pillar, resource, sequence, subkey=False, subkey_only=
|
|||||||
immutable[rkey] = True
|
immutable[rkey] = True
|
||||||
if rkey not in output:
|
if rkey not in output:
|
||||||
log.error('Cant\'t merge key {0} doesn\'t exist'.format(rkey))
|
log.error('Cant\'t merge key {0} doesn\'t exist'.format(rkey))
|
||||||
elif type(results[key]) is not type(output[rkey]):
|
elif not isinstance(results[key], type(output[rkey])):
|
||||||
log.error('Can\'t merge different types for key {0}'.format(rkey))
|
log.error('Can\'t merge different types for key {0}'.format(rkey))
|
||||||
elif isinstance(results[key], dict):
|
elif isinstance(results[key], dict):
|
||||||
output[rkey].update(results[key])
|
output[rkey].update(results[key])
|
||||||
|
@ -81,9 +81,9 @@ def downloaded(name, artifact, target_dir='/tmp', target_file=None):
|
|||||||
log.debug("ret=%s", str(ret))
|
log.debug("ret=%s", str(ret))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
ret['result'] = False
|
ret['result'] = False
|
||||||
ret['comment'] = e
|
ret['comment'] = exc
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -276,7 +276,8 @@ def _load_accumulators():
|
|||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
loaded = serial.load(f)
|
loaded = serial.load(f)
|
||||||
return loaded if loaded else ret
|
return loaded if loaded else ret
|
||||||
except IOError:
|
except (IOError, NameError):
|
||||||
|
# NameError is a msgpack error from salt-ssh
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
loaded = _deserialize(_get_accumulator_filepath())
|
loaded = _deserialize(_get_accumulator_filepath())
|
||||||
@ -290,8 +291,12 @@ def _persist_accummulators(accumulators, accumulators_deps):
|
|||||||
'accumulators_deps': accumulators_deps}
|
'accumulators_deps': accumulators_deps}
|
||||||
|
|
||||||
serial = salt.payload.Serial(__opts__)
|
serial = salt.payload.Serial(__opts__)
|
||||||
with open(_get_accumulator_filepath(), 'w+b') as f:
|
try:
|
||||||
serial.dump(accumm_data, f)
|
with open(_get_accumulator_filepath(), 'w+b') as f:
|
||||||
|
serial.dump(accumm_data, f)
|
||||||
|
except NameError:
|
||||||
|
# msgpack error from salt-ssh
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _check_user(user, group):
|
def _check_user(user, group):
|
||||||
|
@ -146,7 +146,6 @@ def sig4(method, endpoint, params, prov_dict, aws_api_version, location,
|
|||||||
http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||||
'''
|
'''
|
||||||
timenow = datetime.datetime.utcnow()
|
timenow = datetime.datetime.utcnow()
|
||||||
timestamp = timenow.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
|
|
||||||
# Retrieve access credentials from meta-data, or use provided
|
# Retrieve access credentials from meta-data, or use provided
|
||||||
access_key_id, secret_access_key, token = creds(prov_dict)
|
access_key_id, secret_access_key, token = creds(prov_dict)
|
||||||
@ -155,11 +154,10 @@ def sig4(method, endpoint, params, prov_dict, aws_api_version, location,
|
|||||||
params_with_headers['Version'] = aws_api_version
|
params_with_headers['Version'] = aws_api_version
|
||||||
keys = sorted(params_with_headers.keys())
|
keys = sorted(params_with_headers.keys())
|
||||||
values = list(map(params_with_headers.get, keys))
|
values = list(map(params_with_headers.get, keys))
|
||||||
querystring = urlencode(list(zip(keys, values)))
|
querystring = urlencode(list(zip(keys, values))).replace('+', '%20')
|
||||||
|
|
||||||
amzdate = timenow.strftime('%Y%m%dT%H%M%SZ')
|
amzdate = timenow.strftime('%Y%m%dT%H%M%SZ')
|
||||||
datestamp = timenow.strftime('%Y%m%d')
|
datestamp = timenow.strftime('%Y%m%d')
|
||||||
payload_hash = hashlib.sha256('').hexdigest()
|
|
||||||
|
|
||||||
canonical_headers = 'host:{0}\nx-amz-date:{1}\n'.format(
|
canonical_headers = 'host:{0}\nx-amz-date:{1}\n'.format(
|
||||||
endpoint,
|
endpoint,
|
||||||
@ -167,11 +165,6 @@ def sig4(method, endpoint, params, prov_dict, aws_api_version, location,
|
|||||||
)
|
)
|
||||||
signed_headers = 'host;x-amz-date'
|
signed_headers = 'host;x-amz-date'
|
||||||
|
|
||||||
request = '\n'.join((
|
|
||||||
method, endpoint, querystring, canonical_headers,
|
|
||||||
signed_headers, payload_hash
|
|
||||||
))
|
|
||||||
|
|
||||||
algorithm = 'AWS4-HMAC-SHA256'
|
algorithm = 'AWS4-HMAC-SHA256'
|
||||||
|
|
||||||
# Create payload hash (hash of the request body content). For GET
|
# Create payload hash (hash of the request body content). For GET
|
||||||
|
@ -22,7 +22,7 @@ class DecoratorTest(integration.ModuleCase):
|
|||||||
def not_test_depends(self):
|
def not_test_depends(self):
|
||||||
ret = self.run_function('runtests_decorators.depends')
|
ret = self.run_function('runtests_decorators.depends')
|
||||||
self.assertTrue(ret['ret'])
|
self.assertTrue(ret['ret'])
|
||||||
self.assertTrue(type(ret['time']) == float)
|
self.assertTrue(isinstance(ret['time'], float))
|
||||||
|
|
||||||
def test_missing_depends(self):
|
def test_missing_depends(self):
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
@ -49,7 +49,7 @@ class DecoratorTest(integration.ModuleCase):
|
|||||||
def not_test_depends_will_fallback(self):
|
def not_test_depends_will_fallback(self):
|
||||||
ret = self.run_function('runtests_decorators.depends_will_fallback')
|
ret = self.run_function('runtests_decorators.depends_will_fallback')
|
||||||
self.assertTrue(ret['ret'])
|
self.assertTrue(ret['ret'])
|
||||||
self.assertTrue(type(ret['time']) == float)
|
self.assertTrue(isinstance(ret['time'], float))
|
||||||
|
|
||||||
def test_missing_depends_again(self):
|
def test_missing_depends_again(self):
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
|
142
tests/unit/modules/postfix_test.py
Normal file
142
tests/unit/modules/postfix_test.py
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.modules import postfix
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
postfix.__salt__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class PostfixTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.modules.postfix
|
||||||
|
'''
|
||||||
|
def test_show_master(self):
|
||||||
|
'''
|
||||||
|
Test for return a dict of active config values
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, '_parse_master',
|
||||||
|
return_value=({'A': 'a'}, ['b'])):
|
||||||
|
self.assertDictEqual(postfix.show_master('path'), {'A': 'a'})
|
||||||
|
|
||||||
|
def test_set_master(self):
|
||||||
|
'''
|
||||||
|
Test for set a single config value in the master.cf file
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, '_parse_master',
|
||||||
|
return_value=({'A': 'a'}, ['b'])):
|
||||||
|
with patch.object(postfix, '_write_conf', return_value=None):
|
||||||
|
self.assertTrue(postfix.set_master('a', 'b'))
|
||||||
|
|
||||||
|
def test_show_main(self):
|
||||||
|
'''
|
||||||
|
Test for return a dict of active config values
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, '_parse_main',
|
||||||
|
return_value=({'A': 'a'}, ['b'])):
|
||||||
|
self.assertDictEqual(postfix.show_main('path'), {'A': 'a'})
|
||||||
|
|
||||||
|
def test_set_main(self):
|
||||||
|
'''
|
||||||
|
Test for set a single config value in the master.cf file
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, '_parse_main',
|
||||||
|
return_value=({'A': 'a'}, ['b'])):
|
||||||
|
with patch.object(postfix, '_write_conf', return_value=None):
|
||||||
|
self.assertTrue(postfix.set_main('key', 'value'))
|
||||||
|
|
||||||
|
def test_show_queue(self):
|
||||||
|
'''
|
||||||
|
Test for show contents of the mail queue
|
||||||
|
'''
|
||||||
|
with patch.dict(postfix.__salt__, {'cmd.run':
|
||||||
|
MagicMock(return_value='A\nB')}):
|
||||||
|
self.assertEqual(postfix.show_queue(), [])
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
'''
|
||||||
|
Test for delete message(s) from the mail queue
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, 'show_queue', return_value={}):
|
||||||
|
self.assertDictEqual(postfix.delete('queue_id'),
|
||||||
|
{'result': False, 'message':
|
||||||
|
'No message in queue with ID queue_id'})
|
||||||
|
|
||||||
|
with patch.dict(postfix.__salt__,
|
||||||
|
{'cmd.run_all':
|
||||||
|
MagicMock(return_value={'retcode': 0})}):
|
||||||
|
self.assertDictEqual(postfix.delete('ALL'),
|
||||||
|
{'result': True, 'message':
|
||||||
|
'Successfully removed all messages'})
|
||||||
|
|
||||||
|
def test_hold(self):
|
||||||
|
'''
|
||||||
|
Test for set held message(s) in the mail queue to unheld
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, 'show_queue', return_value={}):
|
||||||
|
self.assertDictEqual(postfix.hold('queue_id'),
|
||||||
|
{'result': False, 'message':
|
||||||
|
'No message in queue with ID queue_id'})
|
||||||
|
|
||||||
|
with patch.dict(postfix.__salt__,
|
||||||
|
{'cmd.run_all':
|
||||||
|
MagicMock(return_value={'retcode': 0})}):
|
||||||
|
self.assertDictEqual(postfix.hold('ALL'),
|
||||||
|
{'result': True, 'message':
|
||||||
|
'Successfully placed all messages on hold'})
|
||||||
|
|
||||||
|
def test_unhold(self):
|
||||||
|
'''
|
||||||
|
Test for put message(s) on hold from the mail queue
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, 'show_queue', return_value={}):
|
||||||
|
self.assertDictEqual(postfix.unhold('queue_id'),
|
||||||
|
{'result': False, 'message':
|
||||||
|
'No message in queue with ID queue_id'})
|
||||||
|
|
||||||
|
with patch.dict(postfix.__salt__,
|
||||||
|
{'cmd.run_all':
|
||||||
|
MagicMock(return_value={'retcode': 0})}):
|
||||||
|
self.assertDictEqual(postfix.unhold('ALL'),
|
||||||
|
{'result': True, 'message':
|
||||||
|
'Successfully set all message as unheld'})
|
||||||
|
|
||||||
|
def test_requeue(self):
|
||||||
|
'''
|
||||||
|
Test for requeue message(s) in the mail queue
|
||||||
|
'''
|
||||||
|
with patch.object(postfix, 'show_queue', return_value={}):
|
||||||
|
self.assertDictEqual(postfix.requeue('queue_id'),
|
||||||
|
{'result': False, 'message':
|
||||||
|
'No message in queue with ID queue_id'})
|
||||||
|
|
||||||
|
with patch.dict(postfix.__salt__,
|
||||||
|
{'cmd.run_all':
|
||||||
|
MagicMock(return_value={'retcode': 0})}):
|
||||||
|
self.assertDictEqual(postfix.requeue('ALL'),
|
||||||
|
{'result': True, 'message':
|
||||||
|
'Successfully requeued all messages'})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(PostfixTestCase, needs_daemon=False)
|
@ -154,11 +154,11 @@ class BuildoutTestCase(Base):
|
|||||||
# These lines are throwing pylint errors - disabling for now since we are skipping
|
# These lines are throwing pylint errors - disabling for now since we are skipping
|
||||||
# these tests
|
# these tests
|
||||||
#self.assertTrue(
|
#self.assertTrue(
|
||||||
# u''
|
# u''
|
||||||
# u'OUTPUT:\n'
|
# u'OUTPUT:\n'
|
||||||
# u'foo\n'
|
# u'foo\n'
|
||||||
# u''
|
# u''
|
||||||
#in ret1['outlog']
|
# in ret1['outlog']
|
||||||
#)
|
#)
|
||||||
|
|
||||||
# These lines are throwing pylint errors - disabling for now since we are skipping
|
# These lines are throwing pylint errors - disabling for now since we are skipping
|
||||||
@ -167,11 +167,11 @@ class BuildoutTestCase(Base):
|
|||||||
# These lines are throwing pylint errors - disabling for now since we are skipping
|
# These lines are throwing pylint errors - disabling for now since we are skipping
|
||||||
# these tests
|
# these tests
|
||||||
# self.assertTrue(
|
# self.assertTrue(
|
||||||
# u'INFO: ibar\n'
|
# u'INFO: ibar\n'
|
||||||
# u'WARN: wbar\n'
|
# u'WARN: wbar\n'
|
||||||
# u'DEBUG: dbar\n'
|
# u'DEBUG: dbar\n'
|
||||||
# u'ERROR: ebar\n'
|
# u'ERROR: ebar\n'
|
||||||
#in ret1['outlog']
|
# in ret1['outlog']
|
||||||
#)
|
#)
|
||||||
# These lines are throwing pylint errors - disabling for now since we are skipping
|
# These lines are throwing pylint errors - disabling for now since we are skipping
|
||||||
# these tests
|
# these tests
|
||||||
|
72
tests/unit/states/apache_test.py
Normal file
72
tests/unit/states/apache_test.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch,
|
||||||
|
mock_open)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import apache
|
||||||
|
import salt.utils
|
||||||
|
|
||||||
|
apache.__opts__ = {}
|
||||||
|
apache.__salt__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class ApacheTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.apache
|
||||||
|
'''
|
||||||
|
# 'configfile' function tests: 1
|
||||||
|
|
||||||
|
@patch('os.path.exists', MagicMock(return_value=True))
|
||||||
|
def test_configfile(self):
|
||||||
|
'''
|
||||||
|
Test to allows for inputting a yaml dictionary into a file
|
||||||
|
for apache configuration files.
|
||||||
|
'''
|
||||||
|
name = 'yaml'
|
||||||
|
config = 'VirtualHost: this: "*:80"'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': True,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
mock = MagicMock(side_effect=[config, '', ''])
|
||||||
|
with patch.object(salt.utils, 'fopen', mock_open(read_data=config)):
|
||||||
|
with patch.dict(apache.__salt__,
|
||||||
|
{'apache.config': mock}):
|
||||||
|
ret.update({'comment': 'Configuration is up to date.'})
|
||||||
|
self.assertDictEqual(apache.configfile(name, config), ret)
|
||||||
|
|
||||||
|
ret.update({'comment': 'Configuration will update.',
|
||||||
|
'changes': {'new': '',
|
||||||
|
'old': 'VirtualHost: this: "*:80"'},
|
||||||
|
'result': None})
|
||||||
|
with patch.dict(apache.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(apache.configfile(name, config), ret)
|
||||||
|
|
||||||
|
ret.update({'comment': 'Successfully created configuration.',
|
||||||
|
'result': True})
|
||||||
|
with patch.dict(apache.__opts__, {'test': False}):
|
||||||
|
self.assertDictEqual(apache.configfile(name, config), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(ApacheTestCase, needs_daemon=False)
|
52
tests/unit/states/apt_test.py
Normal file
52
tests/unit/states/apt_test.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import apt
|
||||||
|
|
||||||
|
apt.__opts__ = {}
|
||||||
|
apt.__salt__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class AptTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.apt
|
||||||
|
'''
|
||||||
|
# 'held' function tests: 1
|
||||||
|
|
||||||
|
def test_held(self):
|
||||||
|
'''
|
||||||
|
Test to set package in 'hold' state, meaning it will not be upgraded.
|
||||||
|
'''
|
||||||
|
name = 'tmux'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': False,
|
||||||
|
'changes': {},
|
||||||
|
'comment': 'Package {0} does not have a state'.format(name)}
|
||||||
|
|
||||||
|
mock = MagicMock(return_value=False)
|
||||||
|
with patch.dict(apt.__salt__, {'pkg.get_selections': mock}):
|
||||||
|
self.assertDictEqual(apt.held(name), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(AptTestCase, needs_daemon=False)
|
64
tests/unit/states/artifactory_test.py
Normal file
64
tests/unit/states/artifactory_test.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import artifactory
|
||||||
|
|
||||||
|
artifactory.__salt__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class ArtifactoryTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.artifactory
|
||||||
|
'''
|
||||||
|
# 'downloaded' function tests: 1
|
||||||
|
|
||||||
|
def test_downloaded(self):
|
||||||
|
'''
|
||||||
|
Test to ensures that the artifact from artifactory exists at
|
||||||
|
given location.
|
||||||
|
'''
|
||||||
|
name = 'jboss'
|
||||||
|
arti_url = 'http://artifactory.intranet.company.com/artifactory'
|
||||||
|
artifact = {'artifactory_url': arti_url, 'artifact_id': 'module',
|
||||||
|
'repository': 'libs-release-local', 'packaging': 'jar',
|
||||||
|
'group_id': 'com.company.module', 'classifier': 'sources',
|
||||||
|
'version': '1.0'}
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': False,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
mck = MagicMock(return_value={'status': False, 'changes': {},
|
||||||
|
'comment': ''})
|
||||||
|
with patch.dict(artifactory.__salt__, {'artifactory.get_release': mck}):
|
||||||
|
self.assertDictEqual(artifactory.downloaded(name, artifact), ret)
|
||||||
|
|
||||||
|
with patch.object(artifactory, '__fetch_from_artifactory',
|
||||||
|
MagicMock(side_effect=Exception('error'))):
|
||||||
|
ret = artifactory.downloaded(name, artifact)
|
||||||
|
self.assertEqual(ret['result'], False)
|
||||||
|
self.assertEqual(repr(ret['comment']), repr(Exception('error')))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(ArtifactoryTestCase, needs_daemon=False)
|
109
tests/unit/states/at_test.py
Normal file
109
tests/unit/states/at_test.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import at
|
||||||
|
|
||||||
|
at.__salt__ = {}
|
||||||
|
at.__opts__ = {}
|
||||||
|
at.__grains__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class AtTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.at
|
||||||
|
'''
|
||||||
|
# 'present' function tests: 1
|
||||||
|
|
||||||
|
def test_present(self):
|
||||||
|
'''
|
||||||
|
Test to add a job to queue.
|
||||||
|
'''
|
||||||
|
name = 'jboss'
|
||||||
|
timespec = '9:09 11/04/15'
|
||||||
|
tag = 'love'
|
||||||
|
user = 'jam'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': True,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
mock = MagicMock(return_value=False)
|
||||||
|
with patch.dict(at.__opts__, {'test': False}):
|
||||||
|
with patch.dict(at.__grains__, {'os_family': 'Redhat'}):
|
||||||
|
with patch.dict(at.__salt__, {'cmd.run': mock}):
|
||||||
|
ret.update({'comment': False})
|
||||||
|
self.assertDictEqual(at.present(name, timespec, tag),
|
||||||
|
ret)
|
||||||
|
|
||||||
|
with patch.dict(at.__salt__, {'user.info': mock}):
|
||||||
|
comt = 'User: {0} is not exists'.format(user)
|
||||||
|
ret.update({'comment': comt, 'result': False})
|
||||||
|
self.assertDictEqual(at.present(name, timespec, tag, user),
|
||||||
|
ret)
|
||||||
|
|
||||||
|
with patch.dict(at.__opts__, {'test': True}):
|
||||||
|
comt = 'job {0} is add and will run on {1}'.format(name, timespec)
|
||||||
|
ret.update({'comment': comt, 'result': None})
|
||||||
|
self.assertDictEqual(at.present(name, timespec, tag, user), ret)
|
||||||
|
|
||||||
|
# 'absent' function tests: 1
|
||||||
|
|
||||||
|
def test_absent(self):
|
||||||
|
'''
|
||||||
|
Test to remove a job from queue
|
||||||
|
'''
|
||||||
|
name = 'jboss'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': None,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
with patch.dict(at.__opts__, {'test': True}):
|
||||||
|
ret.update({'comment': 'Remove jobs()'})
|
||||||
|
self.assertDictEqual(at.absent(name), ret)
|
||||||
|
|
||||||
|
with patch.dict(at.__opts__, {'test': False}):
|
||||||
|
comt = 'limit parameter not supported {0}'.format(name)
|
||||||
|
ret.update({'comment': comt, 'result': False})
|
||||||
|
self.assertDictEqual(at.absent(name), ret)
|
||||||
|
|
||||||
|
mock = MagicMock(return_value={'jobs': []})
|
||||||
|
mock_bool = MagicMock(return_value=False)
|
||||||
|
with patch.dict(at.__salt__, {'at.atq': mock,
|
||||||
|
'cmd.run': mock_bool}):
|
||||||
|
comt = 'No match jobs or time format error'
|
||||||
|
ret.update({'comment': comt, 'result': False, 'name': 'all'})
|
||||||
|
self.assertDictEqual(at.absent('all'), ret)
|
||||||
|
|
||||||
|
mock = MagicMock(return_value={'jobs': [{'job': 'rose'}]})
|
||||||
|
mock_bool = MagicMock(return_value=False)
|
||||||
|
with patch.dict(at.__salt__, {'at.atq': mock,
|
||||||
|
'cmd.run': mock_bool}):
|
||||||
|
comt = "Remove job(rose) from queue but (['rose']) fail"
|
||||||
|
ret.update({'comment': comt, 'result': True})
|
||||||
|
self.assertDictEqual(at.absent('all'), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(AtTestCase, needs_daemon=False)
|
78
tests/unit/states/augeas_test.py
Normal file
78
tests/unit/states/augeas_test.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch
|
||||||
|
)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import augeas
|
||||||
|
|
||||||
|
augeas.__opts__ = {}
|
||||||
|
augeas.__salt__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class AugeasTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.augeas
|
||||||
|
'''
|
||||||
|
# 'change' function tests: 1
|
||||||
|
|
||||||
|
def test_change(self):
|
||||||
|
'''
|
||||||
|
Test to issue changes to Augeas, optionally for a specific context,
|
||||||
|
with a specific lens.
|
||||||
|
'''
|
||||||
|
name = 'zabbix'
|
||||||
|
context = '/files/etc/services'
|
||||||
|
changes = ['ins service-name after service-name[last()]',
|
||||||
|
'set service-name[last()] zabbix-agent']
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': False,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
comt = ('\'changes\' must be specified as a list')
|
||||||
|
ret.update({'comment': comt})
|
||||||
|
self.assertDictEqual(augeas.change(name), ret)
|
||||||
|
|
||||||
|
comt = ('Executing commands in file "/files/etc/services":\n'
|
||||||
|
'ins service-name after service-name[last()]'
|
||||||
|
'\nset service-name[last()] zabbix-agent')
|
||||||
|
ret.update({'comment': comt, 'result': None})
|
||||||
|
with patch.dict(augeas.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(augeas.change(name, context, changes), ret)
|
||||||
|
|
||||||
|
with patch.dict(augeas.__opts__, {'test': False}):
|
||||||
|
mock = MagicMock(return_value={'retval': False, 'error': 'error'})
|
||||||
|
with patch.dict(augeas.__salt__, {'augeas.execute': mock}):
|
||||||
|
ret.update({'comment': 'Error: error', 'result': False})
|
||||||
|
self.assertDictEqual(augeas.change(name, changes=changes), ret)
|
||||||
|
|
||||||
|
chang = ['ins service-name after service-name[last()]',
|
||||||
|
'set service-name[last()] zabbix-agent']
|
||||||
|
mock = MagicMock(return_value={'retval': True})
|
||||||
|
with patch.dict(augeas.__salt__, {'augeas.execute': mock}):
|
||||||
|
ret.update({'comment': 'Changes have been saved',
|
||||||
|
'result': True, 'changes': chang})
|
||||||
|
self.assertDictEqual(augeas.change(name, changes=changes), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(AugeasTestCase, needs_daemon=False)
|
85
tests/unit/states/aws_sqs_test.py
Normal file
85
tests/unit/states/aws_sqs_test.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import aws_sqs
|
||||||
|
|
||||||
|
aws_sqs.__salt__ = {}
|
||||||
|
aws_sqs.__opts__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class AwsSqsTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.aws_sqs
|
||||||
|
'''
|
||||||
|
# 'exists' function tests: 1
|
||||||
|
|
||||||
|
def test_exists(self):
|
||||||
|
'''
|
||||||
|
Test to ensure the SQS queue exists.
|
||||||
|
'''
|
||||||
|
name = 'myqueue'
|
||||||
|
region = 'eu-west-1'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': None,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
mock = MagicMock(side_effect=[False, True])
|
||||||
|
with patch.dict(aws_sqs.__salt__, {'aws_sqs.queue_exists': mock}):
|
||||||
|
comt = 'AWS SQS queue {0} is set to be created'.format(name)
|
||||||
|
ret.update({'comment': comt})
|
||||||
|
with patch.dict(aws_sqs.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(aws_sqs.exists(name, region), ret)
|
||||||
|
|
||||||
|
comt = u'{0} exists in {1}'.format(name, region)
|
||||||
|
ret.update({'comment': comt, 'result': True})
|
||||||
|
self.assertDictEqual(aws_sqs.exists(name, region), ret)
|
||||||
|
|
||||||
|
# 'absent' function tests: 1
|
||||||
|
|
||||||
|
def test_absent(self):
|
||||||
|
'''
|
||||||
|
Test to remove the named SQS queue if it exists.
|
||||||
|
'''
|
||||||
|
name = 'myqueue'
|
||||||
|
region = 'eu-west-1'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': None,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
mock = MagicMock(side_effect=[True, False])
|
||||||
|
with patch.dict(aws_sqs.__salt__, {'aws_sqs.queue_exists': mock}):
|
||||||
|
comt = 'AWS SQS queue {0} is set to be removed'.format(name)
|
||||||
|
ret.update({'comment': comt})
|
||||||
|
with patch.dict(aws_sqs.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(aws_sqs.absent(name, region), ret)
|
||||||
|
|
||||||
|
comt = u'{0} does not exist in {1}'.format(name, region)
|
||||||
|
ret.update({'comment': comt, 'result': True})
|
||||||
|
self.assertDictEqual(aws_sqs.absent(name, region), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(AwsSqsTestCase, needs_daemon=False)
|
108
tests/unit/states/blockdev_test.py
Normal file
108
tests/unit/states/blockdev_test.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
:codeauthor: :email:`Jayesh Kariya <jayeshk@saltstack.com>`
|
||||||
|
'''
|
||||||
|
# Import Python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Import Salt Testing Libs
|
||||||
|
from salttesting import skipIf, TestCase
|
||||||
|
from salttesting.mock import (
|
||||||
|
NO_MOCK,
|
||||||
|
NO_MOCK_REASON,
|
||||||
|
MagicMock,
|
||||||
|
patch)
|
||||||
|
|
||||||
|
from salttesting.helpers import ensure_in_syspath
|
||||||
|
|
||||||
|
ensure_in_syspath('../../')
|
||||||
|
|
||||||
|
# Import Salt Libs
|
||||||
|
from salt.states import blockdev
|
||||||
|
import salt.utils
|
||||||
|
|
||||||
|
blockdev.__salt__ = {}
|
||||||
|
blockdev.__opts__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
class BlockdevTestCase(TestCase):
|
||||||
|
'''
|
||||||
|
Test cases for salt.states.blockdev
|
||||||
|
'''
|
||||||
|
# 'tuned' function tests: 1
|
||||||
|
|
||||||
|
def test_tuned(self):
|
||||||
|
'''
|
||||||
|
Test to manage options of block device
|
||||||
|
'''
|
||||||
|
name = '/dev/vg/master-data'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': True,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
comt = ('Changes to {0} cannot be applied. '
|
||||||
|
'Not a block device. ').format(name)
|
||||||
|
with patch.dict(blockdev.__salt__, {'file.is_blkdev': False}):
|
||||||
|
ret.update({'comment': comt})
|
||||||
|
self.assertDictEqual(blockdev.tuned(name), ret)
|
||||||
|
|
||||||
|
comt = ('Changes to {0} will be applied '.format(name))
|
||||||
|
with patch.dict(blockdev.__salt__, {'file.is_blkdev': True}):
|
||||||
|
ret.update({'comment': comt, 'result': None})
|
||||||
|
with patch.dict(blockdev.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(blockdev.tuned(name), ret)
|
||||||
|
|
||||||
|
# 'formatted' function tests: 1
|
||||||
|
|
||||||
|
def test_formatted(self):
|
||||||
|
'''
|
||||||
|
Test to manage filesystems of partitions.
|
||||||
|
'''
|
||||||
|
name = '/dev/vg/master-data'
|
||||||
|
|
||||||
|
ret = {'name': name,
|
||||||
|
'result': False,
|
||||||
|
'changes': {},
|
||||||
|
'comment': ''}
|
||||||
|
|
||||||
|
with patch.object(os.path, 'exists', MagicMock(side_effect=[False, True,
|
||||||
|
True, True,
|
||||||
|
True])):
|
||||||
|
comt = ('{0} does not exist'.format(name))
|
||||||
|
ret.update({'comment': comt})
|
||||||
|
self.assertDictEqual(blockdev.formatted(name), ret)
|
||||||
|
|
||||||
|
mock = MagicMock(return_value='ext4')
|
||||||
|
with patch.dict(blockdev.__salt__, {'cmd.run': mock}):
|
||||||
|
comt = ('{0} already formatted with '.format(name))
|
||||||
|
ret.update({'comment': comt, 'result': True})
|
||||||
|
self.assertDictEqual(blockdev.formatted(name, fs_type=''), ret)
|
||||||
|
|
||||||
|
ret.update({'comment': 'Invalid fs_type: ext4',
|
||||||
|
'result': False})
|
||||||
|
with patch.object(salt.utils, 'which',
|
||||||
|
MagicMock(return_value=False)):
|
||||||
|
self.assertDictEqual(blockdev.formatted(name), ret)
|
||||||
|
|
||||||
|
comt = ('Changes to {0} will be applied '.format(name))
|
||||||
|
ret.update({'comment': comt, 'result': None})
|
||||||
|
with patch.object(salt.utils, 'which',
|
||||||
|
MagicMock(return_value=True)):
|
||||||
|
with patch.dict(blockdev.__opts__, {'test': True}):
|
||||||
|
self.assertDictEqual(blockdev.formatted(name), ret)
|
||||||
|
|
||||||
|
comt = ('Failed to format {0}'.format(name))
|
||||||
|
ret.update({'comment': comt, 'result': False})
|
||||||
|
with patch.object(salt.utils, 'which',
|
||||||
|
MagicMock(return_value=True)):
|
||||||
|
with patch.dict(blockdev.__opts__, {'test': False}):
|
||||||
|
self.assertDictEqual(blockdev.formatted(name), ret)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from integration import run_tests
|
||||||
|
run_tests(BlockdevTestCase, needs_daemon=False)
|
Loading…
Reference in New Issue
Block a user