mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +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,
|
||||
W0704,
|
||||
W1202,
|
||||
W1307,
|
||||
F0220,
|
||||
F0401,
|
||||
E8501,
|
||||
@ -116,6 +117,7 @@ disable=R,
|
||||
E8129,
|
||||
E8131,
|
||||
E8265,
|
||||
E8266,
|
||||
E8402,
|
||||
E8731
|
||||
|
||||
@ -151,9 +153,11 @@ disable=R,
|
||||
# F0220 (unresolved-interface)
|
||||
# F0401 (import-error)
|
||||
# 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*
|
||||
# E8265 PEP8 E265 - block comment should start with "# "
|
||||
# E8266 PEP8 E266 - too many leading '#' for block comment
|
||||
# E8501 PEP8 line too long
|
||||
# E8402 module level import not at top of file
|
||||
# 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
|
||||
|
||||
* 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
|
||||
* `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>`__
|
||||
@ -35,9 +39,7 @@ minion exe>` should match the contents of the corresponding md5 file.
|
||||
* 2014.7.0
|
||||
* Salt-Minion-2014.7.0-1-win32-Setup.exe | md5
|
||||
* Salt-Minion-2014.7.0-AMD64-Setup.exe | md5
|
||||
|
||||
.. note::
|
||||
|
||||
The 2014.7.0 installers have been removed because of a regression. Please use the 2014.7.1 release instead.
|
||||
|
||||
* 2014.1.13
|
||||
@ -135,7 +137,7 @@ minion exe>` should match the contents of the corresponding md5 file.
|
||||
|
||||
.. note::
|
||||
|
||||
The executables above will install all dependencies that the Salt minion
|
||||
The executables above will install dependencies that the Salt minion
|
||||
requires.
|
||||
|
||||
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
|
||||
installer:
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: bat
|
||||
|
||||
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
|
||||
======================================
|
||||
|
||||
1. Install the Microsoft Visual C++ 2008 SP1 Redistributable, `vcredist_x86`_
|
||||
or `vcredist_x64`_.
|
||||
This document will explain how to set up a development environment for salt on
|
||||
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
|
||||
wish to target
|
||||
1. Clone the `Salt-Windows-Dev <https://github.com/saltstack/salt-windows-dev/>`_
|
||||
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
|
||||
directory
|
||||
Set-ExecutionPolicy RemoteSigned
|
||||
|
||||
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
|
||||
chosen architecture
|
||||
3. Build the Salt Environment
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
git branch -a
|
||||
git tag -n
|
||||
|
||||
|
||||
Building the installer
|
||||
======================
|
||||
The Hard Way
|
||||
------------
|
||||
|
||||
The Salt Windows installer is built with the open-source NSIS compiler. The
|
||||
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.
|
||||
Prerequisite Software
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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
|
||||
@ -361,7 +526,7 @@ salt, including all dependencies:
|
||||
|
||||
This script is not up to date. Please use the installer found above
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: powershell
|
||||
|
||||
# (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
|
||||
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
|
||||
.. _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
|
||||
.. _Python 2.7: http://www.python.org/downloads
|
||||
.. _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
|
||||
.. _jinja2: http://www.lfd.uci.edu/~gohlke/pythonlibs/#jinja2
|
||||
.. _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
|
||||
pygit2_ website has installation instructions here__. Keep in mind however that
|
||||
following these instructions will install libgit2 and pygit2_ without system
|
||||
packages. Also, while this is not explicitly mentioned in the pygit2_
|
||||
installation instructions, libssh2 development headers must be installed before
|
||||
building libgit2 in order to enable access to SSH-protected git repositories.
|
||||
Luckily, these are available in most distros' repositories, usually as either
|
||||
``libssh2-devel`` or ``libssh2-dev``, depending on platform. On some distros
|
||||
(debian based) ``pkg-config`` is also required to link libgit2 with libssh2.
|
||||
packages. Additionally, keep in mind that :ref:`SSH authentication in pygit2
|
||||
<pygit2-authentication-ssh>` requires libssh2_ (*not* libssh) development
|
||||
libraries to be present before libgit2 is built. On some distros (debian based)
|
||||
``pkg-config`` is also required to link libgit2 with libssh2.
|
||||
|
||||
.. __: http://www.pygit2.org/install.html
|
||||
.. _libssh2: http://www.libssh2.org/
|
||||
|
||||
GitPython
|
||||
---------
|
||||
@ -544,6 +543,8 @@ an ``insecure_auth`` parameter:
|
||||
- password: mypassword
|
||||
- insecure_auth: True
|
||||
|
||||
.. _pygit2-authentication-ssh:
|
||||
|
||||
SSH
|
||||
~~~
|
||||
|
||||
|
@ -41,6 +41,7 @@ Var MinionName_State
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "salt.ico"
|
||||
!define MUI_UNICON "salt.ico"
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "panel.bmp"
|
||||
|
||||
; Welcome page
|
||||
!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)
|
||||
return ret
|
||||
|
||||
def send(self, local, remote):
|
||||
def send(self, local, remote, makedirs=False):
|
||||
'''
|
||||
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 = self._cmd_str(cmd, ssh='scp')
|
||||
|
||||
|
@ -6,18 +6,39 @@ from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
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
|
||||
|
||||
.. 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)
|
||||
single = salt.client.ssh.Single(
|
||||
__opts__,
|
||||
'',
|
||||
**__salt__.kwargs)
|
||||
ret = single.shell.send(src, dest)
|
||||
ret = single.shell.send(src, dest, makedirs)
|
||||
return not ret[2]
|
||||
|
||||
|
||||
@ -74,3 +95,56 @@ def list_master_symlinks(saltenv='base', prefix=''):
|
||||
List all of the symlinks stored on the master
|
||||
'''
|
||||
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:
|
||||
node_data = conn.create_node(**kwargs) # pylint: disable=W0142
|
||||
node_data = conn.create_node(**kwargs)
|
||||
except Exception as exc: # pylint: disable=W0703
|
||||
log.error(
|
||||
'Error creating {0} on GCE\n\n'
|
||||
@ -2179,7 +2179,6 @@ def create(vm_=None, call=None):
|
||||
transport=__opts__['transport']
|
||||
)
|
||||
|
||||
# pylint: disable=W0142
|
||||
deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)
|
||||
if deployed:
|
||||
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']
|
||||
if 'primaryBackendIpAddress' in nodes[node]:
|
||||
ret[node]['private_ips'] = nodes[node]['primaryBackendIpAddress']
|
||||
if 'status' in nodes[node]:
|
||||
ret[node]['state'] = str(nodes[node]['status']['name'])
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -577,7 +577,7 @@ def _verify_auth(repo):
|
||||
'''
|
||||
Helper function to log errors about missing auth parameters
|
||||
'''
|
||||
log.error(
|
||||
log.critical(
|
||||
'Incomplete authentication information for remote {0}. Missing '
|
||||
'parameters: {1}'.format(remote_url, ', '.join(missing))
|
||||
)
|
||||
@ -600,9 +600,9 @@ def _verify_auth(repo):
|
||||
user = address.split('@')[0]
|
||||
if user == address:
|
||||
# No '@' sign == no user. This is a problem.
|
||||
log.error(
|
||||
'Password / keypair specified for remote {0}, but remote '
|
||||
'URL is missing a username'.format(repo['url'])
|
||||
log.critical(
|
||||
'Keypair specified for remote {0}, but remote URL is missing '
|
||||
'a username'.format(repo['url'])
|
||||
)
|
||||
_failhard()
|
||||
|
||||
@ -625,7 +625,7 @@ def _verify_auth(repo):
|
||||
return True
|
||||
if password_ok:
|
||||
if transport == 'http' and not repo['insecure_auth']:
|
||||
log.error(
|
||||
log.critical(
|
||||
'Invalid configuration for gitfs remote {0}. '
|
||||
'Authentication is disabled by default on http remotes. '
|
||||
'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])]
|
||||
_incomplete_auth(repo['url'], missing_auth)
|
||||
else:
|
||||
log.error(
|
||||
log.critical(
|
||||
'Invalid configuration for remote {0}. Unsupported transport '
|
||||
'{1!r}.'.format(repo['url'], transport)
|
||||
)
|
||||
@ -705,7 +705,7 @@ def init():
|
||||
six.iteritems(salt.utils.repack_dictlist(remote[repo_url]))]
|
||||
)
|
||||
if not per_remote_conf:
|
||||
log.error(
|
||||
log.critical(
|
||||
'Invalid per-remote configuration for gitfs remote {0}. '
|
||||
'If no per-remote parameters are being specified, there '
|
||||
'may be a trailing colon after the URL, which should be '
|
||||
@ -816,7 +816,7 @@ def init():
|
||||
'{0}'.format(exc))
|
||||
if provider == 'gitpython':
|
||||
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()
|
||||
|
||||
if new_remote:
|
||||
@ -1152,7 +1152,21 @@ def update():
|
||||
except KeyError:
|
||||
# No credentials configured for this repo
|
||||
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:
|
||||
# pygit2.Remote.fetch() returns a dict in pygit2 < 0.21.0
|
||||
received_objects = fetch['received_objects']
|
||||
@ -1160,10 +1174,16 @@ def update():
|
||||
# pygit2.Remote.fetch() returns a class instance in
|
||||
# pygit2 >= 0.21.0
|
||||
received_objects = fetch.received_objects
|
||||
log.debug(
|
||||
'gitfs received {0} objects for remote {1}'
|
||||
.format(received_objects, repo['url'])
|
||||
)
|
||||
if received_objects != 0:
|
||||
log.debug(
|
||||
'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
|
||||
refs_post = repo['repo'].listall_references()
|
||||
cleaned = _clean_stale(repo['repo'], refs_post)
|
||||
@ -1180,14 +1200,14 @@ def update():
|
||||
try:
|
||||
refs_post = client.fetch(path, repo['repo'])
|
||||
except dulwich.errors.NotGitRepository:
|
||||
log.critical(
|
||||
log.error(
|
||||
'Dulwich does not recognize remote {0} as a valid '
|
||||
'remote URL. Perhaps it is missing \'.git\' at the '
|
||||
'end.'.format(repo['url'])
|
||||
)
|
||||
continue
|
||||
except KeyError:
|
||||
log.critical(
|
||||
log.error(
|
||||
'Local repository cachedir {0!r} (corresponding '
|
||||
'remote: {1}) has been corrupted. Salt will now '
|
||||
'attempt to remove the local checkout to allow it to '
|
||||
@ -1198,7 +1218,7 @@ def update():
|
||||
try:
|
||||
salt.utils.rm_rf(repo['cachedir'])
|
||||
except OSError as exc:
|
||||
log.critical(
|
||||
log.error(
|
||||
'Unable to remove {0!r}: {1}'
|
||||
.format(repo['cachedir'], exc)
|
||||
)
|
||||
@ -1626,7 +1646,7 @@ def _file_lists(load, form):
|
||||
try:
|
||||
os.makedirs(list_cachedir)
|
||||
except os.error:
|
||||
log.critical('Unable to make cachedir {0}'.format(list_cachedir))
|
||||
log.error('Unable to make cachedir {0}'.format(list_cachedir))
|
||||
return []
|
||||
list_cache = os.path.join(
|
||||
list_cachedir,
|
||||
|
@ -203,7 +203,7 @@ def cql_query(query, contact_points=None, port=None, cql_user=None, cql_pass=Non
|
||||
if results:
|
||||
for result in results:
|
||||
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
|
||||
if not isinstance(value, six.text_type):
|
||||
value = str(value)
|
||||
|
@ -48,7 +48,7 @@ def load():
|
||||
datastore_path = os.path.join(__opts__['cachedir'], 'datastore')
|
||||
fn_ = salt.utils.fopen(datastore_path, 'rb')
|
||||
return serial.load(fn_)
|
||||
except (IOError, OSError):
|
||||
except (IOError, OSError, NameError):
|
||||
return {}
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ def dump(new_data):
|
||||
|
||||
return True
|
||||
|
||||
except (IOError, OSError):
|
||||
except (IOError, OSError, NameError):
|
||||
return False
|
||||
|
||||
|
||||
|
@ -1696,7 +1696,7 @@ def replace(path,
|
||||
raise CommandExecutionError("Exception: {0}".format(exc))
|
||||
|
||||
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
|
||||
if prepend_if_not_found:
|
||||
new_file.insert(0, not_found_content + '\n')
|
||||
|
@ -587,7 +587,11 @@ def find_cached_job(jid):
|
||||
buf = fp_.read()
|
||||
fp_.close()
|
||||
if buf:
|
||||
data = serial.loads(buf)
|
||||
try:
|
||||
data = serial.loads(buf)
|
||||
except NameError:
|
||||
# msgpack error in salt-ssh
|
||||
return
|
||||
else:
|
||||
return
|
||||
if not isinstance(data, dict):
|
||||
|
@ -736,7 +736,7 @@ def bootstrap(directory='.',
|
||||
with salt.utils.fopen(b_py) as fic:
|
||||
content = fic.read()
|
||||
if (
|
||||
(False != test_release)
|
||||
(test_release is not False)
|
||||
and ' --accept-buildout-test-releases' in content
|
||||
):
|
||||
bootstrap_args += ' --accept-buildout-test-releases'
|
||||
|
@ -1,11 +1,9 @@
|
||||
# encoding: utf-8
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import absolute_import, print_function
|
||||
import hashlib
|
||||
import logging
|
||||
import distutils.version
|
||||
import distutils.version # pylint: disable=no-name-in-module
|
||||
|
||||
__virtualname__ = 'rest_tornado'
|
||||
|
||||
|
@ -26,12 +26,12 @@ returns a list of key/value pairs for all of the EC2 tags assigned to
|
||||
the instance.
|
||||
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import re
|
||||
import logging
|
||||
from distutils.version import StrictVersion
|
||||
from distutils.version import StrictVersion # pylint: disable=no-name-in-module
|
||||
|
||||
# Import AWS Boto libs
|
||||
try:
|
||||
|
@ -457,7 +457,7 @@ def ext_pillar(minion_id, pillar, resource, sequence, subkey=False, subkey_only=
|
||||
immutable[rkey] = True
|
||||
if rkey not in output:
|
||||
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))
|
||||
elif isinstance(results[key], dict):
|
||||
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))
|
||||
|
||||
return ret
|
||||
except Exception as e:
|
||||
except Exception as exc:
|
||||
ret['result'] = False
|
||||
ret['comment'] = e
|
||||
ret['comment'] = exc
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -276,7 +276,8 @@ def _load_accumulators():
|
||||
with open(path, 'rb') as f:
|
||||
loaded = serial.load(f)
|
||||
return loaded if loaded else ret
|
||||
except IOError:
|
||||
except (IOError, NameError):
|
||||
# NameError is a msgpack error from salt-ssh
|
||||
return ret
|
||||
|
||||
loaded = _deserialize(_get_accumulator_filepath())
|
||||
@ -290,8 +291,12 @@ def _persist_accummulators(accumulators, accumulators_deps):
|
||||
'accumulators_deps': accumulators_deps}
|
||||
|
||||
serial = salt.payload.Serial(__opts__)
|
||||
with open(_get_accumulator_filepath(), 'w+b') as f:
|
||||
serial.dump(accumm_data, f)
|
||||
try:
|
||||
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):
|
||||
|
@ -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
|
||||
'''
|
||||
timenow = datetime.datetime.utcnow()
|
||||
timestamp = timenow.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
|
||||
# Retrieve access credentials from meta-data, or use provided
|
||||
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
|
||||
keys = sorted(params_with_headers.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')
|
||||
datestamp = timenow.strftime('%Y%m%d')
|
||||
payload_hash = hashlib.sha256('').hexdigest()
|
||||
|
||||
canonical_headers = 'host:{0}\nx-amz-date:{1}\n'.format(
|
||||
endpoint,
|
||||
@ -167,11 +165,6 @@ def sig4(method, endpoint, params, prov_dict, aws_api_version, location,
|
||||
)
|
||||
signed_headers = 'host;x-amz-date'
|
||||
|
||||
request = '\n'.join((
|
||||
method, endpoint, querystring, canonical_headers,
|
||||
signed_headers, payload_hash
|
||||
))
|
||||
|
||||
algorithm = 'AWS4-HMAC-SHA256'
|
||||
|
||||
# Create payload hash (hash of the request body content). For GET
|
||||
|
@ -22,7 +22,7 @@ class DecoratorTest(integration.ModuleCase):
|
||||
def not_test_depends(self):
|
||||
ret = self.run_function('runtests_decorators.depends')
|
||||
self.assertTrue(ret['ret'])
|
||||
self.assertTrue(type(ret['time']) == float)
|
||||
self.assertTrue(isinstance(ret['time'], float))
|
||||
|
||||
def test_missing_depends(self):
|
||||
self.assertIn(
|
||||
@ -49,7 +49,7 @@ class DecoratorTest(integration.ModuleCase):
|
||||
def not_test_depends_will_fallback(self):
|
||||
ret = self.run_function('runtests_decorators.depends_will_fallback')
|
||||
self.assertTrue(ret['ret'])
|
||||
self.assertTrue(type(ret['time']) == float)
|
||||
self.assertTrue(isinstance(ret['time'], float))
|
||||
|
||||
def test_missing_depends_again(self):
|
||||
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 tests
|
||||
#self.assertTrue(
|
||||
# u''
|
||||
# u'OUTPUT:\n'
|
||||
# u'foo\n'
|
||||
# u''
|
||||
#in ret1['outlog']
|
||||
# u''
|
||||
# u'OUTPUT:\n'
|
||||
# u'foo\n'
|
||||
# u''
|
||||
# in ret1['outlog']
|
||||
#)
|
||||
|
||||
# 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 tests
|
||||
# self.assertTrue(
|
||||
# u'INFO: ibar\n'
|
||||
# u'WARN: wbar\n'
|
||||
# u'DEBUG: dbar\n'
|
||||
# u'ERROR: ebar\n'
|
||||
#in ret1['outlog']
|
||||
# u'INFO: ibar\n'
|
||||
# u'WARN: wbar\n'
|
||||
# u'DEBUG: dbar\n'
|
||||
# u'ERROR: ebar\n'
|
||||
# in ret1['outlog']
|
||||
#)
|
||||
# These lines are throwing pylint errors - disabling for now since we are skipping
|
||||
# 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