mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #54918 from dwoz/2019.2.1-merge-master
2019.2.2 merge master
This commit is contained in:
commit
aee25f6413
84 changed files with 8988 additions and 216 deletions
|
@ -255,7 +255,7 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ
|
|||
project = 'Salt'
|
||||
|
||||
version = salt.version.__version__
|
||||
latest_release = '2019.2.0' # latest release
|
||||
latest_release = '2019.2.1' # latest release
|
||||
previous_release = '2018.3.4' # latest release from previous branch
|
||||
previous_release_dir = '2018.3' # path on web server for previous branch
|
||||
next_release = '' # next release
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-API" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-API" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-api \- salt-api Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CALL" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-CALL" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-call \- salt-call Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CLOUD" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-CLOUD" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-cloud \- Salt Cloud Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-CP" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-CP" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-cp \- salt-cp Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-KEY" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-KEY" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-key \- salt-key Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-MASTER" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-MASTER" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-master \- salt-master Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-MINION" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-MINION" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-minion \- salt-minion Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-PROXY" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-PROXY" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-proxy \- salt-proxy Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-RUN" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-RUN" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-run \- salt-run Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-SSH" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-SSH" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-ssh \- salt-ssh Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-SYNDIC" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-SYNDIC" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-syndic \- salt-syndic Documentation
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT-UNITY" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT-UNITY" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt-unity \- salt-unity Command
|
||||
.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SALT" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SALT" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
salt \- salt
|
||||
.
|
||||
|
|
7720
doc/man/salt.7
7720
doc/man/salt.7
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "SPM" "1" "Sep 05, 2019" "2019.2.1" "Salt"
|
||||
.TH "SPM" "1" "Oct 02, 2019" "2019.2.2" "Salt"
|
||||
.SH NAME
|
||||
spm \- Salt Package Manager Command
|
||||
.
|
||||
|
|
|
@ -4,6 +4,25 @@ Salt 2019.2.1 Release Notes
|
|||
|
||||
Version 2019.2.1 is a bugfix release for :ref:`2019.2.0 <release-2019-2-0>`.
|
||||
|
||||
Known Issues
|
||||
============
|
||||
|
||||
* **ISSUE** `#54751`_: Proxy minion fails to start. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54762`_: URIs with IPv6 addresses are broken, preventing master-minion communication in IPv6-only environments. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54776`_: Minion fails to start when it contains `ping_interval` in minion configuration file. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54731`_: Returners (except for default salt master returner) not loading properly in Py3. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54758`_: salt-call state.show_states gives "Passed invalid arguments" error when a sls defined in top.sls file is missing. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54765`_: Jinja from import is broken. Fix planned in 2019.2.2 release.
|
||||
|
||||
* **ISSUE** `#54771`_: Affects only Debian 10. pkgrepo.managed does not work if used with proxy (configured at salt-minion). No fix date available yet.
|
||||
|
||||
* **ISSUE** `#54759`_: Deprecation warnings for pyzmq. No fix date available yet.
|
||||
|
||||
Change to YAML Renderer
|
||||
=======================
|
||||
|
||||
|
@ -6779,6 +6798,14 @@ Changelog for v2019.2.0..v2019.2.1
|
|||
.. _`#54429`: https://github.com/saltstack/salt/issues/54429
|
||||
.. _`#54433`: https://github.com/saltstack/salt/pull/54433
|
||||
.. _`#54434`: https://github.com/saltstack/salt/pull/54434
|
||||
.. _`#54751`: https://github.com/saltstack/salt/issues/54751
|
||||
.. _`#54762`: https://github.com/saltstack/salt/issues/54762
|
||||
.. _`#54776`: https://github.com/saltstack/salt/issues/54776
|
||||
.. _`#54731`: https://github.com/saltstack/salt/pull/54731
|
||||
.. _`#54758`: https://github.com/saltstack/salt/issues/54758
|
||||
.. _`#54765`: https://github.com/saltstack/salt/issues/54765
|
||||
.. _`#54771`: https://github.com/saltstack/salt/issues/54771
|
||||
.. _`#54759`: https://github.com/saltstack/salt/issues/54759
|
||||
.. _`#5`: https://github.com/saltstack/salt/issues/5
|
||||
.. _`#6`: https://github.com/saltstack/salt/issues/6
|
||||
.. _`#7745`: https://github.com/saltstack/salt/issues/7745
|
||||
|
|
292
doc/topics/releases/2019.2.2.rst
Normal file
292
doc/topics/releases/2019.2.2.rst
Normal file
|
@ -0,0 +1,292 @@
|
|||
===========================
|
||||
Salt 2019.2.2 Release Notes
|
||||
===========================
|
||||
|
||||
Version 2019.2.2 is a bugfix release for :ref:`2019.2.0 <release-2019-2-0>`.
|
||||
|
||||
Statistics
|
||||
==========
|
||||
|
||||
- Total Merges: **20**
|
||||
- Total Issue References: **11**
|
||||
- Total PR References: **20**
|
||||
|
||||
- Contributors: **12** (`Akm0d`_, `Ch3LL`_, `Oloremo`_, `OrlandoArcapix`_, `bryceml`_, `dhiltonp`_, `dwoz`_, `frogunder`_, `garethgreenaway`_, `javierbertoli`_, `pizzapanther`_, `s0undt3ch`_)
|
||||
|
||||
Changelog for v2019.2.1..v2019.2.2
|
||||
==================================
|
||||
|
||||
*Generated at: 2019-10-02 18:33:46 UTC*
|
||||
|
||||
* **PR** `#54852`_: (`frogunder`_) Update man pages for 2019.2.2
|
||||
@ *2019-10-02 18:27:07 UTC*
|
||||
|
||||
* 10d433f Merge pull request `#54852`_ from frogunder/man_pages_2019.2.2
|
||||
|
||||
* 92bc4b2 Update man pages for 2019.2.2
|
||||
|
||||
* **PR** `#54845`_: (`s0undt3ch`_) Remove debug print
|
||||
@ *2019-10-02 17:38:21 UTC*
|
||||
|
||||
* 8ca6b20 Merge pull request `#54845`_ from s0undt3ch/hotfix/event-return-fix-2019.2.1
|
||||
|
||||
* 3937890 Remove debug print
|
||||
|
||||
* **ISSUE** `#54755`_: (`Reiner030`_) 2019.2.1/2019.2.0 pip failures even when not using pip (refs: `#54826`_)
|
||||
|
||||
* **PR** `#54826`_: (`dwoz`_) Fix issue 54755 and add regression tests
|
||||
@ *2019-10-01 20:07:46 UTC*
|
||||
|
||||
* 9e3914a Merge pull request `#54826`_ from dwoz/issue_54755
|
||||
|
||||
* 0bad9cb Handle locals and globals separatly
|
||||
|
||||
* bcbe9a2 Only purge pip when needed
|
||||
|
||||
* d2f98ca Fix issue 54755 and add regression tests
|
||||
|
||||
* **PR** `#54830`_: (`frogunder`_) Add known issues to 2019.2.1 release notes
|
||||
@ *2019-10-01 16:23:30 UTC*
|
||||
|
||||
* ba569d0 Merge pull request `#54830`_ from frogunder/update_relasenotes_2019.2.1
|
||||
|
||||
* 8cdb27b Update 2019.2.1.rst
|
||||
|
||||
* 14f955c Add known issues to 2019.2.1 release notes
|
||||
|
||||
* **ISSUE** `#54521`_: (`Oloremo`_) [Regression] Failhard, batch and retcodes (refs: `#54806`_)
|
||||
|
||||
* **PR** `#54806`_: (`Oloremo`_) [Regression] Batch with failhard fix
|
||||
@ *2019-10-01 14:51:47 UTC*
|
||||
|
||||
* 433b6fa Merge pull request `#54806`_ from Oloremo/failhard-batch-fix-2019.2.1
|
||||
|
||||
* 6684793 Merge branch '2019.2.1' into failhard-batch-fix-2019.2.1
|
||||
|
||||
* 3e0e928 Added tests for cli and runner
|
||||
|
||||
* 2416516 Made batch work properly with failhard in cli and runner
|
||||
|
||||
* **ISSUE** `#54820`_: (`OrangeDog`_) schedule.present not idempotent when scheduler disabled (refs: `#54828`_)
|
||||
|
||||
* **PR** `#54828`_: (`garethgreenaway`_) [2019.2.1] Fix global disabling code in scheduler
|
||||
@ *2019-10-01 09:27:49 UTC*
|
||||
|
||||
* ed94aa5 Merge pull request `#54828`_ from garethgreenaway/54820_fix_schedule_disabled_job_enabled_bug
|
||||
|
||||
* be15a28 Rework code that handles individual jobs being disabled and scheduler being globally being disabled. Previously disabling the schedule would result in individual jobs being disabled when they were run through eval. This change does not change schedule items.
|
||||
|
||||
* **PR** `#54778`_: (`Akm0d`_) fix broken salt-cloud openstack query
|
||||
@ *2019-10-01 09:23:27 UTC*
|
||||
|
||||
* 435b40c Merge pull request `#54778`_ from Akm0d/master_openstack_query_fix
|
||||
|
||||
* ba4ba2a fixed pylint errors in openstack test
|
||||
|
||||
* d9a8517 Added openstack tests for openstack --query fix
|
||||
|
||||
* 59214ad Fallback to image id if we don't have an image name
|
||||
|
||||
* 3a42a4d fixed pylint error
|
||||
|
||||
* 0074d18 created unit tests for openstack
|
||||
|
||||
* 4255e3e Merge branch '2019.2.1' of https://github.com/saltstack/salt into HEAD
|
||||
|
||||
* 1c2821b Return a configured provider, not a bool
|
||||
|
||||
* c585550 fix broken salt-cloud openstack query
|
||||
|
||||
* **ISSUE** `#54762`_: (`margau`_) 2019.2.1: Breaks Minion-Master Communication (refs: `#54807`_, `#54784`_, `#54823`_)
|
||||
|
||||
* **PR** `#54823`_: (`dhiltonp`_) ip_bracket can now accept ipv6 addresses with brackets
|
||||
@ *2019-10-01 01:13:34 UTC*
|
||||
|
||||
* 93b1c4d Merge pull request `#54823`_ from dhiltonp/maybe-bracket
|
||||
|
||||
* faa1d98 ip_bracket can now accept ipv6 addresses with brackets
|
||||
|
||||
* **ISSUE** `#54762`_: (`margau`_) 2019.2.1: Breaks Minion-Master Communication (refs: `#54807`_, `#54784`_, `#54823`_)
|
||||
|
||||
* **PR** `#54807`_: (`dwoz`_) Fix pip state pip >=10.0 and <=18.0
|
||||
@ *2019-09-30 09:20:14 UTC*
|
||||
|
||||
* **PR** `#54772`_: (`OrlandoArcapix`_) Fix import of pip modules (refs: `#54807`_)
|
||||
|
||||
* b61b30d Merge pull request `#54807`_ from dwoz/patch-2
|
||||
|
||||
* 664806b Add unit test for pip state fix
|
||||
|
||||
* e637658 Revert change to pip version query
|
||||
|
||||
* 42810a2 Fix import of pip modules
|
||||
|
||||
* **ISSUE** `#54741`_: (`kjkeane`_) Schedulers Fail to Run (refs: `#54799`_)
|
||||
|
||||
* **PR** `#54799`_: (`garethgreenaway`_) Fix to scheduler when job without a time element is run with schedule.run_job
|
||||
@ *2019-09-30 00:19:43 UTC*
|
||||
|
||||
* 4ee1ff6 Merge pull request `#54799`_ from garethgreenaway/54741_run_job_fails_without_time_element
|
||||
|
||||
* 44caa81 Merge branch '54741_run_job_fails_without_time_element' of github.com:garethgreenaway/salt into 54741_run_job_fails_without_time_element
|
||||
|
||||
* 3ae4f75 Merge branch '2019.2.1' into 54741_run_job_fails_without_time_element
|
||||
|
||||
* 8afd2d8 Removing extra, unnecessary code.
|
||||
|
||||
* 549cfb8 Fixing test_run_job test to ensure the right data is being asserted. Updating unit/test_module_names.py to include integration.scheduler.test_run_job.
|
||||
|
||||
* 7d716d6 Fixing lint.
|
||||
|
||||
* ec68591 If a scheduled job does not contains a time element parameter then running that job with schedule.run_job fails with a traceback because data['run'] does not exist.
|
||||
|
||||
* **PR** `#54785`_: (`Ch3LL`_) Fix state.show_states when sls file missing in top file
|
||||
@ *2019-09-30 00:00:34 UTC*
|
||||
|
||||
* b90c3f2 Merge pull request `#54785`_ from Ch3LL/fix_show_states
|
||||
|
||||
* 96540be Clean up files after state.show_states test
|
||||
|
||||
* ad265ae Fix state.show_states when sls file missing
|
||||
|
||||
* **ISSUE** `#54768`_: (`paul-palmer`_) 2019.2.1 Some Jinja imports not found (refs: `#54780`_)
|
||||
|
||||
* **ISSUE** `#54765`_: (`awerner`_) 2019.2.1: Jinja from import broken (refs: `#54780`_)
|
||||
|
||||
* **PR** `#54780`_: (`dwoz`_) Fix masterless jinja imports
|
||||
@ *2019-09-29 22:12:48 UTC*
|
||||
|
||||
* b9459e6 Merge pull request `#54780`_ from dwoz/fix-masterless-jinja-imports
|
||||
|
||||
* 5d873cc Merge branch '2019.2.1' into fix-masterless-jinja-imports
|
||||
|
||||
* e901a83 Add regression tests for jinja import bug
|
||||
|
||||
* 3925bb7 Fix broken jinja imports in masterless salt-call
|
||||
|
||||
* **ISSUE** `#54776`_: (`javierbertoli`_) Setting `ping_interval` in salt-minion's config (version 2019.2.1) prevents it from starting (refs: `#54777`_)
|
||||
|
||||
* **PR** `#54777`_: (`javierbertoli`_) Fix minion's remove_periodic_callback()
|
||||
@ *2019-09-29 21:33:53 UTC*
|
||||
|
||||
* 4c240e5 Merge pull request `#54777`_ from netmanagers/2019.2.1
|
||||
|
||||
* 459c790 Merge branch '2019.2.1' into 2019.2.1
|
||||
|
||||
* **PR** `#54805`_: (`bryceml`_) improve lint job
|
||||
@ *2019-09-29 21:24:05 UTC*
|
||||
|
||||
* 83f8f5c Merge pull request `#54805`_ from bryceml/2019.2.1_update_lint_salt
|
||||
|
||||
* ffa4ed6 improve lint job
|
||||
|
||||
* fa1a767 Merge branch '2019.2.1' into 2019.2.1
|
||||
|
||||
* **ISSUE** `#54751`_: (`jnmatlock`_) NXOS_API Proxy Minions Error KeyError: 'proxy.post_master_init' after upgrading to 2019.2.1 (refs: `#54783`_)
|
||||
|
||||
* **PR** `#54783`_: (`garethgreenaway`_) Ensure metaproxy directory is included in sdist
|
||||
@ *2019-09-29 02:17:23 UTC*
|
||||
|
||||
* 6b43fbe Merge pull request `#54783`_ from garethgreenaway/54751_fixing_missing_metaproxy_directory
|
||||
|
||||
* 67d9938 Merge branch '2019.2.1' into 54751_fixing_missing_metaproxy_directory
|
||||
|
||||
* a35e609 Adding __init__.py to metaproxy directory so that metaproxy is included when running setup.py.
|
||||
|
||||
* **ISSUE** `#54762`_: (`margau`_) 2019.2.1: Breaks Minion-Master Communication (refs: `#54807`_, `#54784`_, `#54823`_)
|
||||
|
||||
* **PR** `#54784`_: (`dhiltonp`_) fix dns_check to return uri-compatible ipv6 addresses, add tests
|
||||
@ *2019-09-28 08:36:51 UTC*
|
||||
|
||||
* 7912b67 Merge pull request `#54784`_ from dhiltonp/ipv46
|
||||
|
||||
* 042a101 Merge branch '2019.2.1' into ipv46
|
||||
|
||||
* **PR** `#54779`_: (`frogunder`_) Add 2019.2.2 release notes
|
||||
@ *2019-09-27 17:45:46 UTC*
|
||||
|
||||
* 2f94b44 Merge pull request `#54779`_ from frogunder/releasenotes_2019.2.2
|
||||
|
||||
* 67f564b Add 2019.2.2 release notes
|
||||
|
||||
* ac6b54f Merge branch '2019.2.1' into ipv46
|
||||
|
||||
* 93ebd09 update mock (py2) from 2.0.0 to 3.0.5
|
||||
|
||||
* 37bcc4c fix dns_check to return uri-compatible ipv6 addresses, add tests
|
||||
|
||||
* dd86c46 Merge pull request `#1`_ from waynew/pull/54777-callback-typo
|
||||
|
||||
* a57f7d0 Add tests
|
||||
|
||||
* c19d0b0 Fix minion's remove_periodic_callback()
|
||||
|
||||
* **PR** `#54731`_: (`pizzapanther`_) Fix returners not loading properly
|
||||
@ *2019-09-26 17:24:27 UTC*
|
||||
|
||||
* 46bec3c Merge pull request `#54731`_ from pizzapanther/not-so-__new__-and-shiny
|
||||
|
||||
* bdf24f4 Make sure we tests salt-master's `event_return` setting
|
||||
|
||||
* 5499518 remove unnecessary import
|
||||
|
||||
* 3f8a382 fix module import
|
||||
|
||||
* 0746aa7 remove __new__ method since it was removed from parent class
|
||||
|
||||
* **PR** `#54706`_: (`bryceml`_) 2019.2.1 ruby
|
||||
@ *2019-09-23 16:00:27 UTC*
|
||||
|
||||
* e2b86bf Merge pull request `#54706`_ from bryceml/2019.2.1_ruby
|
||||
|
||||
* 168a6c1 switch to ruby 2.6.3
|
||||
|
||||
.. _`#1`: https://github.com/saltstack/salt/issues/1
|
||||
.. _`#54521`: https://github.com/saltstack/salt/issues/54521
|
||||
.. _`#54706`: https://github.com/saltstack/salt/pull/54706
|
||||
.. _`#54731`: https://github.com/saltstack/salt/pull/54731
|
||||
.. _`#54741`: https://github.com/saltstack/salt/issues/54741
|
||||
.. _`#54751`: https://github.com/saltstack/salt/issues/54751
|
||||
.. _`#54755`: https://github.com/saltstack/salt/issues/54755
|
||||
.. _`#54762`: https://github.com/saltstack/salt/issues/54762
|
||||
.. _`#54765`: https://github.com/saltstack/salt/issues/54765
|
||||
.. _`#54768`: https://github.com/saltstack/salt/issues/54768
|
||||
.. _`#54772`: https://github.com/saltstack/salt/pull/54772
|
||||
.. _`#54776`: https://github.com/saltstack/salt/issues/54776
|
||||
.. _`#54777`: https://github.com/saltstack/salt/pull/54777
|
||||
.. _`#54778`: https://github.com/saltstack/salt/pull/54778
|
||||
.. _`#54779`: https://github.com/saltstack/salt/pull/54779
|
||||
.. _`#54780`: https://github.com/saltstack/salt/pull/54780
|
||||
.. _`#54783`: https://github.com/saltstack/salt/pull/54783
|
||||
.. _`#54784`: https://github.com/saltstack/salt/pull/54784
|
||||
.. _`#54785`: https://github.com/saltstack/salt/pull/54785
|
||||
.. _`#54799`: https://github.com/saltstack/salt/pull/54799
|
||||
.. _`#54805`: https://github.com/saltstack/salt/pull/54805
|
||||
.. _`#54806`: https://github.com/saltstack/salt/pull/54806
|
||||
.. _`#54807`: https://github.com/saltstack/salt/pull/54807
|
||||
.. _`#54820`: https://github.com/saltstack/salt/issues/54820
|
||||
.. _`#54823`: https://github.com/saltstack/salt/pull/54823
|
||||
.. _`#54826`: https://github.com/saltstack/salt/pull/54826
|
||||
.. _`#54828`: https://github.com/saltstack/salt/pull/54828
|
||||
.. _`#54830`: https://github.com/saltstack/salt/pull/54830
|
||||
.. _`#54845`: https://github.com/saltstack/salt/pull/54845
|
||||
.. _`#54852`: https://github.com/saltstack/salt/pull/54852
|
||||
.. _`Akm0d`: https://github.com/Akm0d
|
||||
.. _`Ch3LL`: https://github.com/Ch3LL
|
||||
.. _`Oloremo`: https://github.com/Oloremo
|
||||
.. _`OrangeDog`: https://github.com/OrangeDog
|
||||
.. _`OrlandoArcapix`: https://github.com/OrlandoArcapix
|
||||
.. _`Reiner030`: https://github.com/Reiner030
|
||||
.. _`awerner`: https://github.com/awerner
|
||||
.. _`bryceml`: https://github.com/bryceml
|
||||
.. _`dhiltonp`: https://github.com/dhiltonp
|
||||
.. _`dwoz`: https://github.com/dwoz
|
||||
.. _`frogunder`: https://github.com/frogunder
|
||||
.. _`garethgreenaway`: https://github.com/garethgreenaway
|
||||
.. _`javierbertoli`: https://github.com/javierbertoli
|
||||
.. _`jnmatlock`: https://github.com/jnmatlock
|
||||
.. _`kjkeane`: https://github.com/kjkeane
|
||||
.. _`margau`: https://github.com/margau
|
||||
.. _`paul-palmer`: https://github.com/paul-palmer
|
||||
.. _`pizzapanther`: https://github.com/pizzapanther
|
||||
.. _`s0undt3ch`: https://github.com/s0undt3ch
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -56,7 +56,7 @@ kubernetes==3.0.0
|
|||
libnacl==1.6.1
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -59,7 +59,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -59,7 +59,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -57,7 +57,7 @@ kubernetes==3.0.0
|
|||
libnacl==1.6.1
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -65,7 +65,7 @@ lxml==4.3.3 # via junos-eznc, ncclient
|
|||
mako==1.0.7
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -59,7 +59,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -59,7 +59,7 @@ libnacl==1.6.1
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -60,7 +60,7 @@ lxml==4.3.0
|
|||
mako==1.0.7
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -54,7 +54,7 @@ keyring==5.7.1
|
|||
kubernetes==3.0.0
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -57,7 +57,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -57,7 +57,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -58,7 +58,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -55,7 +55,7 @@ keyring==5.7.1
|
|||
kubernetes==3.0.0
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -63,7 +63,7 @@ lxml==4.3.3 # via junos-eznc, ncclient
|
|||
mako==1.0.7
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -57,7 +57,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -57,7 +57,7 @@ kubernetes==3.0.0
|
|||
lxml==4.3.3 # via junos-eznc, ncclient
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -59,7 +59,7 @@ lxml==4.3.0
|
|||
mako==1.0.7
|
||||
markupsafe==1.1.1
|
||||
meld3==1.0.2 # via supervisor
|
||||
mock==2.0.0 ; python_version < "3.6"
|
||||
mock==3.0.5 ; python_version < "3.6"
|
||||
more-itertools==5.0.0
|
||||
moto==1.3.7
|
||||
msgpack-python==0.5.6
|
||||
|
|
|
@ -254,6 +254,9 @@ class Batch(object):
|
|||
data['ret']['retcode'] = data['retcode']
|
||||
if self.opts.get('failhard') and data['ret']['retcode'] > 0:
|
||||
failhard = True
|
||||
else:
|
||||
if self.opts.get('failhard') and data['retcode'] > 0:
|
||||
failhard = True
|
||||
|
||||
if self.opts.get('raw'):
|
||||
ret[minion] = data
|
||||
|
|
|
@ -547,7 +547,7 @@ class LocalClient(object):
|
|||
'tgt_type': tgt_type,
|
||||
'ret': ret,
|
||||
'batch': batch,
|
||||
'failhard': kwargs.get('failhard', False),
|
||||
'failhard': kwargs.get('failhard', self.opts.get('failhard', False)),
|
||||
'raw': kwargs.get('raw', False)}
|
||||
|
||||
if 'timeout' in kwargs:
|
||||
|
|
|
@ -260,10 +260,14 @@ def get_configured_provider():
|
|||
'''
|
||||
Return the first configured instance.
|
||||
'''
|
||||
return config.is_provider_configured(
|
||||
provider = config.is_provider_configured(
|
||||
__opts__, __active_provider_name__ or __virtualname__,
|
||||
('auth', 'region_name'), log_message=False,
|
||||
) or config.is_provider_configured(
|
||||
('auth', 'region_name')
|
||||
)
|
||||
if provider:
|
||||
return provider
|
||||
|
||||
return config.is_provider_configured(
|
||||
__opts__, __active_provider_name__ or __virtualname__,
|
||||
('cloud', 'region_name')
|
||||
)
|
||||
|
@ -280,8 +284,8 @@ def get_dependencies():
|
|||
log.warning(HAS_SHADE[1])
|
||||
return False
|
||||
deps = {
|
||||
'shade': shade[0],
|
||||
'os_client_config': shade[0],
|
||||
'shade': HAS_SHADE[0],
|
||||
'os_client_config': HAS_SHADE[0],
|
||||
}
|
||||
return config.check_driver_dependencies(
|
||||
__virtualname__,
|
||||
|
@ -420,7 +424,10 @@ def list_nodes_full(conn=None, call=None):
|
|||
ret[node.name]['public_ips'] = _get_ips(node, 'public')
|
||||
ret[node.name]['floating_ips'] = _get_ips(node, 'floating')
|
||||
ret[node.name]['fixed_ips'] = _get_ips(node, 'fixed')
|
||||
ret[node.name]['image'] = node.image.name
|
||||
if isinstance(node.image, six.string_types):
|
||||
ret[node.name]['image'] = node.image
|
||||
else:
|
||||
ret[node.name]['image'] = getattr(conn.get_image(node.image.id), 'name', node.image.id)
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -479,7 +486,7 @@ def show_instance(name, conn=None, call=None):
|
|||
if isinstance(node.image, six.string_types):
|
||||
ret['image'] = node.image
|
||||
else:
|
||||
ret['image'] = conn.get_image(node.image.id).name
|
||||
ret['image'] = getattr(conn.get_image(node.image.id), 'name', node.image.id)
|
||||
return ret
|
||||
|
||||
|
||||
|
|
4
salt/metaproxy/__init__.py
Normal file
4
salt/metaproxy/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Metaproxy Directory
|
||||
'''
|
|
@ -2730,7 +2730,7 @@ class Minion(MinionBase):
|
|||
self._fire_master('ping', 'minion_ping', sync=False, timeout_handler=ping_timeout_handler)
|
||||
except Exception:
|
||||
log.warning('Attempt to ping master failed.', exc_on_loglevel=logging.DEBUG)
|
||||
self.remove_periodic_callbback('ping', ping_master)
|
||||
self.remove_periodic_callback('ping')
|
||||
self.add_periodic_callback('ping', ping_master, ping_interval)
|
||||
|
||||
# add handler to subscriber
|
||||
|
|
|
@ -1645,6 +1645,9 @@ def show_states(queue=False, **kwargs):
|
|||
raise Exception(result)
|
||||
|
||||
for s in result:
|
||||
if not isinstance(s, dict):
|
||||
_set_retcode(result)
|
||||
return result
|
||||
states[s['__sls__']] = True
|
||||
finally:
|
||||
st_.pop_active()
|
||||
|
|
|
@ -24,6 +24,7 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
import re
|
||||
import types
|
||||
import logging
|
||||
import sys
|
||||
try:
|
||||
import pkg_resources
|
||||
HAS_PKG_RESOURCES = True
|
||||
|
@ -39,13 +40,15 @@ from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
|||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
# pylint: disable=import-error
|
||||
try:
|
||||
import pip
|
||||
HAS_PIP = True
|
||||
except ImportError:
|
||||
HAS_PIP = False
|
||||
|
||||
|
||||
def purge_pip():
|
||||
'''
|
||||
Purge pip and it's sub-modules
|
||||
'''
|
||||
# Remove references to the loaded pip module above so reloading works
|
||||
import sys
|
||||
if 'pip' not in sys.modules:
|
||||
return
|
||||
pip_related_entries = [
|
||||
(k, v) for (k, v) in sys.modules.items()
|
||||
or getattr(v, '__module__', '').startswith('pip.')
|
||||
|
@ -55,19 +58,56 @@ except ImportError:
|
|||
sys.modules.pop(name)
|
||||
del entry
|
||||
|
||||
del pip
|
||||
if 'pip' in globals():
|
||||
del globals()['pip']
|
||||
if 'pip' in locals():
|
||||
del locals()['pip']
|
||||
sys_modules_pip = sys.modules.pop('pip', None)
|
||||
if sys_modules_pip is not None:
|
||||
del sys_modules_pip
|
||||
|
||||
|
||||
def pip_has_internal_exceptions_mod(ver):
|
||||
'''
|
||||
True when the pip version has the `pip._internal.exceptions` module
|
||||
'''
|
||||
return salt.utils.versions.compare(
|
||||
ver1=ver,
|
||||
oper='>=',
|
||||
ver2='10.0',
|
||||
)
|
||||
|
||||
|
||||
def pip_has_exceptions_mod(ver):
|
||||
'''
|
||||
True when the pip version has the `pip.exceptions` module
|
||||
'''
|
||||
if pip_has_internal_exceptions_mod(ver):
|
||||
return False
|
||||
return salt.utils.versions.compare(
|
||||
ver1=ver,
|
||||
oper='>=',
|
||||
ver2='1.0'
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
import pip
|
||||
HAS_PIP = True
|
||||
except ImportError:
|
||||
HAS_PIP = False
|
||||
|
||||
|
||||
if HAS_PIP is True:
|
||||
if salt.utils.versions.compare(ver1=pip.__version__,
|
||||
oper='>=',
|
||||
ver2='18.1'):
|
||||
if not hasattr(purge_pip, '__pip_ver__'):
|
||||
purge_pip.__pip_ver__ = pip.__version__
|
||||
elif purge_pip.__pip_ver__ != pip.__version__:
|
||||
purge_pip()
|
||||
import pip
|
||||
purge_pip.__pip_ver__ = pip.__version__
|
||||
if pip_has_internal_exceptions_mod(pip.__version__):
|
||||
from pip._internal.exceptions import InstallationError # pylint: disable=E0611,E0401
|
||||
elif salt.utils.versions.compare(ver1=pip.__version__,
|
||||
oper='>=',
|
||||
ver2='1.0'):
|
||||
elif pip_has_exceptions_mod(pip.__version__):
|
||||
from pip.exceptions import InstallationError # pylint: disable=E0611,E0401
|
||||
else:
|
||||
InstallationError = ValueError
|
||||
|
|
|
@ -128,6 +128,7 @@ def state(name,
|
|||
queue=False,
|
||||
subset=None,
|
||||
orchestration_jid=None,
|
||||
failhard=None,
|
||||
**kwargs):
|
||||
'''
|
||||
Invoke a state run on a given target
|
||||
|
@ -221,6 +222,11 @@ def state(name,
|
|||
|
||||
.. versionadded:: 2017.7.0
|
||||
|
||||
failhard
|
||||
pass failhard down to the executing state
|
||||
|
||||
.. versionadded:: 2019.2.2
|
||||
|
||||
Examples:
|
||||
|
||||
Run a list of sls files via :py:func:`state.sls <salt.state.sls>` on target
|
||||
|
@ -311,9 +317,13 @@ def state(name,
|
|||
|
||||
if batch is not None:
|
||||
cmd_kw['batch'] = six.text_type(batch)
|
||||
|
||||
if subset is not None:
|
||||
cmd_kw['subset'] = subset
|
||||
|
||||
if failhard is True or __opts__.get('failhard'):
|
||||
cmd_kw['failhard'] = True
|
||||
|
||||
masterless = __opts__['__role'] == 'minion' and \
|
||||
__opts__['file_client'] == 'local'
|
||||
if not masterless:
|
||||
|
@ -428,6 +438,7 @@ def function(
|
|||
timeout=None,
|
||||
batch=None,
|
||||
subset=None,
|
||||
failhard=None,
|
||||
**kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Execute a single module function on a remote minion via salt or salt-ssh
|
||||
|
@ -477,6 +488,11 @@ def function(
|
|||
|
||||
.. versionadded:: 2017.7.0
|
||||
|
||||
failhard
|
||||
pass failhard down to the executing state
|
||||
|
||||
.. versionadded:: 2019.2.2
|
||||
|
||||
'''
|
||||
func_ret = {'name': name,
|
||||
'changes': {},
|
||||
|
@ -502,6 +518,9 @@ def function(
|
|||
cmd_kw['expect_minions'] = expect_minions
|
||||
cmd_kw['_cmd_meta'] = True
|
||||
|
||||
if failhard is True or __opts__.get('failhard'):
|
||||
cmd_kw['failhard'] = True
|
||||
|
||||
if ret_config:
|
||||
cmd_kw['ret_config'] = ret_config
|
||||
|
||||
|
|
|
@ -59,7 +59,6 @@ import fnmatch
|
|||
import hashlib
|
||||
import logging
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
try:
|
||||
from collections.abc import MutableMapping
|
||||
|
@ -1162,22 +1161,16 @@ class EventReturn(salt.utils.process.SignalHandlingMultiprocessingProcess):
|
|||
A dedicated process which listens to the master event bus and queues
|
||||
and forwards events to the specified returner.
|
||||
'''
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if sys.platform.startswith('win'):
|
||||
# This is required for Windows. On Linux, when a process is
|
||||
# forked, the module namespace is copied and the current process
|
||||
# gets all of sys.modules from where the fork happens. This is not
|
||||
# the case for Windows.
|
||||
import salt.minion
|
||||
instance = super(EventReturn, cls).__new__(cls, *args, **kwargs)
|
||||
return instance
|
||||
|
||||
def __init__(self, opts, **kwargs):
|
||||
'''
|
||||
Initialize the EventReturn system
|
||||
|
||||
Return an EventReturn instance
|
||||
'''
|
||||
# This is required because the process is forked and the module no
|
||||
# longer exists in the global namespace.
|
||||
import salt.minion
|
||||
|
||||
super(EventReturn, self).__init__(**kwargs)
|
||||
|
||||
self.opts = opts
|
||||
|
|
|
@ -56,16 +56,18 @@ class SaltCacheLoader(BaseLoader):
|
|||
and only loaded once per loader instance.
|
||||
'''
|
||||
|
||||
_cached_pillar_client = None
|
||||
_cached_client = None
|
||||
|
||||
@classmethod
|
||||
def shutdown(cls):
|
||||
if cls._cached_client is None:
|
||||
return
|
||||
# PillarClient and LocalClient objects do not have a destroy method
|
||||
if hasattr(cls._cached_client, 'destroy'):
|
||||
cls._cached_client.destroy()
|
||||
cls._cached_client = None
|
||||
for attr in ('_cached_client', '_cached_pillar_client'):
|
||||
client = getattr(cls, attr, None)
|
||||
if client is not None:
|
||||
# PillarClient and LocalClient objects do not have a destroy method
|
||||
if hasattr(client, 'destroy'):
|
||||
client.destroy()
|
||||
setattr(cls, attr, None)
|
||||
|
||||
def __init__(self, opts, saltenv='base', encoding='utf-8',
|
||||
pillar_rend=False, _file_client=None):
|
||||
|
@ -94,10 +96,12 @@ class SaltCacheLoader(BaseLoader):
|
|||
# and use that. This avoids opening a new file_client every time this
|
||||
# class is instantiated
|
||||
if self._file_client is None:
|
||||
if not SaltCacheLoader._cached_client:
|
||||
SaltCacheLoader._cached_client = salt.fileclient.get_file_client(
|
||||
self.opts, self.pillar_rend)
|
||||
self._file_client = SaltCacheLoader._cached_client
|
||||
attr = '_cached_pillar_client' if self.pillar_rend else '_cached_client'
|
||||
cached_client = getattr(self, attr, None)
|
||||
if cached_client is None:
|
||||
cached_client = salt.fileclient.get_file_client(self.opts, self.pillar_rend)
|
||||
setattr(SaltCacheLoader, attr, cached_client)
|
||||
self._file_client = cached_client
|
||||
return self._file_client
|
||||
|
||||
def cache_file(self, template):
|
||||
|
|
|
@ -1899,61 +1899,25 @@ def refresh_dns():
|
|||
@jinja_filter('dns_check')
|
||||
def dns_check(addr, port, safe=False, ipv6=None):
|
||||
'''
|
||||
Return the ip resolved by dns, but do not exit on failure, only raise an
|
||||
exception. Obeys system preference for IPv4/6 address resolution - this
|
||||
can be overridden by the ipv6 flag.
|
||||
Tries to connect to the address before considering it useful. If no address
|
||||
can be reached, the first one resolved is used as a fallback.
|
||||
Return an ip address resolved by dns in a format usable in URLs (ipv6 in brackets).
|
||||
Obeys system preference for IPv4/6 address resolution - this can be overridden by
|
||||
the ipv6 flag. Tries to connect to the address before considering it useful. If no
|
||||
address can be reached, the first one resolved is used as a fallback.
|
||||
Does not exit on failure, raises an exception.
|
||||
'''
|
||||
error = False
|
||||
lookup = addr
|
||||
seen_ipv6 = False
|
||||
ip_addrs = []
|
||||
family = socket.AF_INET6 if ipv6 else socket.AF_INET if ipv6 is False else socket.AF_UNSPEC
|
||||
try:
|
||||
refresh_dns()
|
||||
hostnames = socket.getaddrinfo(addr, port, family, socket.SOCK_STREAM)
|
||||
if not hostnames:
|
||||
error = True
|
||||
else:
|
||||
resolved = False
|
||||
candidates = []
|
||||
for h in hostnames:
|
||||
# Input is IP address, passed through unchanged, just return it
|
||||
if h[4][0] == addr:
|
||||
resolved = salt.utils.zeromq.ip_bracket(addr)
|
||||
break
|
||||
|
||||
if h[0] == socket.AF_INET and ipv6 is True:
|
||||
continue
|
||||
if h[0] == socket.AF_INET6 and ipv6 is False:
|
||||
continue
|
||||
|
||||
candidate_addr = h[4][0]
|
||||
|
||||
if h[0] != socket.AF_INET6 or ipv6 is not None:
|
||||
candidates.append(candidate_addr)
|
||||
|
||||
try:
|
||||
s = socket.socket(h[0], socket.SOCK_STREAM)
|
||||
s.connect((candidate_addr, port))
|
||||
s.close()
|
||||
|
||||
resolved = candidate_addr
|
||||
break
|
||||
except socket.error:
|
||||
pass
|
||||
if not resolved:
|
||||
if len(candidates) > 0:
|
||||
resolved = candidates[0]
|
||||
else:
|
||||
error = True
|
||||
addrinfo = socket.getaddrinfo(addr, port, family, socket.SOCK_STREAM)
|
||||
ip_addrs = _test_addrs(addrinfo, port)
|
||||
except TypeError:
|
||||
err = ('Attempt to resolve address \'{0}\' failed. Invalid or unresolveable address').format(lookup)
|
||||
err = ('Attempt to resolve address \'{0}\' failed. Invalid or unresolveable address').format(addr)
|
||||
raise SaltSystemExit(code=42, msg=err)
|
||||
except socket.error:
|
||||
error = True
|
||||
pass
|
||||
|
||||
if error:
|
||||
if not ip_addrs:
|
||||
err = ('DNS lookup or connection check of \'{0}\' failed.').format(addr)
|
||||
if safe:
|
||||
if salt.log.is_console_configured():
|
||||
|
@ -1963,7 +1927,34 @@ def dns_check(addr, port, safe=False, ipv6=None):
|
|||
log.error(err)
|
||||
raise SaltClientError()
|
||||
raise SaltSystemExit(code=42, msg=err)
|
||||
return resolved
|
||||
|
||||
return salt.utils.zeromq.ip_bracket(ip_addrs[0])
|
||||
|
||||
|
||||
def _test_addrs(addrinfo, port):
|
||||
'''
|
||||
Attempt to connect to all addresses, return one if it succeeds.
|
||||
Otherwise, return all addrs.
|
||||
'''
|
||||
ip_addrs = []
|
||||
# test for connectivity, short circuit on success
|
||||
for a in addrinfo:
|
||||
ip_family = a[0]
|
||||
ip_addr = a[4][0]
|
||||
if ip_addr in ip_addrs:
|
||||
continue
|
||||
ip_addrs.append(ip_addr)
|
||||
|
||||
try:
|
||||
s = socket.socket(ip_family, socket.SOCK_STREAM)
|
||||
s.connect((ip_addr, port))
|
||||
s.close()
|
||||
|
||||
ip_addrs = [ip_addr]
|
||||
break
|
||||
except socket.error:
|
||||
pass
|
||||
return ip_addrs
|
||||
|
||||
|
||||
def parse_host_port(host_port):
|
||||
|
|
|
@ -214,7 +214,7 @@ class Schedule(object):
|
|||
# dict we treat it like it was there and is True
|
||||
|
||||
# Check if we're able to run
|
||||
if not data['run']:
|
||||
if 'run' not in data or not data['run']:
|
||||
return data
|
||||
if 'jid_include' not in data or data['jid_include']:
|
||||
jobcount = 0
|
||||
|
@ -463,7 +463,10 @@ class Schedule(object):
|
|||
|
||||
if 'name' not in data:
|
||||
data['name'] = name
|
||||
log.info('Running Job: %s', name)
|
||||
|
||||
# Assume run should be True until we check max_running
|
||||
if 'run' not in data:
|
||||
data['run'] = True
|
||||
|
||||
if not self.standalone:
|
||||
data = self._check_max_running(func,
|
||||
|
@ -472,8 +475,8 @@ class Schedule(object):
|
|||
datetime.datetime.now())
|
||||
|
||||
# Grab run, assume True
|
||||
run = data.get('run', True)
|
||||
if run:
|
||||
if data.get('run'):
|
||||
log.info('Running Job: %s', name)
|
||||
self._run_job(func, data)
|
||||
|
||||
def enable_schedule(self):
|
||||
|
@ -1593,22 +1596,10 @@ class Schedule(object):
|
|||
if '_continue' in data and data['_continue']:
|
||||
run = False
|
||||
|
||||
# If there is no job specific enabled available,
|
||||
# grab the global which defaults to True.
|
||||
if 'enabled' not in data:
|
||||
data['enabled'] = self.enabled
|
||||
|
||||
# If globally disabled, disable the job
|
||||
if not self.enabled:
|
||||
data['enabled'] = self.enabled
|
||||
data['_skip_reason'] = 'disabled'
|
||||
data['_skipped_time'] = now
|
||||
data['_skipped'] = True
|
||||
run = False
|
||||
|
||||
# Job is disabled, set run to False
|
||||
if 'enabled' in data and not data['enabled']:
|
||||
data['_enabled'] = False
|
||||
# If globally disabled or job
|
||||
# is diabled skip the job
|
||||
if not self.enabled or not data.get('enabled', True):
|
||||
log.trace('Job: %s is disabled', job_name)
|
||||
data['_skip_reason'] = 'disabled'
|
||||
data['_skipped_time'] = now
|
||||
data['_skipped'] = True
|
||||
|
@ -1621,14 +1612,6 @@ class Schedule(object):
|
|||
|
||||
try:
|
||||
if run:
|
||||
# Job is disabled, continue
|
||||
if 'enabled' in data and not data['enabled']:
|
||||
log.debug('Job: %s is disabled', job_name)
|
||||
data['_skip_reason'] = 'disabled'
|
||||
data['_skipped_time'] = now
|
||||
data['_skipped'] = True
|
||||
continue
|
||||
|
||||
if 'jid_include' not in data or data['jid_include']:
|
||||
data['jid_include'] = True
|
||||
log.debug('schedule: Job %s was scheduled with jid_include, '
|
||||
|
|
|
@ -80,8 +80,11 @@ def check_ipc_path_max_len(uri):
|
|||
|
||||
def ip_bracket(addr):
|
||||
'''
|
||||
Convert IP address representation to ZMQ (URL) format. ZMQ expects
|
||||
brackets around IPv6 literals, since they are used in URLs.
|
||||
Ensure IP addresses are URI-compatible - specifically, add brackets
|
||||
around IPv6 literals if they are not already present.
|
||||
'''
|
||||
addr = str(addr)
|
||||
addr = addr.lstrip('[')
|
||||
addr = addr.rstrip(']')
|
||||
addr = ipaddress.ip_address(addr)
|
||||
return ('[{}]' if addr.version == 6 else '{}').format(addr)
|
||||
|
|
|
@ -768,6 +768,12 @@ class TestDaemon(object):
|
|||
}
|
||||
master_opts['ext_pillar'].append({'file_tree': file_tree})
|
||||
|
||||
# Config settings to test `event_return`
|
||||
if 'returner_dirs' not in master_opts:
|
||||
master_opts['returner_dirs'] = []
|
||||
master_opts['returner_dirs'].append(os.path.join(RUNTIME_VARS.FILES, 'returners'))
|
||||
master_opts['event_return'] = 'runtests_noop'
|
||||
|
||||
# Under windows we can't seem to properly create a virtualenv off of another
|
||||
# virtualenv, we can on linux but we will still point to the virtualenv binary
|
||||
# outside the virtualenv running the test suite, if that's the case.
|
||||
|
@ -884,10 +890,10 @@ class TestDaemon(object):
|
|||
}
|
||||
master_opts['file_roots'] = syndic_master_opts['file_roots'] = {
|
||||
'base': [
|
||||
os.path.join(FILES, 'file', 'base'),
|
||||
# Let's support runtime created files that can be used like:
|
||||
# salt://my-temp-file.txt
|
||||
RUNTIME_VARS.TMP_STATE_TREE
|
||||
RUNTIME_VARS.TMP_STATE_TREE,
|
||||
os.path.join(FILES, 'file', 'base'),
|
||||
],
|
||||
# Alternate root to test __env__ choices
|
||||
'prod': [
|
||||
|
@ -897,10 +903,10 @@ class TestDaemon(object):
|
|||
}
|
||||
minion_opts['file_roots'] = {
|
||||
'base': [
|
||||
os.path.join(FILES, 'file', 'base'),
|
||||
# Let's support runtime created files that can be used like:
|
||||
# salt://my-temp-file.txt
|
||||
RUNTIME_VARS.TMP_STATE_TREE
|
||||
RUNTIME_VARS.TMP_STATE_TREE,
|
||||
os.path.join(FILES, 'file', 'base'),
|
||||
],
|
||||
# Alternate root to test __env__ choices
|
||||
'prod': [
|
||||
|
|
|
@ -75,3 +75,63 @@ class BatchTest(ShellCase):
|
|||
timeout=self.run_timeout,
|
||||
)
|
||||
self.assertEqual(cmd[-1], 2)
|
||||
|
||||
# Test for failhard + batch. The best possible solution here was to do something like that:
|
||||
# assertRaises(StopIteration)
|
||||
# But it's impossible due to nature of the tests execution via fork()
|
||||
|
||||
def test_batch_module_stopping_after_error(self):
|
||||
'''
|
||||
Test that a failed command stops the batch run
|
||||
'''
|
||||
|
||||
minions_list = []
|
||||
retcode = None
|
||||
|
||||
# Executing salt with batch: 1 and with failhard. It should stop after the first error.
|
||||
cmd = self.run_salt(
|
||||
'"*minion" test.retcode 42 -b 1 --out=yaml --failhard',
|
||||
timeout=self.run_timeout,
|
||||
)
|
||||
|
||||
# Parsing the output. Idea is to fetch number on minions and retcode of the execution.
|
||||
# retcode var could be overwritten in case of broken failhard but number of minions check should still fail.
|
||||
for line in cmd:
|
||||
if line.startswith('Executing run on'):
|
||||
minions_list.append(line)
|
||||
if line.startswith('retcode'):
|
||||
retcode = line[-1]
|
||||
# We expect to have only one minion to be run
|
||||
self.assertEqual(1, len(minions_list))
|
||||
# We expect to find a retcode in the output
|
||||
self.assertIsNot(None, retcode)
|
||||
# We expect retcode to be non-zero
|
||||
self.assertNotEqual(0, retcode)
|
||||
|
||||
def test_batch_state_stopping_after_error(self):
|
||||
'''
|
||||
Test that a failed state stops the batch run
|
||||
'''
|
||||
|
||||
minions_list = []
|
||||
retcode = None
|
||||
|
||||
# Executing salt with batch: 1 and with failhard. It should stop after the first error.
|
||||
cmd = self.run_salt(
|
||||
'"*minion" state.single test.fail_without_changes name=test_me -b 1 --out=yaml --failhard',
|
||||
timeout=self.run_timeout,
|
||||
)
|
||||
|
||||
# Parsing the output. Idea is to fetch number on minions and retcode of the execution.
|
||||
# retcode var could be overwritten in case of broken failhard but number of minions check should still fail.
|
||||
for line in cmd:
|
||||
if line.startswith('Executing run on'):
|
||||
minions_list.append(line)
|
||||
if line.startswith('retcode'):
|
||||
retcode = line[-1]
|
||||
# We expect to have only one minion to be run
|
||||
self.assertEqual(1, len(minions_list))
|
||||
# We expect to find a retcode in the output
|
||||
self.assertIsNot(None, retcode)
|
||||
# We expect retcode to be non-zero
|
||||
self.assertNotEqual(0, retcode)
|
||||
|
|
5
tests/integration/files/file/base/issue-54755.sls
Normal file
5
tests/integration/files/file/base/issue-54755.sls
Normal file
|
@ -0,0 +1,5 @@
|
|||
issue-54755:
|
||||
file.managed:
|
||||
- name: {{ pillar['file_path'] }}
|
||||
- contents: issue-54755
|
||||
- unless: /bin/bash -c false
|
1
tests/integration/files/file/base/issue-54765-map.jinja
Normal file
1
tests/integration/files/file/base/issue-54765-map.jinja
Normal file
|
@ -0,0 +1 @@
|
|||
{% set defaults = {'foo': 'bar'} %}
|
6
tests/integration/files/file/base/issue-54765.sls
Normal file
6
tests/integration/files/file/base/issue-54765.sls
Normal file
|
@ -0,0 +1,6 @@
|
|||
{% from "issue-54765-map.jinja" import defaults with context %}
|
||||
|
||||
issue-54765:
|
||||
file.managed:
|
||||
- name: {{ pillar['file_path'] }}
|
||||
- contents: {{ defaults['foo'] }}
|
6
tests/integration/files/file/base/orch/batch.sls
Normal file
6
tests/integration/files/file/base/orch/batch.sls
Normal file
|
@ -0,0 +1,6 @@
|
|||
call_fail_state:
|
||||
salt.state:
|
||||
- tgt: '*minion'
|
||||
- batch: 1
|
||||
- failhard: True
|
||||
- sls: fail
|
38
tests/integration/files/returners/noop_returner.py
Normal file
38
tests/integration/files/returners/noop_returner.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
noop_returner
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
A returner that does nothing which is used to test the salt-master `event_return` functionality
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.jid
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__virtualname__ = 'runtests_noop'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
return True
|
||||
|
||||
|
||||
def event_return(events):
|
||||
log.debug('NOOP_RETURN.event_return - Events: %s', events)
|
||||
|
||||
|
||||
def returner(ret):
|
||||
log.debug('NOOP_RETURN.returner - Ret: %s', ret)
|
||||
|
||||
|
||||
def prep_jid(nocache=False, passed_jid=None): # pylint: disable=unused-argument
|
||||
'''
|
||||
Do any work necessary to prepare a JID, including sending a custom id
|
||||
'''
|
||||
return passed_jid if passed_jid is not None else salt.utils.jid.gen_jid(__opts__)
|
1
tests/integration/master/__init__.py
Normal file
1
tests/integration/master/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# -*- coding: utf-8 -*-
|
103
tests/integration/master/test_event_return.py
Normal file
103
tests/integration/master/test_event_return.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
tests.integration.master.test_event_return
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This test module is meant to cover the issue being fixed by:
|
||||
|
||||
https://github.com/saltstack/salt/pull/54731
|
||||
'''
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import TestCase
|
||||
from tests.support.paths import ScriptPathMixin
|
||||
from tests.support.helpers import get_unused_localhost_port
|
||||
from tests.support.mixins import AdaptedConfigurationTestCaseMixin
|
||||
|
||||
# Import 3rd-party libs
|
||||
from tests.support.processes import terminate_process
|
||||
|
||||
# Import Salt libs
|
||||
import salt.ext.six as six
|
||||
from salt.utils.nb_popen import NonBlockingPopen
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestEventReturn(AdaptedConfigurationTestCaseMixin, ScriptPathMixin, TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
overrides = {
|
||||
'publish_port': get_unused_localhost_port(),
|
||||
'ret_port': get_unused_localhost_port(),
|
||||
'tcp_master_pub_port': get_unused_localhost_port(),
|
||||
'tcp_master_pull_port': get_unused_localhost_port(),
|
||||
'tcp_master_publish_pull': get_unused_localhost_port(),
|
||||
'tcp_master_workers': get_unused_localhost_port(),
|
||||
'runtests_conn_check_port': get_unused_localhost_port(),
|
||||
'runtests_log_port': get_unused_localhost_port()
|
||||
}
|
||||
overrides['pytest_engine_port'] = overrides['runtests_conn_check_port']
|
||||
temp_config = AdaptedConfigurationTestCaseMixin.get_temp_config('master', **overrides)
|
||||
cls.root_dir = temp_config['root_dir']
|
||||
cls.config_dir = os.path.dirname(temp_config['conf_file'])
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
shutil.rmtree(cls.root_dir)
|
||||
cls.root_dir = cls.config_dir = None
|
||||
|
||||
def test_master_startup(self):
|
||||
proc = NonBlockingPopen(
|
||||
[
|
||||
self.get_script_path('master'),
|
||||
'-c',
|
||||
self.config_dir,
|
||||
'-l',
|
||||
'info'
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
out = six.b('')
|
||||
err = six.b('')
|
||||
|
||||
# Testing this should never be longer than 1 minute
|
||||
max_time = time.time() + 60
|
||||
try:
|
||||
while True:
|
||||
if time.time() > max_time:
|
||||
assert False, 'Max timeout ocurred'
|
||||
time.sleep(0.5)
|
||||
_out = proc.recv()
|
||||
_err = proc.recv_err()
|
||||
if _out:
|
||||
out += _out
|
||||
if _err:
|
||||
err += _err
|
||||
|
||||
if six.b('DeprecationWarning: object() takes no parameters') in out:
|
||||
self.fail('\'DeprecationWarning: object() takes no parameters\' was seen in output')
|
||||
|
||||
if six.b('TypeError: object() takes no parameters') in out:
|
||||
self.fail('\'TypeError: object() takes no parameters\' was seen in output')
|
||||
|
||||
if six.b('Setting up the master communication server') in out:
|
||||
# We got past the place we need, stop the process
|
||||
break
|
||||
|
||||
if out is None and err is None:
|
||||
break
|
||||
|
||||
if proc.poll() is not None:
|
||||
break
|
||||
finally:
|
||||
terminate_process(proc.pid, kill_children=True)
|
|
@ -15,7 +15,7 @@ import time
|
|||
from tests.support.case import ModuleCase
|
||||
from tests.support.helpers import with_tempdir, flaky
|
||||
from tests.support.unit import skipIf
|
||||
from tests.support.paths import BASE_FILES, TMP, TMP_PILLAR_TREE
|
||||
from tests.support.paths import BASE_FILES, TMP, TMP_PILLAR_TREE, TMP_STATE_TREE
|
||||
from tests.support.mixins import SaltReturnAssertsMixin
|
||||
|
||||
# Import Salt libs
|
||||
|
@ -118,6 +118,21 @@ class StateModuleTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertTrue(isinstance(states, list))
|
||||
self.assertTrue(isinstance(states[0], six.string_types))
|
||||
|
||||
def test_show_states_missing_sls(self):
|
||||
'''
|
||||
Test state.show_states with a sls file
|
||||
defined in a top file is missing
|
||||
'''
|
||||
with salt.utils.files.fopen(os.path.join(TMP_STATE_TREE, 'top.sls'), 'w') as top_file:
|
||||
top_file.write(textwrap.dedent('''\
|
||||
base:
|
||||
'*':
|
||||
- doesnotexist
|
||||
'''))
|
||||
states = self.run_function('state.show_states')
|
||||
assert isinstance(states, list)
|
||||
assert states == ["No matching sls found for 'doesnotexist' in env 'base'"]
|
||||
|
||||
def test_catch_recurse(self):
|
||||
'''
|
||||
state.show_sls used to catch a recursive ref
|
||||
|
@ -2065,9 +2080,14 @@ class StateModuleTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertEqual(_expected, ret[key]['changes']['stdout'])
|
||||
|
||||
def tearDown(self):
|
||||
nonbase_file = os.path.join(TMP, 'nonbase_env')
|
||||
if os.path.isfile(nonbase_file):
|
||||
os.remove(nonbase_file)
|
||||
rm_files = [os.path.join(TMP, 'nonbase_env'),
|
||||
os.path.join(TMP, 'testfile'),
|
||||
os.path.join(TMP, 'test.txt'),
|
||||
os.path.join(TMP_STATE_TREE, 'top.sls')]
|
||||
|
||||
for file_ in rm_files:
|
||||
if os.path.isfile(file_):
|
||||
os.remove(file_)
|
||||
|
||||
# remove old pillar data
|
||||
for filename in os.listdir(TMP_PILLAR_TREE):
|
||||
|
@ -2075,16 +2095,6 @@ class StateModuleTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.run_function('saltutil.refresh_pillar')
|
||||
self.run_function('test.sleep', [5])
|
||||
|
||||
# remove testfile added in core.sls state file
|
||||
state_file = os.path.join(TMP, 'testfile')
|
||||
if os.path.isfile(state_file):
|
||||
os.remove(state_file)
|
||||
|
||||
# remove testfile added in issue-30161.sls state file
|
||||
state_file = os.path.join(TMP, 'test.txt')
|
||||
if os.path.isfile(state_file):
|
||||
os.remove(state_file)
|
||||
|
||||
def test_state_sls_integer_name(self):
|
||||
'''
|
||||
This tests the case where the state file is named
|
||||
|
|
33
tests/integration/renderers/test_jinja.py
Normal file
33
tests/integration/renderers/test_jinja.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import os
|
||||
|
||||
import salt.utils.files
|
||||
|
||||
from tests.support.case import ModuleCase, ShellCase
|
||||
from tests.support.helpers import with_tempdir
|
||||
|
||||
|
||||
class JinjaRendererTest(ModuleCase):
|
||||
|
||||
@with_tempdir()
|
||||
def test_issue_54765(self, tmpdir):
|
||||
file_path = os.path.join(tmpdir, 'issue-54765')
|
||||
ret = self.run_function('state.sls', mods='issue-54765', pillar={'file_path': file_path})
|
||||
key = 'file_|-issue-54765_|-{}_|-managed'.format(file_path)
|
||||
assert key in ret
|
||||
assert ret[key]['result'] is True
|
||||
with salt.utils.files.fopen(file_path, 'r') as fp:
|
||||
assert fp.read().strip() == 'bar'
|
||||
|
||||
|
||||
class JinjaRenderCallTest(ShellCase):
|
||||
|
||||
@with_tempdir()
|
||||
def test_issue_54765(self, tmpdir):
|
||||
file_path = os.path.join(tmpdir, 'issue-54765')
|
||||
pillar_str = '\'{{"file_path": "{}"}}\''.format(file_path)
|
||||
ret = self.run_call('state.apply issue-54765 pillar={}'.format(pillar_str), local=True)
|
||||
assert ' Result: True' in ret
|
||||
with salt.utils.files.fopen(file_path, 'r') as fp:
|
||||
assert fp.read().strip() == 'bar'
|
32
tests/integration/returners/test_noop_return.py
Normal file
32
tests/integration/returners/test_noop_return.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
tests.integration.returners.test_noop_return
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This test module is meant to cover the issue being fixed by:
|
||||
|
||||
https://github.com/saltstack/salt/pull/54731
|
||||
'''
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.unit import skipIf
|
||||
from tests.support.helpers import TestsLoggingHandler
|
||||
|
||||
# Import 3rd-party tests
|
||||
import salt.ext.six as six
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@skipIf(six.PY3, 'Runtest Log Hander Disabled for PY3, #41836')
|
||||
class TestEventReturn(ModuleCase):
|
||||
|
||||
def test_noop_return(self):
|
||||
with TestsLoggingHandler(format='%(message)s', level=logging.DEBUG) as handler:
|
||||
self.run_function('test.ping')
|
||||
assert any('NOOP_RETURN' in s for s in handler.messages) is True, 'NOOP_RETURN not found in log messages'
|
|
@ -242,6 +242,32 @@ class StateRunnerTest(ShellCase):
|
|||
for item in out:
|
||||
assert item in ret
|
||||
|
||||
def test_orchestrate_batch_with_failhard_error(self):
|
||||
'''
|
||||
test orchestration properly stops with failhard and batch.
|
||||
'''
|
||||
ret = self.run_run('state.orchestrate orch.batch --out=json -l critical')
|
||||
ret_json = salt.utils.json.loads('\n'.join(ret))
|
||||
retcode = ret_json['retcode']
|
||||
result = ret_json['data']['master']['salt_|-call_fail_state_|-call_fail_state_|-state']['result']
|
||||
changes = ret_json['data']['master']['salt_|-call_fail_state_|-call_fail_state_|-state']['changes']
|
||||
|
||||
# Looks like there is a platform differences in execution.
|
||||
# I see empty changes dict in MacOS for some reason. Maybe it's a bug?
|
||||
if changes:
|
||||
changes_ret = changes['ret']
|
||||
|
||||
# Debug
|
||||
print('Retcode: {}'.format(retcode))
|
||||
print('Changes: {}'.format(changes))
|
||||
print('Result: {}'.format(result))
|
||||
|
||||
assert retcode != 0
|
||||
assert result is False
|
||||
if changes:
|
||||
# The execution should stop after first error, so return dict should contain only one minion
|
||||
assert len(changes_ret) == 1
|
||||
|
||||
def test_state_event(self):
|
||||
'''
|
||||
test to ensure state.event
|
||||
|
|
|
@ -506,6 +506,9 @@ class SchedulerEvalTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertNotIn('_last_run', ret)
|
||||
self.assertEqual(ret['_skip_reason'], 'disabled')
|
||||
|
||||
# Ensure job data still matches
|
||||
self.assertEqual(ret, job['schedule'][job_name])
|
||||
|
||||
def test_eval_global_disabled_job_enabled(self):
|
||||
'''
|
||||
verify that scheduled job does not run
|
||||
|
@ -532,6 +535,9 @@ class SchedulerEvalTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
self.assertNotIn('_last_run', ret)
|
||||
self.assertEqual(ret['_skip_reason'], 'disabled')
|
||||
|
||||
# Ensure job is still enabled
|
||||
self.assertEqual(ret['enabled'], True)
|
||||
|
||||
def test_eval_run_on_start(self):
|
||||
'''
|
||||
verify that scheduled job is run when minion starts
|
||||
|
|
73
tests/integration/scheduler/test_run_job.py
Normal file
73
tests/integration/scheduler/test_run_job.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.mixins import SaltReturnAssertsMixin
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.mock import MagicMock, patch
|
||||
import tests.integration as integration
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.schedule
|
||||
import salt.utils.platform
|
||||
|
||||
from salt.modules.test import ping as ping
|
||||
|
||||
try:
|
||||
import croniter # pylint: disable=W0611
|
||||
HAS_CRONITER = True
|
||||
except ImportError:
|
||||
HAS_CRONITER = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
ROOT_DIR = os.path.join(integration.TMP, 'schedule-unit-tests')
|
||||
SOCK_DIR = os.path.join(ROOT_DIR, 'test-socks')
|
||||
|
||||
DEFAULT_CONFIG = salt.config.minion_config(None)
|
||||
DEFAULT_CONFIG['conf_dir'] = ROOT_DIR
|
||||
DEFAULT_CONFIG['root_dir'] = ROOT_DIR
|
||||
DEFAULT_CONFIG['sock_dir'] = SOCK_DIR
|
||||
DEFAULT_CONFIG['pki_dir'] = os.path.join(ROOT_DIR, 'pki')
|
||||
DEFAULT_CONFIG['cachedir'] = os.path.join(ROOT_DIR, 'cache')
|
||||
|
||||
|
||||
class SchedulerRunJobTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
'''
|
||||
Validate the pkg module
|
||||
'''
|
||||
def setUp(self):
|
||||
with patch('salt.utils.schedule.clean_proc_dir', MagicMock(return_value=None)):
|
||||
functions = {'test.ping': ping}
|
||||
self.schedule = salt.utils.schedule.Schedule(copy.deepcopy(DEFAULT_CONFIG), functions, returners={})
|
||||
self.schedule.opts['loop_interval'] = 1
|
||||
|
||||
def tearDown(self):
|
||||
self.schedule.reset()
|
||||
|
||||
def test_run_job(self):
|
||||
'''
|
||||
verify that scheduled job runs
|
||||
'''
|
||||
job_name = 'test_run_job'
|
||||
job = {
|
||||
'schedule': {
|
||||
job_name: {
|
||||
'function': 'test.ping',
|
||||
}
|
||||
}
|
||||
}
|
||||
# Add the job to the scheduler
|
||||
self.schedule.opts.update(job)
|
||||
|
||||
# Run job
|
||||
self.schedule.run_job(job_name)
|
||||
ret = self.schedule.job_status(job_name)
|
||||
expected = {'function': 'test.ping', 'run': True, 'name': 'test_run_job'}
|
||||
self.assertEqual(ret, expected)
|
|
@ -598,3 +598,30 @@ class PipStateTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
shutil.rmtree(ographite, ignore_errors=True)
|
||||
if os.path.isdir(venv_dir):
|
||||
shutil.rmtree(venv_dir)
|
||||
|
||||
|
||||
class PipStateInRequisiteTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
|
||||
@with_tempdir()
|
||||
def test_issue_54755(self, tmpdir):
|
||||
'''
|
||||
Verify github issue 54755 is resolved. This only fails when there is no
|
||||
pip module in the python environment. Since the test suite normally has
|
||||
a pip module this test will pass and is here for posterity. See also
|
||||
|
||||
unit.states.test_pip_state.PipStateUtilsTest.test_pip_purge_method_with_pip
|
||||
|
||||
and
|
||||
|
||||
unit.states.test_pip_state.PipStateUtilsTest.test_pip_purge_method_without_pip
|
||||
|
||||
Which also validate this issue and will pass/fail regardless of whether
|
||||
or not pip is installed.
|
||||
'''
|
||||
file_path = os.path.join(tmpdir, 'issue-54755')
|
||||
ret = self.run_function('state.sls', mods='issue-54755', pillar={'file_path': file_path})
|
||||
key = 'file_|-issue-54755_|-{}_|-managed'.format(file_path)
|
||||
assert key in ret
|
||||
assert ret[key]['result'] is True
|
||||
with salt.utils.files.fopen(file_path, 'r') as fp:
|
||||
assert fp.read().strip() == 'issue-54755'
|
||||
|
|
132
tests/unit/cloud/clouds/test_openstack.py
Normal file
132
tests/unit/cloud/clouds/test_openstack.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: `Tyler Johnson <tjohnson@saltstack.com>`
|
||||
|
||||
tests.unit.cloud.clouds.openstack_test
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.cloud.clouds import openstack
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch
|
||||
|
||||
|
||||
class MockImage(object):
|
||||
name = 'image name'
|
||||
id = 'image id'
|
||||
|
||||
|
||||
class MockNode(object):
|
||||
name = 'node name'
|
||||
id = 'node id'
|
||||
flavor = MockImage()
|
||||
status = 'node status'
|
||||
|
||||
def __init__(self, image):
|
||||
self.image = image
|
||||
|
||||
def __iter__(self):
|
||||
return iter(())
|
||||
|
||||
|
||||
class MockConn(object):
|
||||
def __init__(self, image):
|
||||
self.node = MockNode(image)
|
||||
|
||||
def get_image(self, *args, **kwargs):
|
||||
return self.node.image
|
||||
|
||||
def get_flavor(self, *args, **kwargs):
|
||||
return self.node.flavor
|
||||
|
||||
def get_server(self, *args, **kwargs):
|
||||
return self.node
|
||||
|
||||
def list_servers(self, *args, **kwargs):
|
||||
return [self.node]
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class OpenstackTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'''
|
||||
Unit TestCase for salt.cloud.clouds.openstack module.
|
||||
'''
|
||||
|
||||
def setup_loader_modules(self):
|
||||
return {
|
||||
openstack: {
|
||||
'__active_provider_name__': '',
|
||||
'__opts__': {
|
||||
'providers': {
|
||||
'my-openstack-cloud': {
|
||||
'openstack': {
|
||||
'auth': 'daenerys',
|
||||
'region_name': 'westeros',
|
||||
'cloud': 'openstack',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def test_get_configured_provider_bad(self):
|
||||
with patch.dict(openstack.__opts__, {'providers': {}}):
|
||||
result = openstack.get_configured_provider()
|
||||
self.assertEqual(result, False)
|
||||
|
||||
def test_get_configured_provider_auth(self):
|
||||
config = {
|
||||
'region_name': 'westeros',
|
||||
'auth': 'daenerys',
|
||||
}
|
||||
with patch.dict(openstack.__opts__, {'providers': {'my-openstack-cloud': {'openstack': config}}}):
|
||||
result = openstack.get_configured_provider()
|
||||
self.assertEqual(config, result)
|
||||
|
||||
def test_get_configured_provider_cloud(self):
|
||||
config = {
|
||||
'region_name': 'westeros',
|
||||
'cloud': 'foo',
|
||||
}
|
||||
with patch.dict(openstack.__opts__, {'providers': {'my-openstack-cloud': {'openstack': config}}}):
|
||||
result = openstack.get_configured_provider()
|
||||
self.assertEqual(config, result)
|
||||
|
||||
def test_get_dependencies(self):
|
||||
HAS_SHADE = (True, 'Please install newer version of shade: >= 1.19.0')
|
||||
with patch('salt.cloud.clouds.openstack.HAS_SHADE', HAS_SHADE):
|
||||
result = openstack.get_dependencies()
|
||||
self.assertEqual(result, True)
|
||||
|
||||
def test_get_dependencies_no_shade(self):
|
||||
HAS_SHADE = (False, 'Install pypi module shade >= 1.19.0')
|
||||
with patch('salt.cloud.clouds.openstack.HAS_SHADE', HAS_SHADE):
|
||||
result = openstack.get_dependencies()
|
||||
self.assertEqual(result, False)
|
||||
|
||||
def test_list_nodes_full_image_str(self):
|
||||
node_image = 'node image'
|
||||
conn = MockConn(node_image)
|
||||
with patch('salt.cloud.clouds.openstack._get_ips', return_value=[]):
|
||||
ret = openstack.list_nodes_full(conn=conn)
|
||||
self.assertEqual(ret[conn.node.name]['image'], node_image)
|
||||
|
||||
def test_list_nodes_full_image_obj(self):
|
||||
conn = MockConn(MockImage())
|
||||
with patch('salt.cloud.clouds.openstack._get_ips', return_value=[]):
|
||||
ret = openstack.list_nodes_full(conn=conn)
|
||||
self.assertEqual(ret[conn.node.name]['image'], MockImage.name)
|
||||
|
||||
def test_show_instance(self):
|
||||
conn = MockConn(MockImage())
|
||||
with patch('salt.cloud.clouds.openstack._get_ips', return_value=[]):
|
||||
ret = openstack.show_instance(conn.node.name, conn=conn, call='action')
|
||||
self.assertEqual(ret['image'], MockImage.name)
|
|
@ -150,14 +150,14 @@ class ScheduleTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
Test if it run a scheduled job on the minion immediately.
|
||||
'''
|
||||
with patch.dict(schedule.__opts__, {'schedule': {}, 'sock_dir': SOCK_DIR}):
|
||||
with patch.dict(schedule.__opts__, {'schedule': {'job1': JOB1}, 'sock_dir': SOCK_DIR}):
|
||||
mock = MagicMock(return_value=True)
|
||||
with patch.dict(schedule.__salt__, {'event.fire': mock}):
|
||||
_ret_value = {'complete': True, 'schedule': {}}
|
||||
_ret_value = {'complete': True, 'schedule': {'job1': JOB1}}
|
||||
with patch.object(SaltEvent, 'get_event', return_value=_ret_value):
|
||||
self.assertDictEqual(schedule.run_job('job1'),
|
||||
{'comment': 'Job job1 does not exist.',
|
||||
'result': False})
|
||||
{'comment': 'Scheduling Job job1 on minion.',
|
||||
'result': True})
|
||||
|
||||
# 'enable_job' function tests: 1
|
||||
|
||||
|
|
|
@ -632,6 +632,19 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
|
|||
self.assertEqual(state.show_low_sls("foo"), "A")
|
||||
self.assertListEqual(state.show_states("foo"), ['abc'])
|
||||
|
||||
def test_show_states_missing_sls(self):
|
||||
'''
|
||||
Test state.show_states when a sls file defined
|
||||
in a top.sls file is missing
|
||||
'''
|
||||
msg = ["No matching sls found for 'cloud' in evn 'base'"]
|
||||
chunks_mock = MagicMock(side_effect=[msg])
|
||||
mock = MagicMock(side_effect=["A", None])
|
||||
with patch.object(state, '_check_queue', mock),\
|
||||
patch('salt.state.HighState.compile_low_chunks', chunks_mock):
|
||||
self.assertEqual(state.show_low_sls("foo"), "A")
|
||||
self.assertListEqual(state.show_states("foo"), [msg[0]])
|
||||
|
||||
def test_sls_id(self):
|
||||
'''
|
||||
Test to call a single ID from the
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.mixins import LoaderModuleMockMixin, SaltReturnAssertsMixin
|
||||
|
@ -282,3 +283,30 @@ class PipStateTest(TestCase, SaltReturnAssertsMixin, LoaderModuleMockMixin):
|
|||
'successfully installed',
|
||||
{'test': ret}
|
||||
)
|
||||
|
||||
|
||||
class PipStateUtilsTest(TestCase):
|
||||
|
||||
def test_has_internal_exceptions_mod_function(self):
|
||||
assert pip_state.pip_has_internal_exceptions_mod('10.0')
|
||||
assert pip_state.pip_has_internal_exceptions_mod('18.1')
|
||||
assert not pip_state.pip_has_internal_exceptions_mod('9.99')
|
||||
|
||||
def test_has_exceptions_mod_function(self):
|
||||
assert pip_state.pip_has_exceptions_mod('1.0')
|
||||
assert not pip_state.pip_has_exceptions_mod('0.1')
|
||||
assert not pip_state.pip_has_exceptions_mod('10.0')
|
||||
|
||||
def test_pip_purge_method_with_pip(self):
|
||||
mock_modules = sys.modules.copy()
|
||||
mock_modules.pop('pip', None)
|
||||
mock_modules['pip'] = object()
|
||||
with patch('sys.modules', mock_modules):
|
||||
pip_state.purge_pip()
|
||||
assert 'pip' not in mock_modules
|
||||
|
||||
def test_pip_purge_method_without_pip(self):
|
||||
mock_modules = sys.modules.copy()
|
||||
mock_modules.pop('pip', None)
|
||||
with patch('sys.modules', mock_modules):
|
||||
pip_state.purge_pip()
|
||||
|
|
|
@ -282,6 +282,29 @@ class MinionTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
finally:
|
||||
minion.destroy()
|
||||
|
||||
def test_when_ping_interval_is_set_the_callback_should_be_added_to_periodic_callbacks(self):
|
||||
with patch('salt.minion.Minion.ctx', MagicMock(return_value={})), \
|
||||
patch('salt.minion.Minion.sync_connect_master', MagicMock(side_effect=RuntimeError('stop execution'))), \
|
||||
patch('salt.utils.process.SignalHandlingMultiprocessingProcess.start', MagicMock(return_value=True)), \
|
||||
patch('salt.utils.process.SignalHandlingMultiprocessingProcess.join', MagicMock(return_value=True)):
|
||||
mock_opts = self.get_config('minion', from_scratch=True)
|
||||
mock_opts['ping_interval'] = 10
|
||||
io_loop = tornado.ioloop.IOLoop()
|
||||
io_loop.make_current()
|
||||
minion = salt.minion.Minion(mock_opts, io_loop=io_loop)
|
||||
try:
|
||||
try:
|
||||
minion.connected = MagicMock(side_effect=(False, True))
|
||||
minion._fire_master_minion_start = MagicMock()
|
||||
minion.tune_in(start=False)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
# Make sure the scheduler is initialized but the beacons are not
|
||||
self.assertTrue('ping' in minion.periodic_callbacks)
|
||||
finally:
|
||||
minion.destroy()
|
||||
|
||||
def test_minion_retry_dns_count(self):
|
||||
'''
|
||||
Tests that the resolve_dns will retry dns look ups for a maximum of
|
||||
|
|
|
@ -132,6 +132,7 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
'integration.loader.test_ext_grains',
|
||||
'integration.loader.test_ext_modules',
|
||||
'integration.logging.test_jid_logging',
|
||||
'integration.master.test_event_return',
|
||||
'integration.minion.test_blackout',
|
||||
'integration.minion.test_pillar',
|
||||
'integration.minion.test_timeout',
|
||||
|
@ -147,6 +148,7 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
'integration.proxy.test_shell',
|
||||
'integration.proxy.test_simple',
|
||||
'integration.reactor.test_reactor',
|
||||
'integration.returners.test_noop_return',
|
||||
'integration.runners.test_runner_returns',
|
||||
'integration.scheduler.test_error',
|
||||
'integration.scheduler.test_eval',
|
||||
|
@ -154,6 +156,7 @@ class BadTestModuleNamesTestCase(TestCase):
|
|||
'integration.scheduler.test_skip',
|
||||
'integration.scheduler.test_maxrunning',
|
||||
'integration.scheduler.test_helpers',
|
||||
'integration.scheduler.test_run_job',
|
||||
'integration.shell.test_spm',
|
||||
'integration.shell.test_cp',
|
||||
'integration.shell.test_syndic',
|
||||
|
|
|
@ -12,6 +12,7 @@ from __future__ import absolute_import, unicode_literals, print_function
|
|||
import os
|
||||
import hashlib
|
||||
import time
|
||||
import warnings
|
||||
from tornado.testing import AsyncTestCase
|
||||
import zmq
|
||||
import zmq.eventloop.ioloop
|
||||
|
@ -25,6 +26,7 @@ from multiprocessing import Process
|
|||
from tests.support.unit import expectedFailure, skipIf, TestCase
|
||||
|
||||
# Import salt libs
|
||||
import salt.config
|
||||
import salt.utils.event
|
||||
import salt.utils.stringutils
|
||||
import tests.integration as integration
|
||||
|
@ -32,6 +34,7 @@ from salt.utils.process import clean_proc
|
|||
|
||||
# Import 3rd-+arty libs
|
||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||
from tests.support.processes import terminate_process
|
||||
|
||||
SOCK_DIR = os.path.join(integration.TMP, 'test-socks')
|
||||
|
||||
|
@ -366,3 +369,27 @@ class TestAsyncEventPublisher(AsyncTestCase):
|
|||
self.assertEqual(self.tag, 'evt1')
|
||||
self.data.pop('_stamp') # drop the stamp
|
||||
self.assertEqual(self.data, {'data': 'foo1'})
|
||||
|
||||
|
||||
class TestEventReturn(TestCase):
|
||||
|
||||
def test_event_return(self):
|
||||
# Once salt is py3 only, the warnings part of this test no longer applies
|
||||
evt = None
|
||||
try:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
evt = None
|
||||
try:
|
||||
evt = salt.utils.event.EventReturn(salt.config.DEFAULT_MASTER_OPTS.copy())
|
||||
evt.start()
|
||||
except TypeError as exc:
|
||||
if 'object' in str(exc):
|
||||
self.fail('\'{}\' TypeError should have not been raised'.format(exc))
|
||||
for warning in w:
|
||||
if warning.category is DeprecationWarning:
|
||||
assert 'object() takes no parameters' not in warning.message
|
||||
finally:
|
||||
if evt is not None:
|
||||
terminate_process(evt.pid, kill_children=True)
|
||||
|
|
|
@ -11,6 +11,7 @@ from tests.support.unit import TestCase
|
|||
from tests.support.mock import (
|
||||
MagicMock,
|
||||
mock_open,
|
||||
create_autospec,
|
||||
patch,
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
|
@ -18,6 +19,7 @@ from tests.support.mock import (
|
|||
|
||||
# Import salt libs
|
||||
import salt.utils.network as network
|
||||
import salt.exceptions
|
||||
from salt._compat import ipaddress
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -248,25 +250,6 @@ class NetworkTestCase(TestCase):
|
|||
raise _e_
|
||||
|
||||
def test_dns_check(self):
|
||||
class MockSocket(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def setsockopt(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def sendto(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def connect(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def close(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
hosts = [
|
||||
{'host': '10.10.0.3',
|
||||
'port': '',
|
||||
|
@ -279,22 +262,71 @@ class NetworkTestCase(TestCase):
|
|||
{'host': '2001:0db8:85a3::8a2e:0370:7334',
|
||||
'port': '',
|
||||
'mocked': [(10, 1, 6, '', ('2001:db8:85a3::8a2e:370:7334', 0, 0, 0))],
|
||||
'ret': '2001:db8:85a3::8a2e:370:7334'},
|
||||
'ret': '[2001:db8:85a3::8a2e:370:7334]'},
|
||||
{'host': '2001:0db8:85a3::8a2e:370:7334',
|
||||
'port': '1234',
|
||||
'mocked': [(10, 1, 6, '', ('2001:db8:85a3::8a2e:370:7334', 0, 0, 0))],
|
||||
'ret': '2001:db8:85a3::8a2e:370:7334'},
|
||||
'ret': '[2001:db8:85a3::8a2e:370:7334]'},
|
||||
{'host': 'salt-master',
|
||||
'port': '1234',
|
||||
'mocked': [(2, 1, 6, '', ('127.0.0.1', 0))],
|
||||
'ret': '127.0.0.1'},
|
||||
]
|
||||
for host in hosts:
|
||||
with patch.object(socket, 'getaddrinfo', MagicMock(return_value=host['mocked'])):
|
||||
with patch('socket.socket', MockSocket):
|
||||
with patch.object(socket, 'getaddrinfo', create_autospec(socket.getaddrinfo, return_value=host['mocked'])):
|
||||
with patch('socket.socket', create_autospec(socket.socket)):
|
||||
ret = network.dns_check(host['host'], host['port'])
|
||||
self.assertEqual(ret, host['ret'])
|
||||
|
||||
def test_dns_check_ipv6_filter(self):
|
||||
# raise exception to skip everything after the getaddrinfo call
|
||||
with patch.object(socket, 'getaddrinfo',
|
||||
create_autospec(socket.getaddrinfo, side_effect=Exception)) as getaddrinfo:
|
||||
for ipv6, param in [
|
||||
(None, socket.AF_UNSPEC),
|
||||
(True, socket.AF_INET6),
|
||||
(False, socket.AF_INET),
|
||||
]:
|
||||
with self.assertRaises(Exception):
|
||||
network.dns_check('foo', '1', ipv6=ipv6)
|
||||
getaddrinfo.assert_called_with('foo', '1', param, socket.SOCK_STREAM)
|
||||
|
||||
def test_dns_check_errors(self):
|
||||
with patch.object(socket, 'getaddrinfo', create_autospec(socket.getaddrinfo, return_value=[])):
|
||||
with self.assertRaisesRegex(salt.exceptions.SaltSystemExit,
|
||||
"DNS lookup or connection check of 'foo' failed"):
|
||||
network.dns_check('foo', '1')
|
||||
|
||||
with patch.object(socket, 'getaddrinfo', create_autospec(socket.getaddrinfo, side_effect=TypeError)):
|
||||
with self.assertRaisesRegex(salt.exceptions.SaltSystemExit,
|
||||
"Invalid or unresolveable address"):
|
||||
network.dns_check('foo', '1')
|
||||
|
||||
def test_test_addrs(self):
|
||||
# subset of real data from getaddrinfo against saltstack.com
|
||||
addrinfo = [(30, 2, 17, '', ('2600:9000:21eb:a800:8:1031:abc0:93a1', 0, 0, 0)),
|
||||
(30, 1, 6, '', ('2600:9000:21eb:a800:8:1031:abc0:93a1', 0, 0, 0)),
|
||||
(30, 2, 17, '', ('2600:9000:21eb:b400:8:1031:abc0:93a1', 0, 0, 0)),
|
||||
(30, 1, 6, '', ('2600:9000:21eb:b400:8:1031:abc0:93a1', 0, 0, 0)),
|
||||
(2, 1, 6, '', ('13.35.99.52', 0)), (2, 2, 17, '', ('13.35.99.85', 0)),
|
||||
(2, 1, 6, '', ('13.35.99.85', 0)), (2, 2, 17, '', ('13.35.99.122', 0))]
|
||||
with patch('socket.socket', create_autospec(socket.socket)) as s:
|
||||
# we connect to the first address
|
||||
addrs = network._test_addrs(addrinfo, 80)
|
||||
self.assertTrue(len(addrs) == 1)
|
||||
self.assertTrue(addrs[0] == addrinfo[0][4][0])
|
||||
|
||||
# the first lookup fails, succeeds on next check
|
||||
s.side_effect = [socket.error, MagicMock()]
|
||||
addrs = network._test_addrs(addrinfo, 80)
|
||||
self.assertTrue(len(addrs) == 1)
|
||||
self.assertTrue(addrs[0] == addrinfo[2][4][0])
|
||||
|
||||
# nothing can connect, but we've eliminated duplicates
|
||||
s.side_effect = socket.error
|
||||
addrs = network._test_addrs(addrinfo, 80)
|
||||
self.assertTrue(len(addrs) == 5)
|
||||
|
||||
def test_is_subnet(self):
|
||||
for subnet_data in (IPV4_SUBNETS, IPV6_SUBNETS):
|
||||
for item in subnet_data[True]:
|
||||
|
|
|
@ -6,6 +6,7 @@ Test salt.utils.zeromq
|
|||
# Import Python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
import zmq
|
||||
from salt._compat import ipaddress
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
|
@ -24,8 +25,13 @@ class UtilsTestCase(TestCase):
|
|||
def test_ip_bracket(self):
|
||||
test_ipv4 = '127.0.0.1'
|
||||
test_ipv6 = '::1'
|
||||
test_ipv6_uri = '[::1]'
|
||||
self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(test_ipv4))
|
||||
self.assertEqual('[{0}]'.format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6))
|
||||
self.assertEqual('[{0}]'.format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6_uri))
|
||||
|
||||
ip_addr_obj = ipaddress.ip_address(test_ipv4)
|
||||
self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(ip_addr_obj))
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(not hasattr(zmq, 'IPC_PATH_MAX_LEN'), "ZMQ does not have max length support.")
|
||||
|
|
Loading…
Add table
Reference in a new issue