diff --git a/doc/glossary.rst b/doc/glossary.rst index 290153a32635..75df13fca549 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -1,3 +1,6 @@ +.. _glossary: + +======== Glossary ======== diff --git a/doc/ref/clouds/all/salt.cloud.clouds.virtualbox.rst b/doc/ref/clouds/all/salt.cloud.clouds.virtualbox.rst index 410b823f3367..3f687e36809c 100644 --- a/doc/ref/clouds/all/salt.cloud.clouds.virtualbox.rst +++ b/doc/ref/clouds/all/salt.cloud.clouds.virtualbox.rst @@ -1,6 +1,6 @@ -======================== +============================ salt.cloud.clouds.virtualbox -======================== +============================ .. automodule:: salt.cloud.clouds.virtualbox :members: diff --git a/doc/ref/configuration/examples.rst b/doc/ref/configuration/examples.rst index 0493cc1100a2..373ca9c013d6 100644 --- a/doc/ref/configuration/examples.rst +++ b/doc/ref/configuration/examples.rst @@ -1,3 +1,5 @@ +.. _configuration-file-examples: + =========================== Configuration file examples =========================== diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 9ea37b2e8f99..59a5b8cc2951 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -794,7 +794,7 @@ Pass in an alternative location for the salt-ssh roster file. .. conf_master:: ssh_log_file ``ssh_log_file`` -------------------- +---------------- .. versionadded:: 2016.3.5 diff --git a/doc/ref/modules/all/index.rst b/doc/ref/modules/all/index.rst index 467d824103b6..1ec22fd3cbba 100644 --- a/doc/ref/modules/all/index.rst +++ b/doc/ref/modules/all/index.rst @@ -1,4 +1,4 @@ -.. _all-salt_modules: +.. _all-salt.modules: ================= execution modules diff --git a/doc/ref/modules/all/salt.modules.cytest.rst b/doc/ref/modules/all/salt.modules.cytest.rst index cf30b20cf409..cf808dafb67d 100644 --- a/doc/ref/modules/all/salt.modules.cytest.rst +++ b/doc/ref/modules/all/salt.modules.cytest.rst @@ -3,4 +3,3 @@ salt.modules.cytest module .. automodule:: salt.modules.cytest :members: - diff --git a/doc/ref/returners/index.rst b/doc/ref/returners/index.rst index 628a8ebbcbbb..138d681576cd 100644 --- a/doc/ref/returners/index.rst +++ b/doc/ref/returners/index.rst @@ -47,7 +47,7 @@ Writing a Returner A returner is a Python module containing at minimum a ``returner`` function. Other optional functions can be included to add support for -:ref:`master_job_cache`, :ref:`external_job_cache`, and `Event Returners`_. +:conf_master:`master_job_cache`, :ref:`external-job-cache`, and `Event Returners`_. ``returner`` The ``returner`` function must accept a single argument. The argument @@ -85,8 +85,8 @@ serializes the data as JSON and sets it in redis. Master Job Cache Support ------------------------ -:ref:`master_job_cache`, :ref:`external_job_cache`, and `Event Returners`_. -Salt's :ref:`master_job_cache` allows returners to be used as a pluggable +:conf_master:`master_job_cache`, :ref:`external-job-cache`, and `Event Returners`_. +Salt's :conf_master:`master_job_cache` allows returners to be used as a pluggable replacement for the :ref:`default_job_cache`. In order to do so, a returner must implement the following functions: @@ -176,7 +176,7 @@ must implement the following functions: External Job Cache Support -------------------------- -Salt's :ref:`external_job_cache` extends the :ref:`master_job_cache`. External +Salt's :ref:`external-job-cache` extends the :conf_master:`master_job_cache`. External Job Cache support requires the following functions in addition to what is required for Master Job Cache support: @@ -328,7 +328,7 @@ Testing the Returner The ``returner``, ``prep_jid``, ``save_load``, ``get_load``, and ``event_return`` functions can be tested by configuring the -:ref:`master_job_cache` and `Event Returners`_ in the master config +:conf_master:`master_job_cache` and `Event Returners`_ in the master config file and submitting a job to ``test.ping`` each minion from the master. Once you have successfully exercised the Master Job Cache functions, test the diff --git a/doc/topics/cloud/misc.rst b/doc/topics/cloud/misc.rst index 952abc10f42e..3ef1518923c9 100644 --- a/doc/topics/cloud/misc.rst +++ b/doc/topics/cloud/misc.rst @@ -94,7 +94,7 @@ profile or map: Setting Up a Salt Syndic with Salt Cloud ======================================== -In addition to `setting up new Salt Masters`_, :ref:`syndic`s can also be +In addition to `setting up new Salt Masters`_, :ref:`syndics ` can also be provisioned using Salt Cloud. In order to set up a Salt Syndic via Salt Cloud, a Salt Master needs to be installed on the new machine and a master configuration file needs to be set up using the ``make_master`` setting. This setting can be diff --git a/doc/topics/development/contributing.rst b/doc/topics/development/contributing.rst index 3c879c991bea..2c0afa048b5e 100644 --- a/doc/topics/development/contributing.rst +++ b/doc/topics/development/contributing.rst @@ -418,3 +418,4 @@ and bug resolution. See the :ref:`Labels and Milestones .. _'Git resources`: https://help.github.com/articles/good-resources-for-learning-git-and-github/ .. _`Closing issues via commit message`: https://help.github.com/articles/closing-issues-via-commit-messages .. _`git format-patch`: https://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html +.. _salt-users: https://groups.google.com/forum/#!forum/salt-users diff --git a/doc/topics/development/modular_systems.rst b/doc/topics/development/modular_systems.rst index b2943353568f..6060ceea88cc 100644 --- a/doc/topics/development/modular_systems.rst +++ b/doc/topics/development/modular_systems.rst @@ -25,7 +25,7 @@ modules is that the defined functions always return a JSON serializable object. For a list of all built in execution modules, click :ref:`here -` +` For information on writing execution modules, see :ref:`this page `. diff --git a/doc/topics/execution/index.rst b/doc/topics/execution/index.rst index c3e439044dac..0876542e5f4a 100644 --- a/doc/topics/execution/index.rst +++ b/doc/topics/execution/index.rst @@ -15,7 +15,7 @@ a wide variety of tasks. These modules provide functionality such as installing packages, restarting a service, running a remote command, transferring files, and so on. - :ref:`Full list of execution modules ` + :ref:`Full list of execution modules ` Contains: a list of core modules that ship with Salt. :ref:`Writing execution modules ` diff --git a/doc/topics/highavailability/index.rst b/doc/topics/highavailability/index.rst index 088e42b6db1d..6f9d5f07afab 100644 --- a/doc/topics/highavailability/index.rst +++ b/doc/topics/highavailability/index.rst @@ -6,7 +6,7 @@ High Availability Features in Salt Salt supports several features for high availability and fault tolerance. Brief documentation for these features is listed alongside their configuration -parameters in :ref:`Configuration file examples `. +parameters in :ref:`Configuration file examples `. Multimaster =========== diff --git a/doc/topics/index.rst b/doc/topics/index.rst index 28176b230447..a4d9f6805298 100644 --- a/doc/topics/index.rst +++ b/doc/topics/index.rst @@ -6,6 +6,7 @@ Introduction to Salt The 30 second summary ===================== + Salt is: * a configuration management system, capable of maintaining remote nodes @@ -89,3 +90,101 @@ the Salt project so that we can all benefit together as Salt grows. Please feel free to sprinkle Salt around your systems and let the deliciousness come forth. +.. _salt-community: + +Salt Community +============== + +Join the Salt! + +There are many ways to participate in and communicate with the Salt community. + +Salt has an active IRC channel and a mailing list. + +Mailing List +============ + +Join the `salt-users mailing list`_. It is the best place to ask questions +about Salt and see whats going on with Salt development! The Salt mailing list +is hosted by Google Groups. It is open to new members. + +.. _`salt-users mailing list`: https://groups.google.com/forum/#!forum/salt-users + + +IRC +=== + +The ``#salt`` IRC channel is hosted on the popular `Freenode`_ network. You +can use the `Freenode webchat client`_ right from your browser. + +`Logs of the IRC channel activity`_ are being collected courtesy of Moritz Lenz. + +.. _Freenode:: http://freenode.net/irc_servers.shtml +.. _Freenode webchat client:: http://webchat.freenode.net/?channels=salt&uio=Mj10cnVlJjk9dHJ1ZSYxMD10cnVl83 +.. _Logs of the IRC channel activity:: http://irclog.perlgeek.de/salt/ + +If you wish to discuss the development of Salt itself join us in +``#salt-devel``. + + +Follow on Github +================ + +The Salt code is developed via Github. Follow Salt for constant updates on what +is happening in Salt development: + +|saltrepo| + + +Blogs +===== + +SaltStack Inc. keeps a `blog`_ with recent news and advancements: + +http://www.saltstack.com/blog/ + +.. _`blog`: http://www.saltstack.com/blog/ + + +Example Salt States +=================== + +The official ``salt-states`` repository is: +https://github.com/saltstack/salt-states + +A few examples of salt states from the community: + +* https://github.com/blast-hardcheese/blast-salt-states +* https://github.com/kevingranade/kevingranade-salt-state +* https://github.com/uggedal/states +* https://github.com/mattmcclean/salt-openstack/tree/master/salt +* https://github.com/rentalita/ubuntu-setup/ +* https://github.com/brutasse/states +* https://github.com/bclermont/states +* https://github.com/pcrews/salt-data + +Follow on ohloh +=============== + +https://www.ohloh.net/p/salt + +Other community links +===================== + +- `Salt Stack Inc. `_ +- `Subreddit `_ +- `Google+ `_ +- `YouTube `_ +- `Facebook `_ +- `Twitter `_ +- `Wikipedia page `_ + +Hack the Source +=============== + +If you want to get involved with the development of source code or the +documentation efforts, please review the :ref:`contributing documentation +`! + +.. _`Apache 2.0 license`: http://www.apache.org/licenses/LICENSE-2.0.html + diff --git a/doc/topics/jinja/index.rst b/doc/topics/jinja/index.rst index a4b68171e09d..7fbd6b982bbe 100644 --- a/doc/topics/jinja/index.rst +++ b/doc/topics/jinja/index.rst @@ -1,4 +1,4 @@ -.. _jinja: +.. _understanding-jinja: =================== Understanding Jinja diff --git a/doc/topics/jobs/external_cache.rst b/doc/topics/jobs/external_cache.rst index e8b805e89655..ed260af0b6e3 100644 --- a/doc/topics/jobs/external_cache.rst +++ b/doc/topics/jobs/external_cache.rst @@ -1,4 +1,4 @@ -.. _external-master-cache: +.. _external-job-cache: ========================================= Storing Job Results in an External System diff --git a/doc/topics/jobs/job_cache.rst b/doc/topics/jobs/job_cache.rst index 734feecc9dc2..6b08eb850340 100644 --- a/doc/topics/jobs/job_cache.rst +++ b/doc/topics/jobs/job_cache.rst @@ -67,6 +67,6 @@ Many deployments may wish to use an external database to maintain a long term register of executed jobs. Salt comes with two main mechanisms to do this, the master job cache and the external job cache. -See :ref:`Storing Job Results in an External System `. +See :ref:`Storing Job Results in an External System `. diff --git a/doc/topics/mine/index.rst b/doc/topics/mine/index.rst index b6412d2ba4f0..bad3f9bd9e0b 100644 --- a/doc/topics/mine/index.rst +++ b/doc/topics/mine/index.rst @@ -22,7 +22,7 @@ refreshed on a very limited basis and are largely static data. Mines are designed to replace slow peer publishing calls when Minions need data from other Minions. Rather than having a Minion reach out to all the other Minions for a piece of data, the Salt Mine, running on the Master, can collect it from -all the Minions every :ref:`mine-interval`, resulting in +all the Minions every :ref:`mine_interval`, resulting in almost fresh data at any given time, with much less overhead. Mine Functions diff --git a/doc/topics/reactor/index.rst b/doc/topics/reactor/index.rst index 773805db645e..2db796d3f76a 100644 --- a/doc/topics/reactor/index.rst +++ b/doc/topics/reactor/index.rst @@ -410,7 +410,7 @@ sets up and listens to the minions event bus, instead of to the masters. The biggest difference is that you have to use the caller method on the Reactor, which is the equivalent of salt-call, to run your commands. -:ref:`Reactor Engine setup` +:mod:`Reactor Engine setup ` .. code-block:: yaml diff --git a/doc/topics/releases/2014.1.0.rst b/doc/topics/releases/2014.1.0.rst index a95c97d9fc78..86621ad5a2ad 100644 --- a/doc/topics/releases/2014.1.0.rst +++ b/doc/topics/releases/2014.1.0.rst @@ -9,7 +9,7 @@ Salt 2014.1.0 Release Notes - Codename Hydrogen Due to a change in master to minion communication, 2014.1.0 minions are not compatible with older-version masters. Please upgrade masters first. More info on backwards-compatibility policy :ref:`here - `, under the "Upgrading Salt" subheading. .. note:: @@ -248,7 +248,7 @@ Proxy Minions ------------- Initial basic support for Proxy Minions is in this release. Documentation can -be found :ref:`here `. +be found :ref:`here `. Proxy minions are a developing feature in Salt that enables control of devices that cannot run a minion. Examples include network gear like switches and diff --git a/doc/topics/releases/2015.8.11.rst b/doc/topics/releases/2015.8.11.rst index 5d01f7cd05f9..8cec2335e403 100644 --- a/doc/topics/releases/2015.8.11.rst +++ b/doc/topics/releases/2015.8.11.rst @@ -17,7 +17,7 @@ New Configuration Parameter: ``rotate_aes_key`` - ``Rotate_aes_key`` causes Salt to generate a new AES key whenever a minion key is deleted. This eliminates the chance that a deleted minion could continue to eavesdrop on communications with the master if it continues to run after its - key is deleted. See the entry in the documentation for `rotate_aes_key`_. + key is deleted. See the entry in the documentation for :conf_master:`rotate_aes_key`. Ubuntu 16.04 Packages ===================== @@ -404,11 +404,13 @@ Changes: .. _`#20226`: https://github.com/saltstack/salt/pull/20226 .. _`#22480`: https://github.com/saltstack/salt/pull/22480 +.. _`#23643`: https://github.com/saltstack/salt/issues/23643 .. _`#25089`: https://github.com/saltstack/salt/pull/25089 .. _`#28325`: https://github.com/saltstack/salt/pull/28325 .. _`#28467`: https://github.com/saltstack/salt/pull/28467 .. _`#32484`: https://github.com/saltstack/salt/pull/32484 .. _`#32857`: https://github.com/saltstack/salt/pull/32857 +.. _`#33266`: https://github.com/saltstack/salt/issues/33266 .. _`#33282`: https://github.com/saltstack/salt/pull/33282 .. _`#33286`: https://github.com/saltstack/salt/pull/33286 .. _`#33287`: https://github.com/saltstack/salt/pull/33287 @@ -491,6 +493,7 @@ Changes: .. _`#33555`: https://github.com/saltstack/salt/pull/33555 .. _`#33558`: https://github.com/saltstack/salt/pull/33558 .. _`#33581`: https://github.com/saltstack/salt/pull/33581 +.. _`#33582`: https://github.com/saltstack/salt/issues/33582 .. _`#33599`: https://github.com/saltstack/salt/pull/33599 .. _`#33611`: https://github.com/saltstack/salt/pull/33611 .. _`#33615`: https://github.com/saltstack/salt/pull/33615 @@ -647,4 +650,3 @@ Changes: .. _`#34647`: https://github.com/saltstack/salt/pull/34647 .. _`#34651`: https://github.com/saltstack/salt/pull/34651 .. _`#34676`: https://github.com/saltstack/salt/pull/34676 -.. _ `rotate_aes_key`: https://docs.saltstack.com/en/2015.8/ref/configuration/master.html#rotate-aes-key diff --git a/doc/topics/releases/2015.8.4.rst b/doc/topics/releases/2015.8.4.rst index e6e605517071..56d84195c058 100644 --- a/doc/topics/releases/2015.8.4.rst +++ b/doc/topics/releases/2015.8.4.rst @@ -48,8 +48,6 @@ Core Changes salt '*' state.highstate mock=True salt '*' state.apply edit.vim mock=True -.. _`#28994`: https://github.com/saltstack/salt/pull/28994 - Changes for v2015.8.3..v2015.8.4 -------------------------------- @@ -515,7 +513,7 @@ Changes: - **PR** `#29317`_: (*basepi*) [2015.8] Merge forward from 2015.5 to 2015.8 -- **PR** `#29240`_: (*clan*) handle acl_type [[d]efault:][user|group|mask|other] +- **PR** `#29240`_: (*clan*) handle acl_type ``[[d]efault:][user|group|mask|other]`` - **PR** `#29305`_: (*lorengordon*) Add 'file' as a source_hash proto @@ -578,11 +576,13 @@ Changes: - **PR** `#29178`_: (*whytewolf*) Profile not being passed to keystone.endpoint_get in _auth. so if a p… .. _`#19332`: https://github.com/saltstack/salt/issues/19332 +.. _`#24237`: https://github.com/saltstack/salt/issues/24237 .. _`#29116`: https://github.com/saltstack/salt/issues/29116 .. _`#29187`: https://github.com/saltstack/salt/issues/29187 .. _`#23825`: https://github.com/saltstack/salt/pull/23825 .. _`#26511`: https://github.com/saltstack/salt/pull/26511 .. _`#26853`: https://github.com/saltstack/salt/pull/26853 +.. _`#26845`: https://github.com/saltstack/salt/issues/26845 .. _`#26962`: https://github.com/saltstack/salt/pull/26962 .. _`#27104`: https://github.com/saltstack/salt/pull/27104 .. _`#27606`: https://github.com/saltstack/salt/pull/27606 diff --git a/doc/topics/releases/2015.8.8.rst b/doc/topics/releases/2015.8.8.rst index fbe8d253f93d..fd5991cb4ee8 100644 --- a/doc/topics/releases/2015.8.8.rst +++ b/doc/topics/releases/2015.8.8.rst @@ -599,13 +599,16 @@ Changes: - **PR** `#30625`_: (*jfindlay*) doc.topics.eauth: clarify client_acl vs eauth +.. _`#27796`: https://github.com/saltstack/salt/issues/27796 .. _`#29650`: https://github.com/saltstack/salt/pull/29650 .. _`#29718`: https://github.com/saltstack/salt/pull/29718 .. _`#30062`: https://github.com/saltstack/salt/pull/30062 .. _`#30217`: https://github.com/saltstack/salt/pull/30217 .. _`#30279`: https://github.com/saltstack/salt/pull/30279 +.. _`#30300`: https://github.com/saltstack/salt/issues/30300 .. _`#30378`: https://github.com/saltstack/salt/pull/30378 .. _`#30458`: https://github.com/saltstack/salt/pull/30458 +.. _`#30461`: https://github.com/saltstack/salt/issues/30461 .. _`#30542`: https://github.com/saltstack/salt/pull/30542 .. _`#30586`: https://github.com/saltstack/salt/pull/30586 .. _`#30591`: https://github.com/saltstack/salt/pull/30591 @@ -664,6 +667,7 @@ Changes: .. _`#30813`: https://github.com/saltstack/salt/pull/30813 .. _`#30815`: https://github.com/saltstack/salt/pull/30815 .. _`#30818`: https://github.com/saltstack/salt/pull/30818 +.. _`#30820`: https://github.com/saltstack/salt/issues/30820 .. _`#30822`: https://github.com/saltstack/salt/pull/30822 .. _`#30823`: https://github.com/saltstack/salt/pull/30823 .. _`#30826`: https://github.com/saltstack/salt/pull/30826 @@ -700,6 +704,7 @@ Changes: .. _`#30920`: https://github.com/saltstack/salt/pull/30920 .. _`#30922`: https://github.com/saltstack/salt/pull/30922 .. _`#30924`: https://github.com/saltstack/salt/pull/30924 +.. _`#30934`: https://github.com/saltstack/salt/issues/30934 .. _`#30940`: https://github.com/saltstack/salt/pull/30940 .. _`#30941`: https://github.com/saltstack/salt/pull/30941 .. _`#30942`: https://github.com/saltstack/salt/pull/30942 @@ -713,10 +718,12 @@ Changes: .. _`#30978`: https://github.com/saltstack/salt/pull/30978 .. _`#30987`: https://github.com/saltstack/salt/pull/30987 .. _`#30998`: https://github.com/saltstack/salt/pull/30998 +.. _`#30999`: https://github.com/saltstack/salt/issues/30999 .. _`#31002`: https://github.com/saltstack/salt/pull/31002 .. _`#31004`: https://github.com/saltstack/salt/pull/31004 .. _`#31007`: https://github.com/saltstack/salt/pull/31007 .. _`#31012`: https://github.com/saltstack/salt/pull/31012 +.. _`#31014`: https://github.com/saltstack/salt/issues/31014 .. _`#31015`: https://github.com/saltstack/salt/pull/31015 .. _`#31024`: https://github.com/saltstack/salt/pull/31024 .. _`#31026`: https://github.com/saltstack/salt/pull/31026 @@ -737,6 +744,7 @@ Changes: .. _`#31100`: https://github.com/saltstack/salt/pull/31100 .. _`#31103`: https://github.com/saltstack/salt/pull/31103 .. _`#31105`: https://github.com/saltstack/salt/pull/31105 +.. _`#31106`: https://github.com/saltstack/salt/issues/31106 .. _`#31107`: https://github.com/saltstack/salt/pull/31107 .. _`#31108`: https://github.com/saltstack/salt/pull/31108 .. _`#31110`: https://github.com/saltstack/salt/pull/31110 @@ -769,6 +777,7 @@ Changes: .. _`#31191`: https://github.com/saltstack/salt/pull/31191 .. _`#31196`: https://github.com/saltstack/salt/pull/31196 .. _`#31201`: https://github.com/saltstack/salt/pull/31201 +.. _`#31223`: https://github.com/saltstack/salt/issues/31223 .. _`#31225`: https://github.com/saltstack/salt/pull/31225 .. _`#31226`: https://github.com/saltstack/salt/pull/31226 .. _`#31233`: https://github.com/saltstack/salt/pull/31233 @@ -868,6 +877,7 @@ Changes: .. _`#31598`: https://github.com/saltstack/salt/pull/31598 .. _`#31601`: https://github.com/saltstack/salt/pull/31601 .. _`#31604`: https://github.com/saltstack/salt/pull/31604 +.. _`#31617`: https://github.com/saltstack/salt/issues/31617 .. _`#31622`: https://github.com/saltstack/salt/pull/31622 .. _`#31627`: https://github.com/saltstack/salt/pull/31627 .. _`#31629`: https://github.com/saltstack/salt/pull/31629 diff --git a/doc/topics/releases/2015.8.9.rst b/doc/topics/releases/2015.8.9.rst index 3ce305c7117f..8053ed83fb41 100644 --- a/doc/topics/releases/2015.8.9.rst +++ b/doc/topics/releases/2015.8.9.rst @@ -297,7 +297,7 @@ Changes: - **PR** `#32425`_: (*cachedout*) Fix salt-cloud parallel provisioning -* 51fb2ac FreeBSD supports packages in format java/openjdk7 so the prior commit broke that functionality. Check freebsd/pkg`#1409`_ for more info. +* 51fb2ac FreeBSD supports packages in format java/openjdk7 so the prior commit broke that functionality. Check freebsd/pkg #1409 for more info. * 709410a Improve git_pillar documentation/logging @@ -325,7 +325,7 @@ Changes: - **PR** `#32321`_: (*abednarik*) Better message when minion fail to start -- **PR** `#32345`_: (*nmadhok*) [2015.8] Check if profile key exists in vm_ dict +- **PR** `#32345`_: (*nmadhok*) [2015.8] Check if profile key exists in ``vm_`` dict - **PR** `#32343`_: (*Ferbla*) Fixed win_wua example documentation @@ -467,15 +467,21 @@ Changes: - **PR** `#31912`_: (*jfindlay*) log.mixins: remove extermporaneous .record +.. _`#14277`: https://github.com/saltstack/salt/issues/14277 +.. _`#23714`: https://github.com/saltstack/salt/issues/23714 +.. _`#24237`: https://github.com/saltstack/salt/issues/24237 .. _`#26518`: https://github.com/saltstack/salt/pull/26518 .. _`#26648`: https://github.com/saltstack/salt/pull/26648 .. _`#26676`: https://github.com/saltstack/salt/pull/26676 +.. _`#28262`: https://github.com/saltstack/salt/issues/28262 .. _`#28639`: https://github.com/saltstack/salt/pull/28639 +.. _`#28706`: https://github.com/saltstack/salt/issues/28706 .. _`#29322`: https://github.com/saltstack/salt/pull/29322 .. _`#30824`: https://github.com/saltstack/salt/pull/30824 .. _`#31139`: https://github.com/saltstack/salt/pull/31139 .. _`#31162`: https://github.com/saltstack/salt/pull/31162 .. _`#31164`: https://github.com/saltstack/salt/pull/31164 +.. _`#31270`: https://github.com/saltstack/salt/issues/31270 .. _`#31364`: https://github.com/saltstack/salt/pull/31364 .. _`#31382`: https://github.com/saltstack/salt/pull/31382 .. _`#31598`: https://github.com/saltstack/salt/pull/31598 @@ -778,6 +784,7 @@ Changes: .. _`#33224`: https://github.com/saltstack/salt/pull/33224 .. _`#33236`: https://github.com/saltstack/salt/pull/33236 .. _`#33237`: https://github.com/saltstack/salt/pull/33237 +.. _`#33238`: https://github.com/saltstack/salt/issues/33238 .. _`#33239`: https://github.com/saltstack/salt/pull/33239 .. _`#33244`: https://github.com/saltstack/salt/pull/33244 .. _`#33245`: https://github.com/saltstack/salt/pull/33245 @@ -789,5 +796,6 @@ Changes: .. _`#33274`: https://github.com/saltstack/salt/pull/33274 .. _`#33293`: https://github.com/saltstack/salt/pull/33293 .. _`#33294`: https://github.com/saltstack/salt/pull/33294 +.. _`#33299`: https://github.com/saltstack/salt/issues/33299 .. _`#33300`: https://github.com/saltstack/salt/pull/33300 .. _`#33305`: https://github.com/saltstack/salt/pull/33305 diff --git a/doc/topics/releases/2016.3.0.rst b/doc/topics/releases/2016.3.0.rst index f22e70ae1e7c..4d9e9cbe731a 100644 --- a/doc/topics/releases/2016.3.0.rst +++ b/doc/topics/releases/2016.3.0.rst @@ -351,7 +351,7 @@ Documentation of the Dimension Data SaltStack integration is found on `developer Minion Blackout --------------- During a blackout, minions will not execute any remote execution commands, -except for :ref:`saltutil.refresh_pillar +except for :mod:`saltutil.refresh_pillar `. Blackouts are enabled using a special pillar key, ``minion_blackout`` set to ``True``. diff --git a/doc/topics/releases/2016.3.1.rst b/doc/topics/releases/2016.3.1.rst index f9a36a3eb5d2..509c9ad854e3 100644 --- a/doc/topics/releases/2016.3.1.rst +++ b/doc/topics/releases/2016.3.1.rst @@ -155,14 +155,18 @@ Changes: .. _`#33519`: https://github.com/saltstack/salt/pull/33519 .. _`#33520`: https://github.com/saltstack/salt/pull/33520 .. _`#33522`: https://github.com/saltstack/salt/pull/33522 +.. _`#33530`: https://github.com/saltstack/salt/issues/33530 .. _`#33538`: https://github.com/saltstack/salt/pull/33538 .. _`#33549`: https://github.com/saltstack/salt/pull/33549 .. _`#33550`: https://github.com/saltstack/salt/pull/33550 .. _`#33555`: https://github.com/saltstack/salt/pull/33555 .. _`#33558`: https://github.com/saltstack/salt/pull/33558 .. _`#33562`: https://github.com/saltstack/salt/pull/33562 +.. _`#33565`: https://github.com/saltstack/salt/issues/33565 .. _`#33576`: https://github.com/saltstack/salt/pull/33576 +.. _`#33578`: https://github.com/saltstack/salt/issues/33578 .. _`#33581`: https://github.com/saltstack/salt/pull/33581 +.. _`#33590`: https://github.com/saltstack/salt/issues/33590 .. _`#33599`: https://github.com/saltstack/salt/pull/33599 .. _`#33603`: https://github.com/saltstack/salt/pull/33603 .. _`#33604`: https://github.com/saltstack/salt/pull/33604 @@ -170,6 +174,7 @@ Changes: .. _`#33613`: https://github.com/saltstack/salt/pull/33613 .. _`#33615`: https://github.com/saltstack/salt/pull/33615 .. _`#33631`: https://github.com/saltstack/salt/pull/33631 +.. _`#33632`: https://github.com/saltstack/salt/issues/33632 .. _`#33637`: https://github.com/saltstack/salt/pull/33637 .. _`#33638`: https://github.com/saltstack/salt/pull/33638 .. _`#33641`: https://github.com/saltstack/salt/pull/33641 @@ -205,6 +210,7 @@ Changes: .. _`#33743`: https://github.com/saltstack/salt/pull/33743 .. _`#33745`: https://github.com/saltstack/salt/pull/33745 .. _`#33748`: https://github.com/saltstack/salt/pull/33748 +.. _`#33754`: https://github.com/saltstack/salt/issues/33754 .. _`#33757`: https://github.com/saltstack/salt/pull/33757 .. _`#33759`: https://github.com/saltstack/salt/pull/33759 .. _`#33763`: https://github.com/saltstack/salt/pull/33763 diff --git a/doc/topics/releases/2016.3.4.rst b/doc/topics/releases/2016.3.4.rst index 4da922a103e6..4cd6e5a7b3f9 100644 --- a/doc/topics/releases/2016.3.4.rst +++ b/doc/topics/releases/2016.3.4.rst @@ -423,6 +423,7 @@ Changes: .. _`#36016`: https://github.com/saltstack/salt/pull/36016 .. _`#36018`: https://github.com/saltstack/salt/pull/36018 .. _`#36019`: https://github.com/saltstack/salt/pull/36019 +.. _`#36021`: https://github.com/saltstack/salt/issues/36021 .. _`#36022`: https://github.com/saltstack/salt/pull/36022 .. _`#36023`: https://github.com/saltstack/salt/pull/36023 .. _`#36024`: https://github.com/saltstack/salt/pull/36024 @@ -434,6 +435,7 @@ Changes: .. _`#36039`: https://github.com/saltstack/salt/pull/36039 .. _`#36040`: https://github.com/saltstack/salt/pull/36040 .. _`#36047`: https://github.com/saltstack/salt/pull/36047 +.. _`#36055`: https://github.com/saltstack/salt/issues/36055 .. _`#36061`: https://github.com/saltstack/salt/pull/36061 .. _`#36062`: https://github.com/saltstack/salt/pull/36062 .. _`#36068`: https://github.com/saltstack/salt/pull/36068 @@ -474,6 +476,7 @@ Changes: .. _`#36227`: https://github.com/saltstack/salt/pull/36227 .. _`#36235`: https://github.com/saltstack/salt/pull/36235 .. _`#36238`: https://github.com/saltstack/salt/pull/36238 +.. _`#36240`: https://github.com/saltstack/salt/issues/36240 .. _`#36241`: https://github.com/saltstack/salt/pull/36241 .. _`#36244`: https://github.com/saltstack/salt/pull/36244 .. _`#36245`: https://github.com/saltstack/salt/pull/36245 @@ -731,6 +734,7 @@ Changes: .. _`#37179`: https://github.com/saltstack/salt/pull/37179 .. _`#37183`: https://github.com/saltstack/salt/pull/37183 .. _`#37186`: https://github.com/saltstack/salt/pull/37186 +.. _`#37187`: https://github.com/saltstack/salt/issues/37187 .. _`#37188`: https://github.com/saltstack/salt/pull/37188 .. _`#37206`: https://github.com/saltstack/salt/pull/37206 .. _`#37207`: https://github.com/saltstack/salt/pull/37207 diff --git a/doc/topics/tutorials/gitfs.rst b/doc/topics/tutorials/gitfs.rst index 383c39a938e2..877c337aae60 100644 --- a/doc/topics/tutorials/gitfs.rst +++ b/doc/topics/tutorials/gitfs.rst @@ -63,7 +63,8 @@ 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 +pygit2_ website has installation instructions +`here `_. Keep in mind however that following these instructions will install libgit2_ and pygit2_ without system packages. Additionally, keep in mind that :ref:`SSH authentication in pygit2 ` requires libssh2_ (*not* libssh) development @@ -80,26 +81,26 @@ advisable as several other applications depend on it, so on older LTS linux releases pygit2_ 0.20.3 and libgit2_ 0.20.0 is the recommended combination. While these are not packaged in the official repositories for Debian and Ubuntu, SaltStack is actively working on adding packages for these to our -repositories_. The progress of this effort can be tracked here__. +repositories_. The progress of this effort can be tracked `here `_. .. warning:: - pygit2_ is actively developed and :ref:`frequently makes - non-backwards-compatible API changes `, even in + pygit2_ is actively developed and `frequently makes + non-backwards-compatible API changes `_, even in minor releases. It is not uncommon for pygit2_ upgrades to result in errors in Salt. Please take care when upgrading pygit2_, and pay close attention to the changelog_, keeping an eye out for API changes. Errors can be - reported on the :ref:`SaltStack issue tracker `. + reported on the `SaltStack issue tracker `_. .. _pygit2-version-policy: http://www.pygit2.org/install.html#version-numbers .. _changelog: https://github.com/libgit2/pygit2#changelog .. _saltstack-issue-tracker: https://github.com/saltstack/salt/issues -.. __: http://www.pygit2.org/install.html +.. _pygit2-install-instructions: http://www.pygit2.org/install.html .. _libgit2: https://libgit2.github.com/ .. _libssh2: http://www.libssh2.org/ .. _python-cffi: https://pypi.python.org/pypi/cffi .. _libffi: http://sourceware.org/libffi/ .. _repositories: https://repo.saltstack.com -.. __: https://github.com/saltstack/salt-pack/issues/70 +.. _salt-pack-70: https://github.com/saltstack/salt-pack/issues/70 GitPython --------- @@ -934,7 +935,7 @@ match the user under which the minion is running. .. _`post-receive hook`: http://www.git-scm.com/book/en/Customizing-Git-Git-Hooks#Server-Side-Hooks -.. _git-as-ext_pillar +.. _git-as-ext_pillar: Using Git as an External Pillar Source ====================================== diff --git a/doc/topics/tutorials/http.rst b/doc/topics/tutorials/http.rst index c01bf7fcabad..1eaee6207196 100644 --- a/doc/topics/tutorials/http.rst +++ b/doc/topics/tutorials/http.rst @@ -377,7 +377,8 @@ using the ``ca_bundle`` variable. ) Updating CA Bundles -''''''''''''''''''' +``````````````````` + The ``update_ca_bundle()`` function can be used to update the bundle file at a specified location. If the target location is not specified, then it will attempt to auto-detect the location of the bundle file. If the URL to download diff --git a/doc/topics/tutorials/modules.rst b/doc/topics/tutorials/modules.rst index 415c9e9f547c..e1dbde7d764f 100644 --- a/doc/topics/tutorials/modules.rst +++ b/doc/topics/tutorials/modules.rst @@ -82,7 +82,7 @@ Run an arbitrary shell command: salt '*' cmd.run 'uname -a' -.. seealso:: :ref:`the full list of modules ` +.. seealso:: :ref:`the full list of modules ` arguments --------- diff --git a/doc/topics/tutorials/starting_states.rst b/doc/topics/tutorials/starting_states.rst index bc0fa2bc8dcb..16448b608f70 100644 --- a/doc/topics/tutorials/starting_states.rst +++ b/doc/topics/tutorials/starting_states.rst @@ -348,7 +348,7 @@ gives you a `"Pythonic"`_ interface to building state data. They can also be used in :mod:`file.managed ` states, making file management much more dynamic and flexible. Some examples for using templates in managed files can be found in the - documentation for the :ref:`file state `, as well as the + documentation for the :mod:`file state `, as well as the :ref:`MooseFS example` below. diff --git a/doc/topics/tutorials/walkthrough.rst b/doc/topics/tutorials/walkthrough.rst index 4a7783e590d2..9f691c5cc08b 100644 --- a/doc/topics/tutorials/walkthrough.rst +++ b/doc/topics/tutorials/walkthrough.rst @@ -294,7 +294,7 @@ This will display a very large list of available functions and documentation on them. .. note:: - Module documentation is also available :ref:`on the web `. + Module documentation is also available :ref:`on the web `. These functions cover everything from shelling out to package management to manipulating database servers. They comprise a powerful system management API @@ -304,7 +304,7 @@ of Salt. .. note:: Salt comes with many plugin systems. The functions that are available via - the ``salt`` command are called :ref:`Execution Modules `. + the ``salt`` command are called :ref:`Execution Modules `. Helpful Functions to Know diff --git a/doc/topics/tutorials/walkthrough_macosx.rst b/doc/topics/tutorials/walkthrough_macosx.rst index af5a860d7c9d..93183d9dd484 100644 --- a/doc/topics/tutorials/walkthrough_macosx.rst +++ b/doc/topics/tutorials/walkthrough_macosx.rst @@ -7,14 +7,11 @@ The macOS (Maverick) Developer Step By Step Guide To Salt Installation This document provides a step-by-step guide to installing a Salt cluster consisting of one master, and one minion running on a local VM hosted on macOS. - .. note:: This guide is aimed at developers who wish to run Salt in a virtual machine. The official (Linux) walkthrough can be found `here `_. - - The 5 Cent Salt Intro --------------------- @@ -63,18 +60,19 @@ Here's a brief overview of a Salt cluster: that. - Before Digging In, The Architecture Of The Salt Cluster ------------------------------------------------------- Salt Master +++++++++++ + The "Salt master" server is going to be the Mac OS machine, directly. Commands will be run from a terminal app, so Salt will need to be installed on the Mac. This is going to be more convenient for toying around with configuration files. Salt Minion +++++++++++ + We'll only have one "Salt minion" server. It is going to be running on a Virtual Machine running on the Mac, using VirtualBox. It will run an Ubuntu distribution. @@ -194,6 +192,7 @@ There should be no errors when running the above command. Now that the master is set, let's configure a minion on a VM. + Step 2 - Configuring The Minion VM ================================== @@ -324,6 +323,7 @@ following: It's now time to connect the VM to the salt master + Step 3 - Connecting Master and Minion ===================================== @@ -369,7 +369,6 @@ Then copy the .pub file into the list of accepted minions: sudo cp minion1.pub /etc/salt/pki/master/minions/minion1 - Modify Vagrantfile to Use Salt Provisioner ------------------------------------------ @@ -415,6 +414,7 @@ following: You should see your minion answering the ping. It's now time to do some configuration. + Step 4 - Configure Services to Install On the Minion ==================================================== diff --git a/doc/topics/tutorials/writing_tests.rst b/doc/topics/tutorials/writing_tests.rst index 56cedddefb76..3583c26c172c 100644 --- a/doc/topics/tutorials/writing_tests.rst +++ b/doc/topics/tutorials/writing_tests.rst @@ -8,7 +8,7 @@ Salt's Test Suite: An Introduction This tutorial makes a couple of assumptions. The first assumption is that you have a basic knowledge of Salt. To get up to speed, check out the - :ref:`Salt Walkthrough `. + :ref:`Salt Walkthrough `. The second assumption is that your Salt development environment is already configured and that you have a basic understanding of contributing to the diff --git a/doc/topics/yaml/index.rst b/doc/topics/yaml/index.rst index 54600d1e2778..bd2a7767f6c3 100644 --- a/doc/topics/yaml/index.rst +++ b/doc/topics/yaml/index.rst @@ -78,7 +78,7 @@ And in Python: } Rule Three: Dashes -------------------- +------------------ To represent lists of items, a single dash followed by a space is used. Multiple items are a part of the same list as a function of their having the same level of indentation. @@ -115,5 +115,4 @@ One excellent choice for experimenting with YAML parsing is: http://yaml-online- Templating ---------- Jinja statements and expressions are allowed by default in SLS files. See -:ref:`Understanding Jinja `. - +:ref:`Understanding Jinja `. diff --git a/salt/auth/django.py b/salt/auth/django.py index 5962e3be1fab..ea8593c47bd5 100644 --- a/salt/auth/django.py +++ b/salt/auth/django.py @@ -50,12 +50,16 @@ class SaltExternalAuthModel(models.Model): # Import python libs from __future__ import absolute_import import logging +import os +import sys + # Import 3rd-party libs import salt.ext.six as six # pylint: disable=import-error try: import django + from django.db import connection HAS_DJANGO = True except Exception as exc: # If Django is installed and is not detected, uncomment @@ -77,10 +81,22 @@ def __virtual__(): return False +def is_connection_usable(): + try: + connection.connection.ping() + except Exception: + return False + else: + return True + + def django_auth_setup(): ''' Prepare the connection to the Django authentication framework ''' + if django.VERSION >= (1, 7): + django.setup() + global DJANGO_AUTH_CLASS if DJANGO_AUTH_CLASS is not None: @@ -95,21 +111,26 @@ def django_auth_setup(): django_model_name = django_model_fullname.split('.')[-1] django_module_name = '.'.join(django_model_fullname.split('.')[0:-1]) - __import__(django_module_name, globals(), locals(), 'SaltExternalAuthModel') + django_auth_module = __import__(django_module_name, globals(), locals(), 'SaltExternalAuthModel') DJANGO_AUTH_CLASS_str = 'django_auth_module.{0}'.format(django_model_name) DJANGO_AUTH_CLASS = eval(DJANGO_AUTH_CLASS_str) # pylint: disable=W0123 - if django.VERSION >= (1, 7): - django.setup() - def auth(username, password): ''' Simple Django auth ''' - import django.contrib.auth # pylint: disable=import-error + django_auth_path = __opts__['django_auth_path'] + if django_auth_path not in sys.path: + sys.path.append(django_auth_path) + os.environ.setdefault('DJANGO_SETTINGS_MODULE', __opts__['django_auth_settings']) django_auth_setup() + + if not is_connection_usable(): + connection.close() + + import django.contrib.auth # pylint: disable=import-error user = django.contrib.auth.authenticate(username=username, password=password) if user is not None: if user.is_active: diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index f16c6e0759a0..9decd7f9dcae 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -672,6 +672,12 @@ def _manage_devices(devices, vm=None, container_ref=None, new_vm_name=None): if device.capacityInKB < size_kb: # expand the disk disk_spec = _edit_existing_hard_disk_helper(device, size_kb) + elif device.capacityInKB > size_kb: + raise SaltCloudSystemExit( + 'The specified disk size is smaller than the ' + 'size of the disk image. It must be equal to ' + 'or greater than the disk image' + ) if 'mode' in devices['disk'][device.deviceInfo.label]: if devices['disk'][device.deviceInfo.label]['mode'] \ diff --git a/salt/config/__init__.py b/salt/config/__init__.py index fe8aabe1266f..1a40886f1118 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -995,6 +995,10 @@ def _gather_buffer_space(): # Whitelist specific modules to be synced 'extmod_whitelist': dict, + + # django auth + 'django_auth_path': str, + 'django_auth_settings': str, } # default configurations @@ -1533,6 +1537,8 @@ def _gather_buffer_space(): 'ssl': None, 'extmod_whitelist': {}, 'clean_dynamic_modules': True, + 'django_auth_path': '', + 'django_auth_settings': '', } diff --git a/salt/loader.py b/salt/loader.py index 1c44bbdb8603..72dd3a72142a 100644 --- a/salt/loader.py +++ b/salt/loader.py @@ -1476,7 +1476,10 @@ def _load_module(self, name): # It default's of course to the found callable attribute name # if no alias is defined. funcname = getattr(mod, '__func_alias__', {}).get(attr, attr) - full_funcname = '{0}.{1}'.format(module_name, funcname) + try: + full_funcname = '.'.join((module_name, funcname)) + except TypeError: + full_funcname = '{0}.{1}'.format(module_name, funcname) # Save many references for lookups # Careful not to overwrite existing (higher priority) functions if full_funcname not in self._dict: diff --git a/salt/master.py b/salt/master.py index 762f32de0f27..6c31d470247e 100644 --- a/salt/master.py +++ b/salt/master.py @@ -1917,7 +1917,7 @@ def mk_token(self, clear_load): name = self.loadauth.load_name(clear_load) groups = self.loadauth.get_groups(clear_load) eauth_config = self.opts['external_auth'][clear_load['eauth']] - if '*' not in eauth_config and name not in eauth_config: + if '^model' not in eauth_config and '*' not in eauth_config and name not in eauth_config: found = False for group in groups: if "{0}%".format(group) in eauth_config: @@ -2017,7 +2017,7 @@ def publish(self, clear_load): break except KeyError: pass - if '*' not in eauth_users and token['name'] not in eauth_users \ + if '^model' not in eauth_users and '*' not in eauth_users and token['name'] not in eauth_users \ and not group_auth_match: log.warning('Authentication failure of type "token" occurred.') return '' diff --git a/salt/modules/boto_ec2.py b/salt/modules/boto_ec2.py index ab5538851141..9cc7167487bf 100644 --- a/salt/modules/boto_ec2.py +++ b/salt/modules/boto_ec2.py @@ -614,8 +614,8 @@ def create_image(ami_name, instance_id=None, instance_name=None, tags=None, regi .. code-block:: bash - salt myminion boto_ec2.create_instance ami_name instance_name=myinstance - salt myminion boto_ec2.create_instance another_ami_name tags='{"mytag": "value"}' description='this is my ami' + salt myminion boto_ec2.create_image ami_name instance_name=myinstance + salt myminion boto_ec2.create_image another_ami_name tags='{"mytag": "value"}' description='this is my ami' ''' diff --git a/salt/modules/boto_rds.py b/salt/modules/boto_rds.py index bc3ac42625ba..227dc4e0fe5e 100644 --- a/salt/modules/boto_rds.py +++ b/salt/modules/boto_rds.py @@ -220,7 +220,10 @@ def subnet_group_exists(name, tags=None, region=None, key=None, keyid=None, rds = conn.describe_db_subnet_groups(DBSubnetGroupName=name) return {'exists': bool(rds)} except ClientError as e: - return {'error': salt.utils.boto3.get_error(e)} + if "DBSubnetGroupNotFoundFault" in e.message: + return {'exists': False} + else: + return {'error': salt.utils.boto3.get_error(e)} def create(name, allocated_storage, db_instance_class, engine, diff --git a/salt/modules/disk.py b/salt/modules/disk.py index c2f9c491e8fe..6926894bf5d4 100644 --- a/salt/modules/disk.py +++ b/salt/modules/disk.py @@ -75,9 +75,7 @@ def usage(args=None): return {} if __grains__['kernel'] == 'Linux': cmd = 'df -P' - elif __grains__['kernel'] == 'OpenBSD': - cmd = 'df -kP' - elif __grains__['kernel'] == 'AIX': + elif __grains__['kernel'] == 'OpenBSD' or __grains__['kernel'] == 'AIX': cmd = 'df -kP' else: cmd = 'df' @@ -141,7 +139,10 @@ def inodeusage(args=None): salt '*' disk.inodeusage ''' flags = _clean_flags(args, 'disk.inodeusage') - cmd = 'df -iP' + if __grains__['kernel'] == 'AIX': + cmd = 'df -i' + else: + cmd = 'df -iP' if flags: cmd += ' -{0}'.format(flags) ret = {} @@ -163,6 +164,14 @@ def inodeusage(args=None): 'use': comps[7], 'filesystem': comps[0], } + elif __grains__['kernel'] == 'AIX': + ret[comps[6]] = { + 'inodes': comps[4], + 'used': comps[5], + 'free': comps[2], + 'use': comps[5], + 'filesystem': comps[0], + } else: ret[comps[5]] = { 'inodes': comps[1], @@ -189,7 +198,7 @@ def percent(args=None): ''' if __grains__['kernel'] == 'Linux': cmd = 'df -P' - elif __grains__['kernel'] == 'OpenBSD': + elif __grains__['kernel'] == 'OpenBSD' or __grains__['kernel'] == 'AIX': cmd = 'df -kP' else: cmd = 'df' @@ -201,9 +210,11 @@ def percent(args=None): if line.startswith('Filesystem'): continue comps = line.split() - while not comps[1].isdigit(): + while len(comps) >= 2 and not comps[1].isdigit(): comps[0] = '{0} {1}'.format(comps[0], comps[1]) comps.pop(1) + if len(comps) < 2: + continue try: if __grains__['kernel'] == 'Darwin': ret[comps[8]] = comps[4] @@ -464,11 +475,18 @@ def fstype(device): if salt.utils.which('df'): # the fstype was not set on the block device, so inspect the filesystem # itself for its type - df_out = __salt__['cmd.run']('df -T {0}'.format(device)).splitlines() - if len(df_out) > 1: - fs_type = df_out[1] - if fs_type: - return fs_type + if __grains__['kernel'] == 'AIX' and os.path.isfile('/usr/sysv/bin/df'): + df_out = __salt__['cmd.run']('/usr/sysv/bin/df -n {0}'.format(device)).split() + if len(df_out) > 2: + fs_type = df_out[2] + if fs_type: + return fs_type + else: + df_out = __salt__['cmd.run']('df -T {0}'.format(device)).splitlines() + if len(df_out) > 1: + fs_type = df_out[1] + if fs_type: + return fs_type return '' diff --git a/salt/modules/dockerng.py b/salt/modules/dockerng.py index f049cb76f008..308f52f7aea8 100644 --- a/salt/modules/dockerng.py +++ b/salt/modules/dockerng.py @@ -1214,7 +1214,7 @@ def _error_detail(data, item): ''' err = item['errorDetail'] if 'code' in err: - msg = '{1}: {2}'.format( + msg = '{0}: {1}'.format( item['errorDetail']['code'], item['errorDetail']['message'], ) diff --git a/salt/modules/jenkins.py b/salt/modules/jenkins.py index b9228d2132c5..d327d09292b4 100644 --- a/salt/modules/jenkins.py +++ b/salt/modules/jenkins.py @@ -6,6 +6,11 @@ .. versionadded:: 2016.3.0 +:depends: python-jenkins_ Python module (not to be confused with jenkins_) + +.. _python-jenkins: https://pypi.python.org/pypi/python-jenkins +.. _jenkins: https://pypi.python.org/pypi/jenkins + :configuration: This module can be used by either passing an api key and version directly or by specifying both in a configuration profile in the salt master/minion config. @@ -47,9 +52,15 @@ def __virtual__(): :return: The virtual name of the module. ''' if HAS_JENKINS: - return __virtualname__ + if hasattr(jenkins, 'Jenkins'): + return __virtualname__ + else: + return (False, + 'The wrong Python module appears to be installed. Please ' + 'make sure that \'python-jenkins\' is installed, not ' + '\'jenkins\'.') return (False, 'The jenkins execution module cannot be loaded: ' - 'python jenkins library is not installed.') + 'python-jenkins is not installed.') def _connect(): diff --git a/salt/modules/mount.py b/salt/modules/mount.py index 79e9167900b8..6b2ad6e900ae 100644 --- a/salt/modules/mount.py +++ b/salt/modules/mount.py @@ -110,6 +110,27 @@ def _active_mounts(ret): return ret +def _active_mounts_aix(ret): + ''' + List active mounts on AIX systems + ''' + for line in __salt__['cmd.run_stdout']('mount -p').split('\n'): + comps = re.sub(r"\s+", " ", line).split() + if comps and comps[0] == 'node' or comps[0] == '--------': + continue + if len(comps) < 8: + ret[comps[1]] = {'device': comps[0], + 'fstype': comps[2], + 'opts': _resolve_user_group_names(comps[6].split(','))} + else: + ret[comps[2]] = {'node': comps[0], + 'device': comps[1], + 'fstype': comps[3], + 'opts': _resolve_user_group_names(comps[7].split(','))} + + return ret + + def _active_mounts_freebsd(ret): ''' List active mounts on FreeBSD systems @@ -202,6 +223,8 @@ def active(extended=False): ret = {} if __grains__['os'] == 'FreeBSD': _active_mounts_freebsd(ret) + elif __grains__['kernel'] == 'AIX': + _active_mounts_aix(ret) elif __grains__['kernel'] == 'SunOS': _active_mounts_solaris(ret) elif __grains__['os'] == 'OpenBSD': diff --git a/salt/modules/selinux.py b/salt/modules/selinux.py index d29faedf40a5..b51862ec3411 100644 --- a/salt/modules/selinux.py +++ b/salt/modules/selinux.py @@ -100,6 +100,27 @@ def getenforce(): return 'Disabled' +def getconfig(): + ''' + Return the selinux mode from the config file + + CLI Example: + + .. code-block:: bash + + salt '*' selinux.getconfig + ''' + try: + config = '/etc/selinux/config' + with salt.utils.fopen(config, 'r') as _fp: + for line in _fp: + if line.strip().startswith('SELINUX='): + return line.split('=')[1].capitalize().strip() + except (IOError, OSError, AttributeError): + return None + return None + + def setenforce(mode): ''' Set the SELinux enforcing mode diff --git a/salt/modules/snapper.py b/salt/modules/snapper.py index 318ce9b99da5..d5f1181743fc 100644 --- a/salt/modules/snapper.py +++ b/salt/modules/snapper.py @@ -290,6 +290,60 @@ def get_config(name='root'): ) +def create_config(name=None, + subvolume=None, + fstype=None, + template=None, + extra_opts=None): + ''' + Creates a new Snapper configuration + + name + Name of the new Snapper configuration. + subvolume + Path to the related subvolume. + fstype + Filesystem type of the subvolume. + template + Configuration template to use. (Default: default) + extra_opts + Extra Snapper configuration opts dictionary. It will override the values provided + by the given template (if any). + + CLI example: + + .. code-block:: bash + + salt '*' snapper.create_config name=myconfig subvolume=/foo/bar/ fstype=btrfs + salt '*' snapper.create_config name=myconfig subvolume=/foo/bar/ fstype=btrfs template="default" + salt '*' snapper.create_config name=myconfig subvolume=/foo/bar/ fstype=btrfs extra_opts='{"NUMBER_CLEANUP": False}' + ''' + def raise_arg_error(argname): + raise CommandExecutionError( + 'You must provide a "{0}" for the new configuration'.format(argname) + ) + + if not name: + raise_arg_error("name") + if not subvolume: + raise_arg_error("subvolume") + if not fstype: + raise_arg_error("fstype") + if not template: + template = "" + + try: + snapper.CreateConfig(name, subvolume, fstype, template) + if extra_opts: + set_config(name, **extra_opts) + return get_config(name) + except dbus.DBusException as exc: + raise CommandExecutionError( + 'Error encountered while creating the new configuration: {0}' + .format(_dbus_exception_to_reason(exc, locals())) + ) + + def create_snapshot(config='root', snapshot_type='single', pre_number=None, description=None, cleanup_algorithm='number', userdata=None, **kwargs): @@ -309,14 +363,14 @@ def create_snapshot(config='root', snapshot_type='single', pre_number=None, cleanup_algorithm Set the cleanup algorithm for the snapshot. - number - Deletes old snapshots when a certain number of snapshots - is reached. - timeline - Deletes old snapshots but keeps a number of hourly, - daily, weekly, monthly and yearly snapshots. - empty-pre-post - Deletes pre/post snapshot pairs with empty diffs. + number + Deletes old snapshots when a certain number of snapshots + is reached. + timeline + Deletes old snapshots but keeps a number of hourly, + daily, weekly, monthly and yearly snapshots. + empty-pre-post + Deletes pre/post snapshot pairs with empty diffs. userdata Set userdata for the snapshot (key-value pairs). @@ -364,6 +418,95 @@ def create_snapshot(config='root', snapshot_type='single', pre_number=None, return new_nr +def delete_snapshot(snapshots_ids=None, config="root"): + ''' + Deletes an snapshot + + config + Configuration name. (Default: root) + + snapshots_ids + List of the snapshots IDs to be deleted. + + CLI example: + + .. code-block:: bash + + salt '*' snapper.delete_snapshot 54 + salt '*' snapper.delete_snapshot config=root 54 + salt '*' snapper.delete_snapshot config=root snapshots_ids=[54,55,56] + ''' + if not snapshots_ids: + raise CommandExecutionError('Error: No snapshot ID has been provided') + try: + current_snapshots_ids = [x['id'] for x in list_snapshots(config)] + if not isinstance(snapshots_ids, list): + snapshots_ids = [snapshots_ids] + if not set(snapshots_ids).issubset(set(current_snapshots_ids)): + raise CommandExecutionError( + "Error: Snapshots '{0}' not found".format(", ".join( + [str(x) for x in set(snapshots_ids).difference( + set(current_snapshots_ids))])) + ) + snapper.DeleteSnapshots(config, snapshots_ids) + return {config: {"ids": snapshots_ids, "status": "deleted"}} + except dbus.DBusException as exc: + raise CommandExecutionError(_dbus_exception_to_reason(exc, locals())) + + +def modify_snapshot(snapshot_id=None, + description=None, + userdata=None, + cleanup=None, + config="root"): + ''' + Modify attributes of an existing snapshot. + + config + Configuration name. (Default: root) + + snapshot_id + ID of the snapshot to be modified. + + cleanup + Change the cleanup method of the snapshot. (str) + + description + Change the description of the snapshot. (str) + + userdata + Change the userdata dictionary of the snapshot. (dict) + + CLI example: + + .. code-block:: bash + + salt '*' snapper.modify_snapshot 54 description="my snapshot description" + salt '*' snapper.modify_snapshot 54 description="my snapshot description" + salt '*' snapper.modify_snapshot 54 userdata='{"foo": "bar"}' + salt '*' snapper.modify_snapshot snapshot_id=54 cleanup="number" + ''' + if not snapshot_id: + raise CommandExecutionError('Error: No snapshot ID has been provided') + + snapshot = get_snapshot(config=config, number=snapshot_id) + try: + # Updating only the explicitely provided attributes by the user + updated_opts = { + 'description': description if description is not None else snapshot['description'], + 'cleanup': cleanup if cleanup is not None else snapshot['cleanup'], + 'userdata': userdata if userdata is not None else snapshot['userdata'], + } + snapper.SetSnapshot(config, + snapshot_id, + updated_opts['description'], + updated_opts['cleanup'], + updated_opts['userdata']) + return get_snapshot(config=config, number=snapshot_id) + except dbus.DBusException as exc: + raise CommandExecutionError(_dbus_exception_to_reason(exc, locals())) + + def _get_num_interval(config, num_pre, num_post): ''' Returns numerical interval based on optionals num_pre, num_post values diff --git a/salt/modules/solaris_user.py b/salt/modules/solaris_user.py index 67adc8a5e7f0..f135d1dcf4f1 100644 --- a/salt/modules/solaris_user.py +++ b/salt/modules/solaris_user.py @@ -3,10 +3,12 @@ Manage users with the useradd command .. important:: + If you feel that Salt should be using this module to manage users on a minion, and it is using a different module (or gives an error similar to *'user.info' is not available*), see :ref:`here `. + ''' # Import python libs diff --git a/salt/modules/win_ip.py b/salt/modules/win_ip.py index 4729099b5c1f..dc7416b78eb5 100644 --- a/salt/modules/win_ip.py +++ b/salt/modules/win_ip.py @@ -6,7 +6,6 @@ # Import python libs import logging -import socket import time # Import salt libs @@ -41,62 +40,53 @@ def _interface_configs(): ''' cmd = ['netsh', 'interface', 'ip', 'show', 'config'] lines = __salt__['cmd.run'](cmd, python_shell=False).splitlines() - iface = '' - ip = 0 - dns_flag = None - wins_flag = None ret = {} + current_iface = None + current_ip_list = None + for line in lines: - if dns_flag: - try: - socket.inet_aton(line.strip()) - ret[iface][dns_flag].append(line.strip()) - dns_flag = None - continue - except socket.error as exc: - dns_flag = None - if wins_flag: - try: - socket.inet_aton(line.strip()) - ret[iface][wins_flag].append(line.strip()) - wins_flag = None - continue - except socket.error as exc: - wins_flag = None + + line = line.strip() if not line: - iface = '' + current_iface = None + current_ip_list = None continue + if 'Configuration for interface' in line: _, iface = line.rstrip('"').split('"', 1) # get iface name - ret[iface] = {} - ip = 0 - continue - try: - key, val = line.split(':', 1) - except ValueError as exc: - log.debug('Could not split line. Error was {0}.'.format(exc)) - continue - if 'DNS Servers' in line: - dns_flag = key.strip() - ret[iface][key.strip()] = [val.strip()] - continue - if 'WINS Servers' in line: - wins_flag = key.strip() - ret[iface][key.strip()] = [val.strip()] - continue - if 'IP Address' in key: - if 'ip_addrs' not in ret[iface]: - ret[iface]['ip_addrs'] = [] - ret[iface]['ip_addrs'].append(dict([(key.strip(), val.strip())])) + current_iface = {} + ret[iface] = current_iface continue - if 'Subnet Prefix' in key: - subnet, _, netmask = val.strip().split(' ', 2) - ret[iface]['ip_addrs'][ip]['Subnet'] = subnet.strip() - ret[iface]['ip_addrs'][ip]['Netmask'] = netmask.lstrip().rstrip(')') - ip = ip + 1 + + if ':' not in line: + if current_ip_list: + current_ip_list.append(line) + else: + log.warning('Cannot parse "{0}"'.format(line)) continue + + key, val = line.split(':', 1) + key = key.strip() + val = val.strip() + + lkey = key.lower() + if ('dns servers' in lkey) or ('wins servers' in lkey): + current_ip_list = [] + current_iface[key] = current_ip_list + current_ip_list.append(val) + + elif 'ip address' in lkey: + current_iface.setdefault('ip_addrs', []).append({key: val}) + + elif 'subnet prefix' in lkey: + subnet, _, netmask = val.split(' ', 2) + last_ip = current_iface['ip_addrs'][-1] + last_ip['Subnet'] = subnet.strip() + last_ip['Netmask'] = netmask.lstrip().rstrip(')') + else: - ret[iface][key.strip()] = val.strip() + current_iface[key] = val + return ret diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index 395e050e44b3..431a6df08132 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -1026,6 +1026,18 @@ def __init__(self): 'value_lookup': True, }, }, + 'Transform': { + 'Get': '_dict_lookup', + 'Put': '_dict_lookup', + 'GetArgs': { + 'lookup': self.smb_server_name_hardening_levels, + 'value_lookup': False, + }, + 'PutArgs': { + 'lookup': self.smb_server_name_hardening_levels, + 'value_lookup': True, + }, + } }, 'EnableInstallerDetection': { 'Policy': 'User Account Control: Detect application ' @@ -2478,6 +2490,7 @@ def _in_range_inclusive(cls, val, **kwargs): ''' minimum = 0 maximum = 1 + if isinstance(val, string_types): if val.lower() == 'not defined': return True diff --git a/salt/modules/x509.py b/salt/modules/x509.py index e8550c160587..0c491ee27561 100644 --- a/salt/modules/x509.py +++ b/salt/modules/x509.py @@ -850,6 +850,7 @@ def create_private_key(path=None, def create_crl( # pylint: disable=too-many-arguments,too-many-locals path=None, text=False, signing_private_key=None, + signing_private_key_passphrase=None, signing_cert=None, revoked=None, include_expired=False, days_valid=100, digest=''): ''' @@ -868,6 +869,9 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals A path or string of the private key in PEM format that will be used to sign this crl. This is required. + signing_private_key_passphrase: + Passphrase to decrypt the private key. + signing_cert: A certificate matching the private key that will be used to sign this crl. This is required. @@ -971,7 +975,8 @@ def create_crl( # pylint: disable=too-many-arguments,too-many-locals cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, get_pem_entry(signing_cert, pem_type='CERTIFICATE')) - signing_private_key = _text_or_file(signing_private_key) + signing_private_key = _get_private_key_obj(signing_private_key, + passphrase=signing_private_key_passphrase).as_pem(cipher=None) key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, get_pem_entry(signing_private_key)) @@ -1586,8 +1591,17 @@ def create_csr(path=None, text=False, **kwargs): if 'public_key' not in kwargs: kwargs['public_key'] = kwargs['private_key'] + if 'private_key_passphrase' not in kwargs: + kwargs['private_key_passphrase'] = None if 'public_key_passphrase' not in kwargs: kwargs['public_key_passphrase'] = None + if kwargs['public_key_passphrase'] and not kwargs[ + 'private_key_passphrase']: + kwargs['private_key_passphrase'] = kwargs['public_key_passphrase'] + if kwargs['private_key_passphrase'] and not kwargs[ + 'public_key_passphrase']: + kwargs['public_key_passphrase'] = kwargs['private_key_passphrase'] + csr.set_pubkey(get_public_key(kwargs['public_key'], passphrase=kwargs['public_key_passphrase'], asObj=True)) @@ -1609,6 +1623,9 @@ def create_csr(path=None, text=False, **kwargs): critical = True extval = extval[9:] + if extname == 'subjectKeyIdentifier' and 'hash' in extval: + extval = extval.replace('hash', _get_pubkey_hash(csr)) + if extname == 'subjectAltName': extval = extval.replace('IP Address', 'IP') @@ -1628,7 +1645,7 @@ def create_csr(path=None, text=False, **kwargs): csr.add_extensions(extstack) csr.sign(_get_private_key_obj(kwargs['private_key'], - passphrase=kwargs['public_key_passphrase']), kwargs['algorithm']) + passphrase=kwargs['private_key_passphrase']), kwargs['algorithm']) if path: return write_pem( diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 91f9c2eb0326..f21ee6e3d34a 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -2503,18 +2503,12 @@ def mod_repo(repo, basedir=None, **kwargs): ) # Build a list of keys to be deleted - todelete = ['disabled'] + todelete = [] for key in repo_opts: if repo_opts[key] != 0 and not repo_opts[key]: del repo_opts[key] todelete.append(key) - # convert disabled to enabled respectively from pkgrepo state - if 'enabled' not in repo_opts: - repo_opts['enabled'] = int(str(repo_opts.pop('disabled', False)).lower() != 'true') - else: - repo_opts.pop('disabled', False) - # Add baseurl or mirrorlist to the 'todelete' list if the other was # specified in the repo_opts if 'mirrorlist' in repo_opts: @@ -2586,6 +2580,7 @@ def mod_repo(repo, basedir=None, **kwargs): if key in six.iterkeys(filerepos[repo].copy()): del filerepos[repo][key] + _bool_to_str = lambda x: '1' if x else '0' # Old file or new, write out the repos(s) filerepos[repo].update(repo_opts) content = header @@ -2596,7 +2591,12 @@ def mod_repo(repo, basedir=None, **kwargs): del filerepos[stanza]['comments'] content += '\n[{0}]'.format(stanza) for line in six.iterkeys(filerepos[stanza]): - content += '\n{0}={1}'.format(line, filerepos[stanza][line]) + content += '\n{0}={1}'.format( + line, + filerepos[stanza][line] + if not isinstance(filerepos[stanza][line], bool) + else _bool_to_str(filerepos[stanza][line]) + ) content += '\n{0}\n'.format(comments) with salt.utils.fopen(repofile, 'w') as fileout: @@ -2642,9 +2642,6 @@ def _parse_repo_file(filename): 'Failed to parse line in %s, offending line was ' '\'%s\'', filename, line.rstrip() ) - # YUM uses enabled field - create the disabled field so that comparisons works correctly in state - if comps[0].strip() == 'enabled': - repos[repo]['disabled'] = comps[1] != "1" return (header, repos) diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index 5c5e0277ddef..70acfc7d1e4a 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -1686,16 +1686,19 @@ def POST(self, **kwargs): try: eauth = self.opts.get('external_auth', {}).get(token['eauth'], {}) - # Get sum of '*' perms, user-specific perms, and group-specific perms - perms = eauth.get(token['name'], []) - perms.extend(eauth.get('*', [])) + if token['eauth'] == 'django' and '^model' in eauth: + perms = token['auth_list'] + else: + # Get sum of '*' perms, user-specific perms, and group-specific perms + perms = eauth.get(token['name'], []) + perms.extend(eauth.get('*', [])) - if 'groups' in token and token['groups']: - user_groups = set(token['groups']) - eauth_groups = set([i.rstrip('%') for i in eauth.keys() if i.endswith('%')]) + if 'groups' in token and token['groups']: + user_groups = set(token['groups']) + eauth_groups = set([i.rstrip('%') for i in eauth.keys() if i.endswith('%')]) - for group in user_groups & eauth_groups: - perms.extend(eauth['{0}%'.format(group)]) + for group in user_groups & eauth_groups: + perms.extend(eauth['{0}%'.format(group)]) if not perms: logger.debug("Eauth permission list not found.") diff --git a/salt/output/highstate.py b/salt/output/highstate.py index 72daca5210af..013a750800f8 100644 --- a/salt/output/highstate.py +++ b/salt/output/highstate.py @@ -190,7 +190,7 @@ def _format_host(host, data): # Verify that the needed data is present data_tmp = {} for tname, info in six.iteritems(data): - if isinstance(info, dict) and tname is not 'changes' and '__run_num__' not in info: + if isinstance(info, dict) and tname is not 'changes' and info and '__run_num__' not in info: err = (u'The State execution failed to record the order ' 'in which all states were executed. The state ' 'return missing data is:') diff --git a/salt/pillar/git_pillar.py b/salt/pillar/git_pillar.py index c0c7b7d0bb90..86b770bf680e 100644 --- a/salt/pillar/git_pillar.py +++ b/salt/pillar/git_pillar.py @@ -56,6 +56,10 @@ Configuring git_pillar for Salt releases before 2015.8.0 ======================================================== +.. note:: + This legacy configuration for git_pillar will no longer be supported as of + the **Oxygen** release of Salt. + For Salt releases earlier than :ref:`2015.8.0 `, GitPython is the only supported provider for git_pillar. Individual repositories can be configured under the :conf_master:`ext_pillar` @@ -540,6 +544,14 @@ def _legacy_git_pillar(minion_id, repo_string, pillar_dirs): ''' Support pre-Beryllium config schema ''' + salt.utils.warn_until( + 'Oxygen', + 'The git ext_pillar configuration is deprecated. Please refer to the ' + 'documentation at ' + 'https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.git_pillar.html ' + 'for more information. This configuration will no longer be supported ' + 'as of the Oxygen release of Salt.' + ) if pillar_dirs is None: return # split the branch, repo name and optional extra (key=val) parameters. diff --git a/salt/pillar/s3.py b/salt/pillar/s3.py index 554eaff930dd..807d4fe321de 100644 --- a/salt/pillar/s3.py +++ b/salt/pillar/s3.py @@ -184,7 +184,7 @@ def ext_pillar(minion_id, pil = Pillar(opts, __grains__, minion_id, environment) - compiled_pillar = pil.compile_pillar() + compiled_pillar = pil.compile_pillar(ext=False) return compiled_pillar diff --git a/salt/pillar/svn_pillar.py b/salt/pillar/svn_pillar.py index 7be9ad9407e4..01f1fb0c1e9a 100644 --- a/salt/pillar/svn_pillar.py +++ b/salt/pillar/svn_pillar.py @@ -193,4 +193,4 @@ def ext_pillar(minion_id, opts = deepcopy(__opts__) opts['pillar_roots'][branch] = [pillar_dir] pil = Pillar(opts, __grains__, minion_id, branch) - return pil.compile_pillar() + return pil.compile_pillar(ext=False) diff --git a/salt/renderers/jinja.py b/salt/renderers/jinja.py index 0bab045a0e25..24f19b0d2489 100644 --- a/salt/renderers/jinja.py +++ b/salt/renderers/jinja.py @@ -2,7 +2,7 @@ ''' Jinja loading utils to enable a more powerful backend for jinja templates -For Jinja usage information see :ref:`Understanding Jinja `. +For Jinja usage information see :ref:`Understanding Jinja `. ''' # Import python libs diff --git a/salt/returners/postgres.py b/salt/returners/postgres.py index bec3d926fbe7..a2642b70f5ad 100644 --- a/salt/returners/postgres.py +++ b/salt/returners/postgres.py @@ -5,7 +5,7 @@ .. note:: :mod:`returners.postgres_local_cache ` is recommended instead of this module when using PostgreSQL as a - :ref:`master job cache `. These two modules + :ref:`master job cache `. These two modules provide different functionality so you should compare each to see which module best suits your particular needs. diff --git a/salt/returners/postgres_local_cache.py b/salt/returners/postgres_local_cache.py index 9397c355f9d0..ff33965f6662 100644 --- a/salt/returners/postgres_local_cache.py +++ b/salt/returners/postgres_local_cache.py @@ -6,7 +6,7 @@ .. note:: :mod:`returners.postgres ` is also available if you are not using PostgreSQL as a :ref:`master job cache - `. These two modules provide different + `. These two modules provide different functionality so you should compare each to see which module best suits your particular needs. diff --git a/salt/runners/fileserver.py b/salt/runners/fileserver.py index c5c416ddc08e..6322aa78427d 100644 --- a/salt/runners/fileserver.py +++ b/salt/runners/fileserver.py @@ -36,7 +36,7 @@ def envs(backend=None, sources=False): salt-run fileserver.envs git ''' fileserver = salt.fileserver.Fileserver(__opts__) - return fileserver.envs(back=backend, sources=sources) + return sorted(fileserver.envs(back=backend, sources=sources)) def clear_file_list_cache(saltenv=None, backend=None): diff --git a/salt/runners/salt.py b/salt/runners/salt.py index f8d47455dbf2..b37d2e95fd7a 100644 --- a/salt/runners/salt.py +++ b/salt/runners/salt.py @@ -7,14 +7,14 @@ on the salt master. .. _salt_salt_runner: + Salt's execution modules are normally available on the salt minion. Use this runner to call execution modules on the salt master. Salt :ref:`execution modules ` are the functions called by the ``salt`` command. -Execution modules can be -called with ``salt-run``: +Execution modules can be called with ``salt-run``: .. code-block:: bash @@ -45,7 +45,7 @@ def cmd(fun, *args, **kwargs): ''' Execute ``fun`` with the given ``args`` and ``kwargs``. - Parameter ``fun`` should be the string :ref:`name ` + Parameter ``fun`` should be the string :ref:`name ` of the execution module to call. Note that execution modules will be *loaded every time* diff --git a/salt/states/boto_apigateway.py b/salt/states/boto_apigateway.py index fb20e181de22..b6fde1db7fd0 100644 --- a/salt/states/boto_apigateway.py +++ b/salt/states/boto_apigateway.py @@ -31,18 +31,18 @@ .. code-block:: yaml myprofile: - keyid: GKTADJGHEIQSXMKKRBJ08H - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs - region: us-east-1 + keyid: GKTADJGHEIQSXMKKRBJ08H + key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs + region: us-east-1 .. code-block:: yaml Ensure Apigateway API exists: - boto_apigateway.present: - - name: myfunction - - region: us-east-1 - - keyid: GKTADJGHEIQSXMKKRBJ08H - - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs + boto_apigateway.present: + - name: myfunction + - region: us-east-1 + - keyid: GKTADJGHEIQSXMKKRBJ08H + - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs ''' diff --git a/salt/states/boto_rds.py b/salt/states/boto_rds.py index b6b5509eaf90..039944500bf9 100644 --- a/salt/states/boto_rds.py +++ b/salt/states/boto_rds.py @@ -485,21 +485,17 @@ def subnet_group_present(name, description, subnet_ids=None, subnet_names=None, exists = __salt__['boto_rds.subnet_group_exists'](name=name, tags=tags, region=region, key=key, keyid=keyid, profile=profile) - if not exists: + if not exists.get('exists'): if __opts__['test']: ret['comment'] = 'Subnet group {0} is set to be created.'.format(name) ret['result'] = None return ret - if not r.get('created'): - ret['result'] = False - ret['comment'] = 'Failed to create {0} subnet group.'.format(r['error']['message']) - return ret created = __salt__['boto_rds.create_subnet_group'](name=name, - description=description, - subnet_ids=subnet_ids, - tags=tags, region=region, - key=key, keyid=keyid, - profile=profile) + description=description, + subnet_ids=subnet_ids, + tags=tags, region=region, + key=key, keyid=keyid, + profile=profile) if not created: ret['result'] = False @@ -508,6 +504,7 @@ def subnet_group_present(name, description, subnet_ids=None, subnet_names=None, ret['changes']['old'] = None ret['changes']['new'] = name ret['comment'] = 'Subnet {0} created.'.format(name) + return ret else: ret['comment'] = 'Subnet {0} present.'.format(name) @@ -668,7 +665,7 @@ def parameter_present(name, db_parameter_group_family, description, parameters=N 'changes': {} } res = __salt__['boto_rds.parameter_group_exists'](name=name, tags=tags, region=region, key=key, - keyid=keyid, profile=profile) + keyid=keyid, profile=profile) if not res.get('exists'): if __opts__['test']: ret['comment'] = 'Parameter group {0} is set to be created.'.format(name) diff --git a/salt/states/cmd.py b/salt/states/cmd.py index 990448e289c3..96002388c5f1 100644 --- a/salt/states/cmd.py +++ b/salt/states/cmd.py @@ -589,7 +589,7 @@ def wait_script(name, **no**, **on**, **off**, **true**, and **false** are all loaded as boolean ``True`` and ``False`` values, and must be enclosed in quotes to be used as strings. More info on this (and other) PyYAML - idiosyncrasies can be found :ref:`here `. + idiosyncrasies can be found :ref:`here `. Variables as values are not evaluated. So $PATH in the following example is a literal '$PATH': diff --git a/salt/states/mount.py b/salt/states/mount.py index 6435d9f1613b..d8176399e462 100644 --- a/salt/states/mount.py +++ b/salt/states/mount.py @@ -427,18 +427,19 @@ def mounted(name, opts.remove('remount') if real_device not in device_list: # name matches but device doesn't - need to umount - _device_mismatch_is_ignored = False + _device_mismatch_is_ignored = None for regex in list(device_name_regex): for _device in device_list: if re.match(regex, _device): _device_mismatch_is_ignored = _device + break if __opts__['test']: ret['result'] = None ret['comment'] = "An umount would have been forced " \ + "because devices do not match. Watched: " \ + device - elif _device_mismatch_is_ignored is True: - ret['result'] = None + elif _device_mismatch_is_ignored: + ret['result'] = True ret['comment'] = "An umount will not be forced " \ + "because device matched device_name_regex: " \ + _device_mismatch_is_ignored diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py index 37ce64cef2dd..5f8a85ad4c16 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py @@ -110,7 +110,7 @@ def managed(name, ppa=None, **kwargs): `, :mod:`apt `, and :mod:`zypper ` repositories are supported. - **YUM OR ZYPPER-BASED SYSTEMS** + **YUM/DNF/ZYPPER-BASED SYSTEMS** .. note:: One of ``baseurl`` or ``mirrorlist`` below is required. Additionally, @@ -124,6 +124,16 @@ def managed(name, ppa=None, **kwargs): repo. Secondly, it will be the name of the file as stored in /etc/yum.repos.d (e.g. ``/etc/yum.repos.d/foo.conf``). + enabled : True + Whether or not the repo is enabled. Can be specified as True/False or + 1/0. + + disabled : False + Included to reduce confusion due to APT's use of the ``disabled`` + argument. If this is passed for a yum/dnf/zypper-based distro, then the + reverse will be passed as ``enabled``. For example passing + ``disabled=True`` will assume ``enabled=False``. + humanname This is used as the "name" value in the repo file in ``/etc/yum.repos.d/`` (or ``/etc/zypp/repos.d`` for SUSE distros). @@ -201,10 +211,16 @@ def managed(name, ppa=None, **kwargs): 'deb http://us.archive.ubuntu.com/ubuntu precise main': pkgrepo.managed - disabled + disabled : False Toggles whether or not the repo is used for resolving dependencies and/or installing packages. + enabled : True + Included to reduce confusion due to yum/dnf/zypper's use of the + ``enabled`` argument. If this is passed for an APT-based distro, then + the reverse will be passed as ``disabled``. For example, passing + ``enabled=False`` will assume ``disabled=False``. + comps On apt-based systems, comps dictate the types of packages to be installed from the repository (e.g. main, nonfree, ...). For @@ -279,14 +295,19 @@ def managed(name, ppa=None, **kwargs): 'intended.') return ret - if 'enabled' in kwargs: - salt.utils.warn_until( - 'Nitrogen', - 'The `enabled` argument has been deprecated in favor of ' - '`disabled`.' - ) + enabled = kwargs.pop('enabled', None) + disabled = kwargs.pop('disabled', None) + + if enabled is not None and disabled is not None: + ret['result'] = False + ret['comment'] = 'Only one of enabled/disabled is allowed' + return ret + elif enabled is None and disabled is None: + # If neither argument was passed we assume the repo will be enabled + enabled = True repo = name + os_family = __grains__['os_family'].lower() if __grains__['os'] in ('Ubuntu', 'Mint'): if ppa is not None: # overload the name/repo value for PPAs cleanly @@ -296,26 +317,26 @@ def managed(name, ppa=None, **kwargs): except TypeError: repo = ':'.join(('ppa', str(ppa))) - elif __grains__['os_family'].lower() in ('redhat', 'suse'): + kwargs['disabled'] = not salt.utils.is_true(enabled) \ + if enabled is not None \ + else salt.utils.is_true(disabled) + + elif os_family in ('redhat', 'suse'): if 'humanname' in kwargs: kwargs['name'] = kwargs.pop('humanname') - _val = lambda x: '1' if salt.utils.is_true(x) else '0' - if 'disabled' in kwargs: - if 'enabled' in kwargs: - ret['result'] = False - ret['comment'] = 'Only one of enabled/disabled is permitted' - return ret - _reverse = lambda x: '1' if x == '0' else '0' - kwargs['enabled'] = _reverse(_val(kwargs.pop('disabled'))) - elif 'enabled' in kwargs: - kwargs['enabled'] = _val(kwargs['enabled']) if 'name' not in kwargs: # Fall back to the repo name if humanname not provided kwargs['name'] = repo - # Replace 'enabled' from kwargs with 'disabled' - enabled = kwargs.pop('enabled', True) - kwargs['disabled'] = not salt.utils.is_true(enabled) + kwargs['enabled'] = not salt.utils.is_true(disabled) \ + if disabled is not None \ + else salt.utils.is_true(enabled) + + elif os_family == 'nilinuxrt': + # opkg is the pkg virtual + kwargs['enabled'] = not salt.utils.is_true(disabled) \ + if disabled is not None \ + else salt.utils.is_true(enabled) for kwarg in _STATE_INTERNAL_KEYWORDS: kwargs.pop(kwarg, None) @@ -340,11 +361,10 @@ def managed(name, ppa=None, **kwargs): else: sanitizedkwargs = kwargs - if __grains__['os_family'] == 'Debian': + if os_family == 'debian': repo = _strip_uri(repo) if pre: - needs_update = False for kwarg in sanitizedkwargs: if kwarg not in pre: if kwarg == 'enabled': @@ -352,33 +372,40 @@ def managed(name, ppa=None, **kwargs): # not explicitly set, so we don't need to update the repo # if it's desired to be enabled and the 'enabled' key is # missing from the repo definition - if __grains__['os_family'] == 'RedHat': + if os_family == 'redhat': if not salt.utils.is_true(sanitizedkwargs[kwarg]): - needs_update = True + break else: - needs_update = True + break else: - needs_update = True + break elif kwarg == 'comps': if sorted(sanitizedkwargs[kwarg]) != sorted(pre[kwarg]): - needs_update = True - elif kwarg == 'line' and __grains__['os_family'] == 'Debian': + break + elif kwarg == 'line' and os_family == 'debian': # split the line and sort everything after the URL sanitizedsplit = sanitizedkwargs[kwarg].split() sanitizedsplit[3:] = sorted(sanitizedsplit[3:]) reposplit = pre[kwarg].split() reposplit[3:] = sorted(reposplit[3:]) if sanitizedsplit != reposplit: - needs_update = True + break if 'comments' in kwargs: _line = pre[kwarg].split('#') if str(kwargs['comments']) not in _line: - needs_update = True + break else: - if str(sanitizedkwargs[kwarg]) != str(pre[kwarg]): - needs_update = True - - if not needs_update: + if os_family in ('redhat', 'suse') \ + and any(isinstance(x, bool) for x in + (sanitizedkwargs[kwarg], pre[kwarg])): + # This check disambiguates 1/0 from True/False + if salt.utils.is_true(sanitizedkwargs[kwarg]) != \ + salt.utils.is_true(pre[kwarg]): + break + else: + if str(sanitizedkwargs[kwarg]) != str(pre[kwarg]): + break + else: ret['result'] = True ret['comment'] = ('Package repo \'{0}\' already configured' .format(name)) @@ -399,7 +426,7 @@ def managed(name, ppa=None, **kwargs): pass try: - if __grains__['os_family'] == 'Debian': + if os_family == 'debian': __salt__['pkg.mod_repo'](repo, saltenv=__env__, **kwargs) else: __salt__['pkg.mod_repo'](repo, **kwargs) diff --git a/salt/states/selinux.py b/salt/states/selinux.py index c663a38746a4..08f6f5eae50e 100644 --- a/salt/states/selinux.py +++ b/salt/states/selinux.py @@ -94,7 +94,14 @@ def mode(name): if tmode == 'unknown': ret['comment'] = '{0} is not an accepted mode'.format(name) return ret + # Either the current mode in memory or a non-matching config value + # will trigger setenforce mode = __salt__['selinux.getenforce']() + config = __salt__['selinux.getconfig']() + # Just making sure the oldmode reflects the thing that didn't match tmode + if mode == tmode and mode != config and tmode != config: + mode = config + if mode == tmode: ret['result'] = True ret['comment'] = 'SELinux is already in {0} mode'.format(tmode) @@ -109,7 +116,7 @@ def mode(name): return ret oldmode, mode = mode, __salt__['selinux.setenforce'](tmode) - if mode == tmode: + if mode == tmode or (tmode == 'Disabled' and __salt__['selinux.getconfig']() == tmode): ret['result'] = True ret['comment'] = 'SELinux has been set to {0} mode'.format(tmode) ret['changes'] = {'old': oldmode, diff --git a/salt/states/x509.py b/salt/states/x509.py index 1c63604e5682..bcd08972b7dd 100644 --- a/salt/states/x509.py +++ b/salt/states/x509.py @@ -168,6 +168,11 @@ # Import 3rd-party libs import salt.ext.six as six +try: + from M2Crypto.RSA import RSAError +except ImportError: + pass + def __virtual__(): ''' @@ -221,7 +226,8 @@ def _get_file_args(name, **kwargs): return file_args, extra_args -def _check_private_key(name, bits=2048, passphrase=None, new=False): +def _check_private_key(name, bits=2048, passphrase=None, + new=False, overwrite=False): current_bits = 0 if os.path.isfile(name): try: @@ -229,6 +235,10 @@ def _check_private_key(name, bits=2048, passphrase=None, new=False): private_key=name, passphrase=passphrase) except salt.exceptions.SaltInvocationError: pass + except RSAError: + if not overwrite: + raise salt.exceptions.CommandExecutionError( + 'The provided passphrase cannot decrypt the private key.') return current_bits == bits and not new @@ -238,6 +248,7 @@ def private_key_managed(name, passphrase=None, cipher='aes_128_cbc', new=False, + overwrite=False, verbose=True, **kwargs): ''' @@ -259,6 +270,9 @@ def private_key_managed(name, Always create a new key. Defaults to False. Combining new with :mod:`prereq `, or when used as part of a `managed_private_key` can allow key rotation whenever a new certificiate is generated. + overwrite: + Overwrite an existing private key if the provided passphrase cannot decrypt it. + verbose: Provide visual feedback on stdout, dots while key is generated. Default is True. @@ -286,7 +300,8 @@ def private_key_managed(name, ''' file_args, kwargs = _get_file_args(name, **kwargs) new_key = False - if _check_private_key(name, bits, passphrase, new): + if _check_private_key( + name, bits=bits, passphrase=passphrase, new=new, overwrite=overwrite): file_args['contents'] = __salt__['x509.get_pem_entry']( name, pem_type='RSA PRIVATE KEY') else: @@ -329,7 +344,11 @@ def csr_managed(name, - L: Salt Lake City - keyUsage: 'critical dataEncipherment' ''' - old = __salt__['x509.read_csr'](name) + try: + old = __salt__['x509.read_csr'](name) + except salt.exceptions.SaltInvocationError: + old = '{0} is not a valid csr.'.format(name) + file_args, kwargs = _get_file_args(name, **kwargs) file_args['contents'] = __salt__['x509.create_csr'](text=True, **kwargs) @@ -410,6 +429,7 @@ def certificate_managed(name, private_key_args = { 'name': name, 'new': False, + 'overwrite': False, 'bits': 2048, 'passphrase': None, 'cipher': 'aes_128_cbc', @@ -423,9 +443,10 @@ def certificate_managed(name, private_key_args['new'] = False if _check_private_key(private_key_args['name'], - private_key_args['bits'], - private_key_args['passphrase'], - private_key_args['new']): + bits=private_key_args['bits'], + passphrase=private_key_args['passphrase'], + new=private_key_args['new'], + overwrite=private_key_args['overwrite']): private_key = __salt__['x509.get_pem_entry']( private_key_args['name'], pem_type='RSA PRIVATE KEY') else: @@ -551,6 +572,7 @@ def certificate_managed(name, def crl_managed(name, signing_private_key, + signing_private_key_passphrase=None, signing_cert=None, revoked=None, days_valid=100, @@ -568,6 +590,9 @@ def crl_managed(name, The private key that will be used to sign this crl. This is usually your CA's private key. + signing_private_key_passphrase: + Passphrase to decrypt the private key. + signing_cert: The certificate of the authority that will be used to sign this crl. This is usually your CA's certificate. @@ -637,7 +662,7 @@ def crl_managed(name, else: current = '{0} does not exist.'.format(name) - new_crl = __salt__['x509.create_crl'](text=True, signing_private_key=signing_private_key, + new_crl = __salt__['x509.create_crl'](text=True, signing_private_key=signing_private_key, signing_private_key_passphrase=signing_private_key_passphrase, signing_cert=signing_cert, revoked=revoked, days_valid=days_valid, digest=digest, include_expired=include_expired) new = __salt__['x509.read_crl'](crl=new_crl) diff --git a/salt/utils/master.py b/salt/utils/master.py index 1ca2cd96e3f7..fe240700b40e 100644 --- a/salt/utils/master.py +++ b/salt/utils/master.py @@ -121,7 +121,8 @@ def _get_cached_mine_data(self, *minion_ids): log.debug('Skipping cached mine data minion_data_cache' 'and enfore_mine_cache are both disabled.') return mine_data - minion_ids = self.cache.list('minions') + if not minion_ids: + minion_ids = self.cache.list('minions') for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue @@ -139,7 +140,8 @@ def _get_cached_minion_data(self, *minion_ids): log.debug('Skipping cached data because minion_data_cache is not ' 'enabled.') return grains, pillars - minion_ids = self.cache.list('minions') + if not minion_ids: + minion_ids = self.cache.list('minions') for minion_id in minion_ids: if not salt.utils.verify.valid_id(self.opts, minion_id): continue diff --git a/salt/utils/minion.py b/salt/utils/minion.py index 2888f69f8487..690c3766001d 100644 --- a/salt/utils/minion.py +++ b/salt/utils/minion.py @@ -101,7 +101,7 @@ def _read_proc_file(path, opts): except IOError: pass return None - if opts['multiprocessing']: + if opts.get('multiprocessing'): if data.get('pid') == pid: return None else: diff --git a/salt/utils/network.py b/salt/utils/network.py index 52cb976d0e87..936b90a4c851 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -1341,23 +1341,23 @@ def _netbsd_remotes_on(port, which_end): Parses output of shell 'sockstat' (NetBSD) to get connections - $ sudo sockstat -4 + $ sudo sockstat -4 -n USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS - root python2.7 1456 29 tcp4 *.4505 *.* - root python2.7 1445 17 tcp4 *.4506 *.* - root python2.7 1294 14 tcp4 127.0.0.1.11813 127.0.0.1.4505 - root python2.7 1294 41 tcp4 127.0.0.1.61115 127.0.0.1.4506 + root python2.7 1456 29 tcp *.4505 *.* + root python2.7 1445 17 tcp *.4506 *.* + root python2.7 1294 14 tcp 127.0.0.1.11813 127.0.0.1.4505 + root python2.7 1294 41 tcp 127.0.0.1.61115 127.0.0.1.4506 - $ sudo sockstat -4 -c -p 4506 + $ sudo sockstat -4 -c -n -p 4506 USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS - root python2.7 1294 41 tcp4 127.0.0.1.61115 127.0.0.1.4506 + root python2.7 1294 41 tcp 127.0.0.1.61115 127.0.0.1.4506 ''' port = int(port) remotes = set() try: - cmd = salt.utils.shlex_split('sockstat -4 -c -p {0}'.format(port)) + cmd = salt.utils.shlex_split('sockstat -4 -c -n -p {0}'.format(port)) data = subprocess.check_output(cmd) # pylint: disable=minimum-python-version except subprocess.CalledProcessError as ex: log.error('Failed "sockstat" with returncode = {0}'.format(ex.returncode)) @@ -1369,7 +1369,7 @@ def _netbsd_remotes_on(port, which_end): chunks = line.split() if not chunks: continue - # ['root', 'python2.7', '1456', '37', 'tcp4', + # ['root', 'python2.7', '1456', '37', 'tcp', # '127.0.0.1.4505-', '127.0.0.1.55703'] # print chunks if 'COMMAND' in chunks[1]: diff --git a/setup.py b/setup.py index f507a25224ae..202ae02cc010 100755 --- a/setup.py +++ b/setup.py @@ -738,31 +738,6 @@ def run(self): class Install(install): - user_options = install.user_options + [ - ('salt-transport=', None, 'The transport to prepare salt for. Choices are \'zeromq\' ' - '\'raet\' or \'both\'. Defaults to \'zeromq\'', 'zeromq'), - ('salt-root-dir=', None, - 'Salt\'s pre-configured root directory'), - ('salt-config-dir=', None, - 'Salt\'s pre-configured configuration directory'), - ('salt-cache-dir=', None, - 'Salt\'s pre-configured cache directory'), - ('salt-sock-dir=', None, - 'Salt\'s pre-configured socket directory'), - ('salt-srv-root-dir=', None, - 'Salt\'s pre-configured service directory'), - ('salt-base-file-roots-dir=', None, - 'Salt\'s pre-configured file roots directory'), - ('salt-base-pillar-roots-dir=', None, - 'Salt\'s pre-configured pillar roots directory'), - ('salt-base-master-roots-dir=', None, - 'Salt\'s pre-configured master roots directory'), - ('salt-logs-dir=', None, - 'Salt\'s pre-configured logs directory'), - ('salt-pidfile-dir=', None, - 'Salt\'s pre-configured pidfiles directory'), - ] - def initialize_options(self): install.initialize_options(self) diff --git a/tests/unit/config/schemas/ssh_test.py b/tests/unit/config/schemas/ssh_test.py index 02b47ef7cc73..14f9bed3f617 100644 --- a/tests/unit/config/schemas/ssh_test.py +++ b/tests/unit/config/schemas/ssh_test.py @@ -7,6 +7,7 @@ ''' # Import python libs from __future__ import absolute_import, print_function +from distutils.version import LooseVersion as _LooseVersion # Import Salt Testing Libs from salttesting import TestCase, skipIf @@ -23,8 +24,10 @@ import jsonschema import jsonschema.exceptions HAS_JSONSCHEMA = True + JSONSCHEMA_VERSION = _LooseVersion(jsonschema.__version__) except ImportError: HAS_JSONSCHEMA = False + JSONSCHEMA_VERSION = _LooseVersion('0') class RoosterEntryConfigTest(TestCase): @@ -296,7 +299,13 @@ def test_roster_config_validate(self): ssh_schemas.RosterItem.serialize(), format_checker=jsonschema.FormatChecker() ) - self.assertIn( - 'Additional properties are not allowed (\'target-1:1\' was unexpected)', - excinfo.exception.message - ) + if JSONSCHEMA_VERSION < _LooseVersion('2.6.0'): + self.assertIn( + 'Additional properties are not allowed (\'target-1:1\' was unexpected)', + excinfo.exception.message + ) + else: + self.assertIn( + '\'target-1:1\' does not match any of the regexes', + excinfo.exception.message + ) diff --git a/tests/unit/modules/snapper_test.py b/tests/unit/modules/snapper_test.py index ca985cfd055d..a5d9b7686e8a 100644 --- a/tests/unit/modules/snapper_test.py +++ b/tests/unit/modules/snapper_test.py @@ -202,6 +202,26 @@ def test_status_to_string(self): self.assertEqual(snapper.status_to_string(128), ["extended attributes changed"]) self.assertEqual(snapper.status_to_string(256), ["ACL info changed"]) + @patch('salt.modules.snapper.snapper.CreateConfig', MagicMock()) + @patch('salt.modules.snapper.snapper.GetConfig', MagicMock(return_value=DBUS_RET['ListConfigs'][0])) + def test_create_config(self): + opts = { + 'name': 'testconfig', + 'subvolume': '/foo/bar/', + 'fstype': 'btrfs', + 'template': 'mytemplate', + 'extra_opts': {"NUMBER_CLEANUP": False}, + } + with patch('salt.modules.snapper.set_config', MagicMock()) as set_config_mock: + self.assertEqual(snapper.create_config(**opts), DBUS_RET['ListConfigs'][0]) + set_config_mock.assert_called_with("testconfig", **opts['extra_opts']) + + with patch('salt.modules.snapper.set_config', MagicMock()) as set_config_mock: + del opts['extra_opts'] + self.assertEqual(snapper.create_config(**opts), DBUS_RET['ListConfigs'][0]) + assert not set_config_mock.called + self.assertRaises(CommandExecutionError, snapper.create_config) + @patch('salt.modules.snapper.snapper.CreateSingleSnapshot', MagicMock(return_value=1234)) @patch('salt.modules.snapper.snapper.CreatePreSnapshot', MagicMock(return_value=1234)) @patch('salt.modules.snapper.snapper.CreatePostSnapshot', MagicMock(return_value=1234)) @@ -216,6 +236,36 @@ def test_create_snapshot(self): } self.assertEqual(snapper.create_snapshot(**opts), 1234) + @patch('salt.modules.snapper.snapper.DeleteSnapshots', MagicMock()) + @patch('salt.modules.snapper.snapper.ListSnapshots', MagicMock(return_value=DBUS_RET['ListSnapshots'])) + def test_delete_snapshot_id_success(self): + self.assertEqual(snapper.delete_snapshot(snapshots_ids=43), {"root": {"ids": [43], "status": "deleted"}}) + self.assertEqual(snapper.delete_snapshot(snapshots_ids=[42, 43]), {"root": {"ids": [42, 43], "status": "deleted"}}) + + @patch('salt.modules.snapper.snapper.DeleteSnapshots', MagicMock()) + @patch('salt.modules.snapper.snapper.ListSnapshots', MagicMock(return_value=DBUS_RET['ListSnapshots'])) + def test_delete_snapshot_id_fail(self): + self.assertRaises(CommandExecutionError, snapper.delete_snapshot) + self.assertRaises(CommandExecutionError, snapper.delete_snapshot, snapshots_ids=1) + self.assertRaises(CommandExecutionError, snapper.delete_snapshot, snapshots_ids=[1, 2]) + + @patch('salt.modules.snapper.snapper.SetSnapshot', MagicMock()) + def test_modify_snapshot(self): + _ret = { + 'userdata': {'userdata2': 'uservalue2'}, + 'description': 'UPDATED DESCRIPTION', 'timestamp': 1457006571, + 'cleanup': 'number', 'user': 'root', 'type': 'pre', 'id': 42 + } + _opts = { + 'config': 'root', + 'snapshot_id': 42, + 'cleanup': 'number', + 'description': 'UPDATED DESCRIPTION', + 'userdata': {'userdata2': 'uservalue2'}, + } + with patch('salt.modules.snapper.get_snapshot', MagicMock(side_effect=[DBUS_RET['ListSnapshots'][0], _ret])): + self.assertDictEqual(snapper.modify_snapshot(**_opts), _ret) + @patch('salt.modules.snapper._get_last_snapshot', MagicMock(return_value={'id': 42})) def test__get_num_interval(self): self.assertEqual(snapper._get_num_interval(config=None, num_pre=None, num_post=None), (42, 0)) # pylint: disable=protected-access diff --git a/tests/unit/modules/win_ip_test.py b/tests/unit/modules/win_ip_test.py index 301e8929b049..29c4b6a3a90a 100644 --- a/tests/unit/modules/win_ip_test.py +++ b/tests/unit/modules/win_ip_test.py @@ -65,12 +65,12 @@ def test_get_all_interfaces(self): Test if it return configs for all interfaces. ''' ret = {'Ethernet': {'DHCP enabled': 'Yes', - 'DNS servers configured through DHCP': '1.2.3.4', + 'DNS servers configured through DHCP': ['1.2.3.4'], 'Default Gateway': '1.2.3.1', 'Gateway Metric': '0', 'InterfaceMetric': '20', 'Register with which suffix': 'Primary only', - 'WINS servers configured through DHCP': 'None', + 'WINS servers configured through DHCP': ['None'], 'ip_addrs': [{'IP Address': '1.2.3.74', 'Netmask': '255.255.255.0', 'Subnet': '1.2.3.0/24'}]}} @@ -86,11 +86,11 @@ def test_get_interface(self): Test if it return the configuration of a network interface. ''' ret = {'DHCP enabled': 'Yes', - 'DNS servers configured through DHCP': '1.2.3.4', + 'DNS servers configured through DHCP': ['1.2.3.4'], 'Default Gateway': '1.2.3.1', 'Gateway Metric': '0', 'InterfaceMetric': '20', 'Register with which suffix': 'Primary only', - 'WINS servers configured through DHCP': 'None', + 'WINS servers configured through DHCP': ['None'], 'ip_addrs': [{'IP Address': '1.2.3.74', 'Netmask': '255.255.255.0', 'Subnet': '1.2.3.0/24'}]} diff --git a/tests/unit/states/selinux_test.py b/tests/unit/states/selinux_test.py index 026698ad68ff..6b5982bea647 100644 --- a/tests/unit/states/selinux_test.py +++ b/tests/unit/states/selinux_test.py @@ -47,6 +47,7 @@ def test_mode(self): mock_pr = MagicMock(side_effect=['Permissive', 'Enforcing']) with patch.dict(selinux.__salt__, {'selinux.getenforce': mock_en, + 'selinux.getconfig': mock_en, 'selinux.setenforce': mock_pr}): comt = ('SELinux is already in Enforcing mode') ret = {'name': 'Enforcing', 'comment': comt, 'result': True, 'changes': {}} diff --git a/tests/unit/utils/schema_test.py b/tests/unit/utils/schema_test.py index 89a2023b969a..67aac1b5da83 100644 --- a/tests/unit/utils/schema_test.py +++ b/tests/unit/utils/schema_test.py @@ -9,7 +9,7 @@ import json import yaml -from distutils.version import LooseVersion +from distutils.version import LooseVersion as _LooseVersion # Import Salt Testing Libs from salttesting import TestCase, skipIf @@ -25,10 +25,10 @@ import jsonschema import jsonschema.exceptions HAS_JSONSCHEMA = True - JSONSCHEMA_VERSION = jsonschema.__version__ + JSONSCHEMA_VERSION = _LooseVersion(jsonschema.__version__) except ImportError: - JSONSCHEMA_VERSION = '' HAS_JSONSCHEMA = False + JSONSCHEMA_VERSION = _LooseVersion('0') # pylint: disable=unused-import @@ -752,8 +752,7 @@ def test_ipv4_config(self): } ) - @skipIf(HAS_JSONSCHEMA is False, 'The \'jsonschema\' library is missing') - @skipIf(HAS_JSONSCHEMA and LooseVersion(jsonschema.__version__) <= LooseVersion('2.5.0'), 'Requires jsonschema 2.5.0 or greater') + @skipIf(JSONSCHEMA_VERSION <= _LooseVersion('2.5.0'), 'Requires jsonschema 2.5.0 or greater') def test_ipv4_config_validation(self): class TestConf(schema.Schema): item = schema.IPv4Item(title='Item', description='Item description') @@ -1705,7 +1704,14 @@ class TestConf(schema.Schema): with self.assertRaises(jsonschema.exceptions.ValidationError) as excinfo: jsonschema.validate({'item': {'color': 'green', 'sides': 4, 'surfaces': 4}}, TestConf.serialize()) - self.assertIn('Additional properties are not allowed', excinfo.exception.message) + if JSONSCHEMA_VERSION < _LooseVersion('2.6.0'): + self.assertIn( + 'Additional properties are not allowed', + excinfo.exception.message) + else: + self.assertIn( + '\'surfaces\' does not match any of the regexes', + excinfo.exception.message) class TestConf(schema.Schema): item = schema.DictItem(