Merge pull request #54918 from dwoz/2019.2.1-merge-master

2019.2.2 merge master
This commit is contained in:
Daniel Wozniak 2019-10-08 15:43:19 -07:00 committed by GitHub
commit aee25f6413
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
84 changed files with 8988 additions and 216 deletions

View file

@ -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

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

View file

@ -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
.

File diff suppressed because it is too large Load diff

View file

@ -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
.

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
'''
Metaproxy Directory
'''

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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):

View file

@ -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, '

View file

@ -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)

View file

@ -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': [

View file

@ -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)

View file

@ -0,0 +1,5 @@
issue-54755:
file.managed:
- name: {{ pillar['file_path'] }}
- contents: issue-54755
- unless: /bin/bash -c false

View file

@ -0,0 +1 @@
{% set defaults = {'foo': 'bar'} %}

View 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'] }}

View file

@ -0,0 +1,6 @@
call_fail_state:
salt.state:
- tgt: '*minion'
- batch: 1
- failhard: True
- sls: fail

View 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__)

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View 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)

View file

@ -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

View 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'

View 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'

View file

@ -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

View file

@ -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

View 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)

View file

@ -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'

View 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)

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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',

View file

@ -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)

View file

@ -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]:

View file

@ -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.")