diff --git a/README.rst b/README.rst index 9af2294c8478..a800d6633eb1 100644 --- a/README.rst +++ b/README.rst @@ -2,67 +2,108 @@ What is SaltStack? ================== -Salt is a new approach to infrastructure management. Easy enough to get -running in minutes, scalable enough to manage tens of thousands of servers, -and fast enough to communicate with them in *seconds*. - -Salt delivers a dynamic communication bus for infrastructures that can be used -for orchestration, remote execution, configuration management and much more. +SaltStack makes software for complex systems management at scale. +SaltStack is the company that created and maintains the Salt Open +project and develops and sells SaltStack Enterprise software, services +and support. Easy enough to get running in minutes, scalable enough to +manage tens of thousands of servers, and fast enough to communicate with +them in *seconds*. + +Salt is a new approach to infrastructure management built on a dynamic +communication bus. Salt can be used for data-driven orchestration, +remote execution for any infrastructure, configuration management for +any app stack, and much more. + +Download Salt Open +================== -Documentation -============= +Salt Open is tested and packaged to run on CentOS, Debian, RHEL, Ubuntu, +Windows. Download Salt Open and get started now. -Installation instructions, getting started guides, and in-depth API -documentation. +``_ -http://docs.saltstack.com +`Installation Instructions `_ -IRC Chat -======== +SaltStack Documentation +======================= -Join the vibrant, helpful and positive SaltStack chat room in Freenode at -#salt. There is no need to introduce yourself, or ask permission to join in, -just help and be helped! Make sure to wait for an answer, sometimes it may take -a few moments for someone to reply. +Installation instructions, getting started guides, and in-depth API +documentation. -http://webchat.freenode.net/?channels=salt&uio=Mj10cnVlJjk9dHJ1ZSYxMD10cnVl83 +``_ -Salt Air -======== +``_ -The SaltStack YouTube channel is filled with Salt videos and presentations. -Watch the latest Salt Air episodes for updates from Thomas on development, -catch tutorials, and stay on the cutting edge of Salt. +Get SaltStack Support and Help +============================== -http://www.youtube.com/user/saltstack +**IRC Chat** - Join the vibrant, helpful and positive SaltStack chat room in +Freenode at #salt. There is no need to introduce yourself, or ask permission to +join in, just help and be helped! Make sure to wait for an answer, sometimes it +may take a few moments for someone to reply. -Mailing List -============ + ``_ -The SaltStack community users mailing list is hosted by Google groups. Anyone -can post to ask questions about SaltStack products and anyone can help answer. -Join the conversation! +**Mailing List** - The SaltStack community users mailing list is hosted by +Google groups. Anyone can post to ask questions about SaltStack products and +anyone can help answer. Join the conversation! -https://groups.google.com/forum/#!forum/salt-users + ``_ You may subscribe to the list without a Google account by emailing salt-users+subscribe@googlegroups.com and you may post to the list by emailing salt-users@googlegroups.com -Developing Salt -=============== - -The Salt development team is welcoming, positive, and dedicated to helping -people get new code and fixes into SaltStack projects. Log into GitHub and get -started with one of the largest developer communities in the world. The following -links should get you started: +**Reporting Issues** - To report an issue with Salt, please follow the +guidelines for filing bug reports: +``_ -* https://github.com/saltstack -* http://docs.saltstack.com/en/latest/topics/development/index.html +**SaltStack Support** - If you need dedicated, prioritized support, please +consider a SaltStack Support package that fits your needs: +``_ -Reporting Issues +Engage SaltStack ================ -To report an issue with Salt, please follow the guidelines for filing bug reports: +`SaltConf`_, **User Groups and Meetups** - SaltStack has a vibrant and `global +community`_ of customers, users, developers and enthusiasts. Connect with other +Salted folks in your area of the world, or join `SaltConf16`_, the SaltStack +annual user conference, April 19-21 in Salt Lake City. Please let us know if +you would like to start a user group or if we should add your existing +SaltStack user group to this list by emailing: info@saltstack.com + +**SaltStack Training** - Get access to proprietary `SaltStack education +offerings`_ through instructor-led training offered on-site, virtually or at +SaltStack headquarters in Salt Lake City. SaltStack Enterprise training helps +increase the value and effectiveness of SaltStack software for any customer and +is a prerequisite for coveted `SaltStack Certified Engineer (SSCE)`_ status. +SaltStack training is also available through several `SaltStack professional +services`_ offerings. + +**Follow SaltStack on -** + +* YouTube - ``_ +* Twitter - ``_ +* Facebook - ``_ +* LinkedIn - ``_ +* LinkedIn Group - ``_ +* Google+ - ``_ + +.. _SaltConf: http://www.youtube.com/user/saltstack +.. _global community: http://www.meetup.com/pro/saltstack/ +.. _SaltConf16: http://saltconf.com/ +.. _SaltStack education offerings: http://saltstack.com/training/ +.. _SaltStack Certified Engineer (SSCE): http://saltstack.com/certification/ +.. _SaltStack professional services: http://saltstack.com/services/ + +Developing Salt +=============== + +The Salt development team is welcoming, positive, and dedicated to +helping people get new code and fixes into SaltStack projects. Log into +GitHub and get started with one of the largest developer communities in +the world. The following links should get you started: + +* ``_ +* ``_ -* http://docs.saltstack.com/en/develop/topics/development/reporting_bugs.html diff --git a/conf/proxy b/conf/proxy index 79b106c9601c..8c0dd1aff36a 100644 --- a/conf/proxy +++ b/conf/proxy @@ -13,7 +13,7 @@ #default_include: minion.d/*.conf # Backwards compatibility option for proxymodules created before 2015.8.2 -# This setting will default to 'False' in the Boron release +# This setting will default to 'False' in the 2016.3.0 release # Setting this to True adds proxymodules to the __opts__ dictionary. # This breaks several Salt features (basically anything that serializes # __opts__ over the wire) but retains backwards compatibility. diff --git a/doc/.tx/config b/doc/.tx/config index 9d2efc0892e3..125909f44f66 100644 --- a/doc/.tx/config +++ b/doc/.tx/config @@ -3014,12 +3014,6 @@ source_file = _build/locale/ref/clouds/all/index.pot source_lang = en source_name = ref/clouds/all/index.rst -[salt.ref--clouds--all--salt_cloud_clouds_botocore_aws] -file_filter = locale//LC_MESSAGES/ref/clouds/all/salt.cloud.clouds.botocore_aws.po -source_file = _build/locale/ref/clouds/all/salt.cloud.clouds.botocore_aws.pot -source_lang = en -source_name = ref/clouds/all/salt.cloud.clouds.botocore_aws.rst - [salt.ref--clouds--all--salt_cloud_clouds_cloudstack] file_filter = locale//LC_MESSAGES/ref/clouds/all/salt.cloud.clouds.cloudstack.po source_file = _build/locale/ref/clouds/all/salt.cloud.clouds.cloudstack.pot @@ -3056,12 +3050,6 @@ source_file = _build/locale/ref/clouds/all/salt.cloud.clouds.joyent.pot source_lang = en source_name = ref/clouds/all/salt.cloud.clouds.joyent.rst -[salt.ref--clouds--all--salt_cloud_clouds_libcloud_aws] -file_filter = locale//LC_MESSAGES/ref/clouds/all/salt.cloud.clouds.libcloud_aws.po -source_file = _build/locale/ref/clouds/all/salt.cloud.clouds.libcloud_aws.pot -source_lang = en -source_name = ref/clouds/all/salt.cloud.clouds.libcloud_aws.rst - [salt.ref--clouds--all--salt_cloud_clouds_linode] file_filter = locale//LC_MESSAGES/ref/clouds/all/salt.cloud.clouds.linode.po source_file = _build/locale/ref/clouds/all/salt.cloud.clouds.linode.pot diff --git a/doc/ref/clouds/all/index.rst b/doc/ref/clouds/all/index.rst index fc5f7dda83ad..604cc861b82a 100644 --- a/doc/ref/clouds/all/index.rst +++ b/doc/ref/clouds/all/index.rst @@ -11,7 +11,6 @@ Full list of Salt Cloud modules :template: autosummary.rst.tmpl aliyun - botocore_aws cloudstack digital_ocean dimensiondata @@ -19,7 +18,6 @@ Full list of Salt Cloud modules gce gogrid joyent - libcloud_aws linode lxc msazure diff --git a/doc/ref/clouds/all/salt.cloud.clouds.botocore_aws.rst b/doc/ref/clouds/all/salt.cloud.clouds.botocore_aws.rst deleted file mode 100644 index d32e08d42d5d..000000000000 --- a/doc/ref/clouds/all/salt.cloud.clouds.botocore_aws.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================== -salt.cloud.clouds.botocore_aws -============================== - -.. automodule:: salt.cloud.clouds.botocore_aws - :members: \ No newline at end of file diff --git a/doc/ref/clouds/all/salt.cloud.clouds.libcloud_aws.rst b/doc/ref/clouds/all/salt.cloud.clouds.libcloud_aws.rst deleted file mode 100644 index 7fd763ed263a..000000000000 --- a/doc/ref/clouds/all/salt.cloud.clouds.libcloud_aws.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================== -salt.cloud.clouds.libcloud_aws -============================== - -.. automodule:: salt.cloud.clouds.libcloud_aws - :members: \ No newline at end of file diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 665b3ec4b3d2..306b6d006c9f 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -216,7 +216,7 @@ The directory to store the pki authentication keys. ``extension_modules`` --------------------- -.. versionchanged:: Boron +.. versionchanged:: 2016.3.0 The default location for this directory has been moved. Prior to this version, the location was a directory named ``extmods`` in the Salt cachedir (on most platforms, ``/var/cache/salt/extmods``). It has been diff --git a/doc/ref/configuration/minion.rst b/doc/ref/configuration/minion.rst index 94593df7aed2..e47e3777696b 100644 --- a/doc/ref/configuration/minion.rst +++ b/doc/ref/configuration/minion.rst @@ -393,7 +393,7 @@ to enable set grains_cache to ``True``. ``grains_deep_merge`` --------------------- -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Default: ``False`` diff --git a/doc/ref/index.rst b/doc/ref/index.rst index f05a74351d3a..4ee823b1037b 100644 --- a/doc/ref/index.rst +++ b/doc/ref/index.rst @@ -1,39 +1,30 @@ -Reference -========= +===================== +Salt Module Reference +===================== + +This section contains a list of the Python modules that are used to extend the various subsystems within Salt. + .. toctree:: + :maxdepth: 1 :glob: - auth/all/index - cli/index - clientacl - clients/index - clouds/all/index - configuration/* - configuration/logging/* - configuration/logging/handlers/index - file_server/index - file_server/all/index - grains/all/index - internals/index - modules/all/index - netapi/all/index - output/all/index - peer - pillar/index - pillar/all/index - proxy/all/index - renderers/index - returners/index - roster/all/index - runners/index - states/index - states/all/index - modules/index - tops/index - tops/all/index - wheel/all/index - beacons/all/index - engines/all/index - sdb/all/index - serializers/all/index - queues/all/index + ../ref/auth/all/index + ../ref/beacons/all/index + ../ref/engines/all/index + ../ref/file_server/all/index + ../ref/grains/all/index + ../ref/modules/all/index + ../ref/netapi/all/index + ../ref/output/all/index + ../ref/pillar/all/index + ../ref/proxy/all/index + ../ref/queues/all/index + ../ref/renderers/all/index + ../ref/returners/all/index + ../ref/roster/all/index + ../ref/runners/all/index + ../ref/sdb/all/index + ../ref/serializers/all/index + ../ref/states/all/index + ../ref/tops/all/index + ../ref/wheel/all/index diff --git a/doc/ref/states/requisites.rst b/doc/ref/states/requisites.rst index 4e656175c7c1..155519f76675 100644 --- a/doc/ref/states/requisites.rst +++ b/doc/ref/states/requisites.rst @@ -101,9 +101,9 @@ first line in the stanza) or the ``- name`` parameter. Omitting state module in requisites ----------------------------------- -.. versionadded:: Boron +.. versionadded:: 2016.3.0 -In version Boron, the state module name was made optional. If the state module +In version 2016.3.0, the state module name was made optional. If the state module is omitted, all states matching the ID will be required, regardless of which module they are using. diff --git a/doc/topics/blackout/index.rst b/doc/topics/blackout/index.rst new file mode 100644 index 000000000000..a3d19950ec4a --- /dev/null +++ b/doc/topics/blackout/index.rst @@ -0,0 +1,26 @@ +.. _blackout: + +============================= +Minion Blackout Configuration +============================= + +.. versionadded:: 2016.3.0 + +Salt supports minion blackouts. When a minion is in blackout mode, all remote +execution commands are disabled. This allows production minions to be put +"on hold", eliminating the risk of an untimely configuration change. + +Minion blackouts are configured via a special pillar key, ``minion_blackout``. +If this key is set to ``True``, then the minion will reject all incoming +commands, except for ``saltutil.refresh_pillar``. (The exception is important, +so minions can be brought out of blackout mode) + +Salt also supports an explicit whitelist of additional functions that will be +allowed during blackout. This is configured with the special pillar key +``minion_blackout_whitelist``, which is formed as a list: + +.. code_block:: yaml + + minion_blackout_whitelist: + - test.ping + - pillar.get diff --git a/doc/topics/cloud/linode.rst b/doc/topics/cloud/linode.rst index 27f58155902c..de35c1e30f86 100644 --- a/doc/topics/cloud/linode.rst +++ b/doc/topics/cloud/linode.rst @@ -184,17 +184,17 @@ and price. Required. assign_private_ip ----------------- -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Assigns a private IP address to a Linode when set to True. Default is False. private_ip ---------- -Deprecated in favor of `assign_private_ip`_ in Salt Boron. +Deprecated in favor of `assign_private_ip`_ in Salt 2016.3.0. ssh_interface ------------- -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Specify whether to use a public or private IP for the deploy script. Valid options are: diff --git a/doc/topics/cloud/softlayer.rst b/doc/topics/cloud/softlayer.rst index 846b5c53ebf3..1edf8e22d99e 100644 --- a/doc/topics/cloud/softlayer.rst +++ b/doc/topics/cloud/softlayer.rst @@ -192,7 +192,7 @@ Name) which is a result of combining the ``domain`` configuration value and the Minion name specified either via the CLI or a map file rather than only using the short host name, or Minion ID. Default is False. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 For example, if the value of ``domain`` is ``example.com`` and a new VM was created via the CLI with ``salt-cloud -p base_softlayer_ubuntu my-vm``, the resulting diff --git a/doc/topics/cloud/vmware.rst b/doc/topics/cloud/vmware.rst index 59c2ce959f71..6ad44510f90d 100644 --- a/doc/topics/cloud/vmware.rst +++ b/doc/topics/cloud/vmware.rst @@ -246,7 +246,7 @@ Set up an initial profile at ``/etc/salt/cloud.profiles`` or Enter the size of disk in GB thin_provision Specifies whether the disk should be thin provisioned or not. Default is ``thin_provision: False``. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 controller Specify the SCSI controller label to which this disk should be attached. This should be specified only when creating both the specified SCSI @@ -527,7 +527,7 @@ Example of a minimal profile: Creating a VM ============= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Creating a VM from scratch means that more configuration has to be specified in the profile because there is no place to inherit configuration from. diff --git a/doc/topics/configuration/index.rst b/doc/topics/configuration/index.rst index 469b77d2553a..363bffb21e0b 100644 --- a/doc/topics/configuration/index.rst +++ b/doc/topics/configuration/index.rst @@ -11,6 +11,7 @@ secure and troubleshoot, and how to perform many other administrative tasks. ../../ref/configuration/master ../../ref/configuration/minion ../../ref/configuration/examples + ../blackout/index ../eauth/access_control ../jobs/index ../jobs/job_cache diff --git a/doc/topics/development/conventions/documentation.rst b/doc/topics/development/conventions/documentation.rst index 8eb4e171de63..8315f967e148 100644 --- a/doc/topics/development/conventions/documentation.rst +++ b/doc/topics/development/conventions/documentation.rst @@ -139,7 +139,7 @@ For changes to a function: ''' Upper-case the given value - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Added a flag to also strip whitespace from the string. <...snip...> diff --git a/doc/topics/development/conventions/formulas.rst b/doc/topics/development/conventions/formulas.rst index c996f70d2c98..5f56a5cef6f3 100644 --- a/doc/topics/development/conventions/formulas.rst +++ b/doc/topics/development/conventions/formulas.rst @@ -777,6 +777,21 @@ state file using the following syntax: service.running: - name: {{ mysql.service }} +Organizing Pillar data +`````````````````````` + +It is considered a best practice to make formulas expect **all** +formula-related parameters to be placed under second-level ``lookup`` key, +within a main namespace designated for holding data for particular +service/software/etc, managed by the formula: + +.. code-block:: yaml + +mysql: + lookup: + version: 5.7.11 + ... + Collecting common values ```````````````````````` diff --git a/doc/topics/installation/rhel.rst b/doc/topics/installation/rhel.rst index 6d4069de5e2d..3474b9832b50 100644 --- a/doc/topics/installation/rhel.rst +++ b/doc/topics/installation/rhel.rst @@ -84,24 +84,36 @@ To install using the SaltStack repository: - ``yum install salt-cloud`` .. note:: - As of 2015.8.4, EPEL support is no longer required when installing on Red Hat 5. (EPEL - support was previously required on Red Hat 5, but not on Red Hat 6 or 7). + As of 2015.8.0, EPEL repository is no longer required for installing on + RHEL systems. SaltStack repository provides all needed dependencies. + +.. warning:: + If installing on Red Hat Enterprise Linux 7 with disabled (not subscribed on) + 'RHEL Server Releases' or 'RHEL Server Optional Channel' repositories, + append CentOS 7 GPG key URL to SaltStack yum repository configuration to + install required base packages: + + .. code-block:: cfg + + [saltstack-repo] + name=SaltStack repo for Red Hat Enterprise Linux $releasever + baseurl=https://repo.saltstack.com/yum/redhat/$releasever/$basearch/latest + enabled=1 + gpgcheck=1 + gpgkey=https://repo.saltstack.com/yum/redhat/$releasever/$basearch/latest/SALTSTACK-GPG-KEY.pub + https://repo.saltstack.com/yum/redhat/$releasever/$basearch/latest/base/RPM-GPG-KEY-CentOS-7 Installation from the Community Repository ========================================== Beginning with version 0.9.4, Salt has been available in `EPEL`_. For -RHEL/CentOS 5, `Fedora COPR`_ is recommended due to the removal of some -dependencies from EPEL5. - -On RHEL/CentOS 6, the proper Jinja package 'python-jinja2' was moved from EPEL -to the "RHEL Server Optional Channel". Verify this repository is enabled before -installing salt on RHEL/CentOS 6. +RHEL/CentOS 5, `Fedora COPR`_ is a single community repository that provides +Salt packages due to the removal from EPEL5. .. note:: - Packages in these repositories are community built, and it can - take a little while until the latest SaltStack release is available - in this repository. + Packages in these repositories are built by community, and it can + take a little while until the latest stable SaltStack release become + available. .. _`EPEL`: http://fedoraproject.org/wiki/EPEL .. _`Fedora COPR`: https://copr.fedorainfracloud.org/coprs/saltstack/salt-el5/ @@ -110,10 +122,10 @@ RHEL/CentOS 6 and 7, Scientific Linux, etc. ------------------------------------------- .. warning:: - Salt 2015.8 requires ``python-crypto`` 2.6.1 or higher, and ``python-tornado`` version - 4.2.1 or higher. These packages are not currently available in EPEL for - Red Hat 5 and 6. You must install these dependencies from another location - or use the SaltStack repository documented above. + Salt 2015.8 is currently not available in EPEL due to unsatisfied + dependencies: ``python-crypto`` 2.6.1 or higher, and ``python-tornado`` + version 4.2.1 or higher. These packages are not currently available in EPEL + for Red Hat Enterprise Linux 6 and 7. Enabling EPEL ************* @@ -131,7 +143,6 @@ Replace ``epel-release-X-Y.rpm`` with the appropriate filename. .. _RHEL/CentOS 6: http://download.fedoraproject.org/pub/epel/6/i386/repoview/epel-release.html .. _RHEL/CentOS 7: http://download.fedoraproject.org/pub/epel/7/x86_64/repoview/epel-release.html - Installing Stable Release ************************* @@ -149,9 +160,9 @@ Installing from ``epel-testing`` ******************************** When a new Salt release is packaged, it is first admitted into the -``epel-testing`` repository, before being moved to the stable repo. +``epel-testing`` repository, before being moved to the stable EPEL repository. -To install from ``epel-testing``, use the ``enablerepo`` argument for yum: +To install from ``epel-testing``, use the ``enablerepo`` argument for ``yum``: .. code-block:: bash @@ -161,7 +172,7 @@ Installation Using pip ====================== Since Salt is on `PyPI`_, it can be installed using pip, though most users -prefer to install using RPMs (which can be installed from `EPEL`_). +prefer to install using RPM packages (which can be installed from `EPEL`_). Installing from pip has a few additional requirements: @@ -181,7 +192,6 @@ Installation from pip: pip install salt .. warning:: - If installing from pip (or from source using ``setup.py install``), be advised that the ``yum-utils`` package is needed for Salt to manage packages. Also, if the Python dependencies are not already installed, then @@ -192,15 +202,15 @@ Installation from pip: ZeroMQ 4 ======== -We recommend using ZeroMQ 4 where available. SaltStack provides ZeroMQ 4.0.4 -and pyzmq 14.3.1 in the :ref:`SaltStack Repository ` -as well as a COPR_ repository. +We recommend using ZeroMQ 4 where available. SaltStack provides ZeroMQ 4.0.5 +and pyzmq 14.5.0 in the :ref:`SaltStack Repository ` +as well as a separate `zeromq4 COPR`_ repository. -.. _COPR: http://copr.fedorainfracloud.org/coprs/saltstack/zeromq4/ +.. _`zeromq4 COPR`: http://copr.fedorainfracloud.org/coprs/saltstack/zeromq4/ -If this repo is added *before* Salt is installed, then installing either -``salt-master`` or ``salt-minion`` will automatically pull in ZeroMQ 4.0.4, and -additional states to upgrade ZeroMQ and pyzmq are unnecessary. +If this repository is added *before* Salt is installed, then installing either +``salt-master`` or ``salt-minion`` will automatically pull in ZeroMQ 4.0.5, and +additional steps to upgrade ZeroMQ and pyzmq are unnecessary. .. warning:: RHEL/CentOS 5 Users Using COPR repos on RHEL/CentOS 5 requires that the ``python-hashlib`` @@ -208,11 +218,10 @@ additional states to upgrade ZeroMQ and pyzmq are unnecessary. because YUM will not be able to process the SHA256 checksums used by COPR. .. note:: - For RHEL/CentOS 5 installations, if using the new repository to install - Salt (as detailed :ref:`above `), then it is not - necessary to enable the zeromq4 COPR, as the new EL5 repository includes - ZeroMQ 4. - + For RHEL/CentOS 5 installations, if using the SaltStack repo or Fedora COPR + to install Salt (as described :ref:`above `), + then it is not necessary to enable the `zeromq4 COPR`_, because those + repositories already include ZeroMQ 4. Package Management ================== @@ -229,34 +238,66 @@ dependency. Post-installation tasks ======================= -**Master** +Master +------ To have the Master start automatically at boot time: +**RHEL/CentOS 5 and 6** + .. code-block:: bash chkconfig salt-master on +**RHEL/CentOS 7** + +.. code-block:: bash + + systemctl enable salt-master.service To start the Master: +**RHEL/CentOS 5 and 6** + .. code-block:: bash service salt-master start -**Minion** +**RHEL/CentOS 7** + +.. code-block:: bash + + systemctl start salt-master.service + +Minion +------ To have the Minion start automatically at boot time: +**RHEL/CentOS 5 and 6** + .. code-block:: bash chkconfig salt-minion on +**RHEL/CentOS 7** + +.. code-block:: bash + + systemctl enable salt-minion.service To start the Minion: +**RHEL/CentOS 5 and 6** + .. code-block:: bash service salt-minion start +**RHEL/CentOS 7** + +.. code-block:: bash + + systemctl start salt-minion.service + Now go to the :doc:`Configuring Salt` page. diff --git a/doc/topics/orchestrate/orchestrate_runner.rst b/doc/topics/orchestrate/orchestrate_runner.rst index 6767158e21e9..87eef6976778 100644 --- a/doc/topics/orchestrate/orchestrate_runner.rst +++ b/doc/topics/orchestrate/orchestrate_runner.rst @@ -26,7 +26,7 @@ The Orchestrate Runner The Orchestrate Runner was added with the intent to eventually deprecate the OverState system, however the OverState will still be maintained until Salt - Boron. + 2015.8.0. The orchestrate runner generalizes the Salt state system to a Salt master context. Whereas the ``state.sls``, ``state.highstate``, et al functions are diff --git a/doc/topics/proxyminion/index.rst b/doc/topics/proxyminion/index.rst index 88331e56139c..aa4d9d327e6f 100644 --- a/doc/topics/proxyminion/index.rst +++ b/doc/topics/proxyminion/index.rst @@ -43,7 +43,7 @@ New in 2015.8.2 The `proxymodule` variable has been moved a new globally-injected variable called `__proxy__`. A related configuration option called `add_proxymodule_to_opts` has been added and defaults to `True`. In the next -major release, codenamed Boron, this variable will default to False. +major release, 2016.3.0, this variable will default to False. In the meantime, proxies that functioned under 2015.8.0 and .1 should continue to work under 2015.8.2. You should rework your proxy code to use `__proxy__` as diff --git a/doc/topics/releases/2015.8.7.rst b/doc/topics/releases/2015.8.7.rst new file mode 100644 index 000000000000..6bcde0352bee --- /dev/null +++ b/doc/topics/releases/2015.8.7.rst @@ -0,0 +1,91 @@ +=========================== +Salt 2015.8.7 Release Notes +=========================== + +Changes for v2015.8.4..v2015.8.7 +-------------------------------- + +Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs): + +*Generated at: 2016-02-11T22:13:51Z* + +Statistics: + +- Total Merges: **2** +- Total Issue references: **0** +- Total PR references: **3** + +Changes: + +- **PR** `#31111`_: (*jtand*) Fixes failing npm test on arch. + @ *2016-02-10T21:51:47Z* + + * 8d84c63 Merge pull request `#31111`_ from jtand/8_4_npm_fix + * b0a48e5 Fixes failing npm test on arch. + + * 733c6ab Some 3rd-party modules (e.g. gnupg) define custom log levels that emit at INFO level and above. This patch sets the color data lookups to default to TextFormat('reset') rather than producing a stack trace every time a log message is generated from an affected module. + + * 3f71fd0 Revert `#30217`_ + + - **PR** `#30217`_: (*pass-by-value*) Make sure cloud actions can be called via salt run + +- **PR** `#31092`_: (*terminalmage*) Apply PR `#31031`_ to 2015.8.4.follow_up + @ *2016-02-10T20:54:37Z* + + * 5a6a93e Merge pull request `#31092`_ from terminalmage/issue31014-2015.8.4.follow_up + * 2767a4e Don't handle epoch specially for dnf + + * e5dfcc0 More efficient way to add the epoch before version number + + * ed74627 include possible epoch in version for rpm + + * 6c6b66a Comment multiprocessing line in minion config + + * 1f7dfef Set multiprocessing to true in config.py + + * 433c645 Fix remove placeholder files + + * 7103756 Remove placeholder files + + * 20b381f Set overwrite to off + + * ca50f56 Fix boto_secgroup + + * fd571d2 Fix boto test failures + + * cfb6588 Fix regression when contents_pillar/contents_grains is a list. + + * 881d866 utils.aws: use time lib to conver to epoch seconds + + * 3141292 The call to cp.get_url needs the saltenv, if you're using environments other than base, it will fail. + + * a869401 Fix regression in git_pillar when multiple remotes are configured + + * 2243f25 Properly set the default value for pillar_merge_lists + + * c7472ff Lint + + * d868711 Fix failing boto_vpc module unit tests + + * ed09516 Fix failing state module tests + + * fd0e940 Pylint fix + + * bc780a7 Don't use pack=pack. Just pass in pack=__salt__ always. + + * 1ae022d Pass in 'pack' variable to utils.boto.assign_funcs function from ALL boto modules. + + * 1efaff1 Remove bad symlinks in osx pkg dirs + + * c7db435 Fix regression in scanning for state with 'name' param + +.. _`#30217`: https://github.com/saltstack/salt/pull/30217 +.. _`#31031`: https://github.com/saltstack/salt/issues/31031 +.. _`#31092`: https://github.com/saltstack/salt/pull/31092 +.. _`#31111`: https://github.com/saltstack/salt/pull/31111 + +-------------------------- +**2015.8.5 Release Notes** +.. include:: 2015.8.5.rst + :start-line: 6` + diff --git a/doc/topics/releases/boron.rst b/doc/topics/releases/boron.rst index ca0ecb170146..8671aadfc0ae 100644 --- a/doc/topics/releases/boron.rst +++ b/doc/topics/releases/boron.rst @@ -1,8 +1,8 @@ :orphan: -=================================== -Salt Release Notes - Codename Boron -=================================== +============================================ +Salt 2016.3.0 Release Notes - Codename Boron +============================================ Backwards-incompatible Changes ============================== diff --git a/doc/topics/releases/carbon.rst b/doc/topics/releases/carbon.rst index e99c49fea0e0..bd8781a43956 100644 --- a/doc/topics/releases/carbon.rst +++ b/doc/topics/releases/carbon.rst @@ -20,3 +20,101 @@ Grains Changes - The ``loadavg`` beacon now outputs averages as integers instead of strings. (Via :issuse:`31124`.) + +Deprecations +============ + +- The ``boto_vpc`` execution module had two functions removed, + ``boto_vpc.associate_new_dhcp_options_to_vpc`` and + ``boto_vpc.associate_new_network_acl_to_subnet`` in favor of more concise function + names, ``boto_vpc.create_dhcp_options`` and ``boto_vpc.create_network_acl``, respectively. + +- The ``data`` execution module had ``getval`` and ``getvals`` functions removed + in favor of one function, ``get``, which combines the functionality of the + removed functions. + +- The ``grains.cache`` runner no longer accpets ``outputter`` or ``minion`` as keyword arguments. + Users will need to specify an outputter using the ``--out`` option. ``tgt`` is + replacing the ``minion`` kwarg. + +- The use of ``jid_dir`` and ``jid_load`` were removed from the + ``salt.utils.jid``. ``jid_dir`` functionality for job_cache management was moved to + the ``local_cache`` returner. ``jid_load`` data is now retreived from the + ``master_job_cache`` + +reg execution module + Functions in the ``reg`` execution module had misleading and confusing names + for dealing with the Windows registry. They failed to clearly differentiate + between hives, keys, and name/value pairs. Keys were treated like value names. + There was no way to delete a key. + + New functions were added in 2015.5 to properly work with the registry. They + also made it possible to edit key default values as well as delete an entire + key tree recursively. With the new functions in place, the following functions + have been deprecated: + + - read_key + - set_key + - create_key + - delete_key + + Use the following functions instead: + + - for ``read_key`` use ``read_value`` + - for ``set_key`` use ``set_value`` + - for ``create_key`` use ``set_value`` with no ``vname`` and no ``vdata`` + - for ``delete_key`` use ``delete_key_recursive``. To delete a value, use + ``delete_value``. + +reg state module + The ``reg`` state module was modified to work with the new functions in the + execution module. Some logic was left in the ``reg.present`` and the + ``reg.absent`` functions to handle existing state files that used the final + key in the name as the value name. That logic has been removed so you now must + specify value name (``vname``) and, if needed, value data (``vdata``). + + For example, a state file that adds the version value/data pair to the + Software\\Salt key in the HKEY_LOCAL_MACHINE hive used to look like this: + + .. code-block:: yaml + + HKEY_LOCAL_MACHINE\\Software\\Salt\\version: + reg.present: + - value: 2016.3.1 + + Now it should look like this: + + .. code-block:: yaml + + HKEY_LOCAL_MACHINE\\Software\\Salt + reg.present: + - vname: version + - vdata: 2016.3.1 + + A state file for removing the same value added above would have looked like + this: + + .. code-block:: yaml + + HKEY_LOCAL_MACHINE\\Software\\Salt\\version: + reg.absent: + + Now it should look like this: + + .. code-block:: yaml + + HKEY_LOCAL_MACHINE\\Software\\Salt + reg.absent: + - vname: version + + This new structure is important as it allows salt to deal with key default + values which was not possible before. If vname is not passed, salt will work + with the default value for that hive\key. + + Additionally, since you could only delete a value from a the state module, a + new function (``key_absent``) has been added to allow you to delete a registry + key and all subkeys and name/value pairs recursively. It uses the new + ``delete_key_recursive`` function. + + For additional information see the documentation for the ``reg`` execution and + state modules. diff --git a/doc/topics/releases/version_numbers.rst b/doc/topics/releases/version_numbers.rst index c0a14093373a..0b2e9837ab44 100644 --- a/doc/topics/releases/version_numbers.rst +++ b/doc/topics/releases/version_numbers.rst @@ -27,8 +27,9 @@ Assigned codenames: - Helium: ``2014.7.0`` - Lithium: ``2015.5.0`` - Beryllium: ``2015.8.0`` -- Boron: ``TBD`` +- Boron: ``2016.3.0`` - Carbon: ``TBD`` +- Nitrogen: ``TBD`` Example ------- diff --git a/doc/topics/thorium/index.rst b/doc/topics/thorium/index.rst index f43c52de9122..9fc2972d4ab7 100644 --- a/doc/topics/thorium/index.rst +++ b/doc/topics/thorium/index.rst @@ -5,7 +5,8 @@ Thorium Complex Reactor .. note:: Thorium was added to Salt as an experimental feature in the 2016.3.0 - release, as of 2016.3 this feature is considered experimental. + release, as of 2016.3.0 this feature is considered experimental, no + guarantees are made for support of any kind yet. The original Salt Reactor is based on the idea of listening for a specific @@ -13,9 +14,9 @@ event and then reacting to it. This model comes with many logical limitations, for instance it is very difficult (and hacky) to fire a reaction based on aggregate data or based on multiple events. -The Thorium reactor is intended to aleviate this problem in a very elegant way. +The Thorium reactor is intended to alleviate this problem in a very elegant way. Instead of using extensive jinja routines or complex python sls files the -aggregation of data and the determinization of what should run becomes isolated +aggregation of data and the determination of what should run becomes isolated to the sls data logic, makes the definitions much cleaner. diff --git a/doc/topics/tutorials/esxi_proxy_minion.rst b/doc/topics/tutorials/esxi_proxy_minion.rst index 89ce4f422ded..001bc19846c1 100644 --- a/doc/topics/tutorials/esxi_proxy_minion.rst +++ b/doc/topics/tutorials/esxi_proxy_minion.rst @@ -145,10 +145,10 @@ will connect to. .. note:: - If you're running your ESXi Proxy Minion on version of Salt that is 2015.8.4 + If you're running your ESXi Proxy Minion on version of Salt that is 2015.8.2 or newer, you also need to set ``add_proxymodule_to_opts: False`` in your proxy config file. The need to specify this configuration will be removed with - Salt ``Boron``, the next major feature release. See the `New in 2015.8.2`_ + Salt ``2016.3.0``, the next major feature release. See the `New in 2015.8.2`_ section of the Proxy Minion documentation for more information. .. _New in 2015.8.2: https://docs.saltstack.com/en/latest/topics/proxyminion/index.html#new-in-2015-8-2 diff --git a/pkg/salt-api.service b/pkg/salt-api.service index ccf3d34f53e4..72379ba08daa 100644 --- a/pkg/salt-api.service +++ b/pkg/salt-api.service @@ -6,6 +6,7 @@ After=network.target Type=simple LimitNOFILE=8192 ExecStart=/usr/bin/salt-api +TimeoutStopSec=3 [Install] WantedBy=multi-user.target diff --git a/pkg/windows/BuildSalt.bat b/pkg/windows/BuildSalt.bat index e413ab774c5a..04fea057dd75 100644 --- a/pkg/windows/BuildSalt.bat +++ b/pkg/windows/BuildSalt.bat @@ -44,6 +44,8 @@ python "%CurrDir%\portable.py" -f "%BinDir%\Scripts\pip2.exe" del /S /Q "%BinDir%\*.pyc" :: Remove all Compiled HTML Help (.chm) del /S /Q "%BinDir%\*.chm" +:: Remove all empty text files (they are placeholders for git) +del /S /Q "%BinDir%\..\empty.*" :: Delete Unused Docs and Modules If Exist "%BinDir%\Doc" rd /S /Q "%BinDir%\Doc" diff --git a/pkg/windows/buildenv/conf/minion b/pkg/windows/buildenv/conf/minion index 9ba9c78ecc16..fbb9769b06a3 100644 --- a/pkg/windows/buildenv/conf/minion +++ b/pkg/windows/buildenv/conf/minion @@ -281,7 +281,7 @@ pki_dir: /conf/pki/minion ########################################### # Disable multiprocessing support, by default when a minion receives a # publication a new process is spawned and the command is executed therein. -multiprocessing: True +# multiprocessing: True ###### Logging settings ##### ########################################### diff --git a/pkg/windows/installer/Salt-Minion-Setup.nsi b/pkg/windows/installer/Salt-Minion-Setup.nsi index c6b82e75b1e4..fad5721a6c7f 100644 --- a/pkg/windows/installer/Salt-Minion-Setup.nsi +++ b/pkg/windows/installer/Salt-Minion-Setup.nsi @@ -222,7 +222,7 @@ ShowUnInstDetails show Section "MainSection" SEC01 SetOutPath "$INSTDIR\" - SetOverwrite try + SetOverwrite off CreateDirectory $INSTDIR\conf\pki\minion File /r "..\buildenv\" Exec 'icacls c:\salt /inheritance:r /grant:r "BUILTIN\Administrators":(OI)(CI)F /grant:r "NT AUTHORITY\SYSTEM":(OI)(CI)F' diff --git a/salt/beacons/adb.py b/salt/beacons/adb.py index b95fab4f1652..fbe5d554e9d3 100644 --- a/salt/beacons/adb.py +++ b/salt/beacons/adb.py @@ -2,7 +2,7 @@ ''' Beacon to emit adb device state changes for Android devices -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' # Import Python libs diff --git a/salt/beacons/glxinfo.py b/salt/beacons/glxinfo.py index 5ef764a3f554..0154e45624f0 100644 --- a/salt/beacons/glxinfo.py +++ b/salt/beacons/glxinfo.py @@ -2,7 +2,7 @@ ''' Beacon to emit when a display is available to a linux machine -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' # Import Python libs diff --git a/salt/beacons/memusage.py b/salt/beacons/memusage.py index 872da2c2a186..de1d89540cb2 100644 --- a/salt/beacons/memusage.py +++ b/salt/beacons/memusage.py @@ -2,7 +2,7 @@ ''' Beacon to monitor memory usage. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :depends: python-psutil ''' diff --git a/salt/beacons/pkg.py b/salt/beacons/pkg.py index b8deedf89e94..0b7bbee030db 100644 --- a/salt/beacons/pkg.py +++ b/salt/beacons/pkg.py @@ -2,7 +2,7 @@ ''' Watch for pkgs that have upgrades, then fire an event. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' # Import python libs diff --git a/salt/client/mixins.py b/salt/client/mixins.py index 5adfdd28dd36..8bcc79749835 100644 --- a/salt/client/mixins.py +++ b/salt/client/mixins.py @@ -329,7 +329,7 @@ def low(self, fun, low): # kwargs using the old mechanism if kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'kwargs must be passed inside the low under "kwargs"' ) else: diff --git a/salt/client/ssh/wrapper/state.py b/salt/client/ssh/wrapper/state.py index 98c7d04e0053..dd6d5915dd88 100644 --- a/salt/client/ssh/wrapper/state.py +++ b/salt/client/ssh/wrapper/state.py @@ -51,9 +51,9 @@ def sls(mods, saltenv='base', test=None, exclude=None, env=None, **kwargs): __opts__['grains'] = __grains__ if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -484,9 +484,9 @@ def show_sls(mods, saltenv='base', test=None, env=None, **kwargs): __opts__['grains'] = __grains__ if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/cloud/__init__.py b/salt/cloud/__init__.py index 4a198bca2f2b..690fadb91539 100644 --- a/salt/cloud/__init__.py +++ b/salt/cloud/__init__.py @@ -9,7 +9,6 @@ import os import copy import glob -import inspect import time import signal import logging @@ -1500,15 +1499,8 @@ def do_action(self, names, kwargs): ret[alias][driver] = {} if kwargs: - argnames = inspect.getargspec(self.clouds[fun]).args - for _ in inspect.getargspec(self.clouds[fun]).defaults: - argnames.pop(0) - kws = {} - for kwarg in argnames: - kws[kwarg] = kwargs.get(kwarg, None) - kws['call'] = 'action' ret[alias][driver][vm_name] = self.clouds[fun]( - vm_name, **kws + vm_name, kwargs, call='action' ) else: ret[alias][driver][vm_name] = self.clouds[fun]( diff --git a/salt/cloud/clouds/aliyun.py b/salt/cloud/clouds/aliyun.py index cabdf0860b40..14fb6306b9df 100644 --- a/salt/cloud/clouds/aliyun.py +++ b/salt/cloud/clouds/aliyun.py @@ -583,7 +583,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'aliyun', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/botocore_aws.py b/salt/cloud/clouds/botocore_aws.py deleted file mode 100644 index 29b72b11fc53..000000000000 --- a/salt/cloud/clouds/botocore_aws.py +++ /dev/null @@ -1,242 +0,0 @@ -# -*- coding: utf-8 -*- -''' -The AWS Cloud Module -==================== - -The AWS cloud module is used to interact with the Amazon Web Services system. - -This module has been replaced by the EC2 cloud module, and is no longer -supported. The documentation shown here is for reference only; it is highly -recommended to change all usages of this driver over to the EC2 driver. - -If this driver is still needed, set up the cloud configuration at - ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/aws.conf``: - -.. code-block:: yaml - - my-aws-botocore-config: - # The AWS API authentication id - id: GKTADJGHEIQSXMKKRBJ08H - # The AWS API authentication key - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs - # The ssh keyname to use - keyname: default - # The amazon security group - securitygroup: ssh_open - # The location of the private key which corresponds to the keyname - private_key: /root/default.pem - driver: aws - -''' -# pylint: disable=E0102 - -# Import python libs -from __future__ import absolute_import -import logging - -# Import salt.cloud libs -import salt.utils.cloud -import salt.config as config -from salt.utils import namespaced_function -import salt.ext.six as six - -# Import libcloudfuncs and libcloud_aws, required to latter patch __opts__ -try: - from salt.cloud.libcloudfuncs import * # pylint: disable=W0614,W0401 - from salt.cloud import libcloudfuncs - from salt.cloud.clouds import libcloud_aws - # Import libcloud_aws, storing pre and post locals so we can namespace any - # callable to this module. - PRE_IMPORT_LOCALS_KEYS = locals().copy() - from salt.cloud.clouds.libcloud_aws import * # pylint: disable=W0614,W0401 - POST_IMPORT_LOCALS_KEYS = locals().copy() - HAS_LIBCLOUD = True -except ImportError: - HAS_LIBCLOUD = False - -# Get logging started -log = logging.getLogger(__name__) - -# Define the module's virtual name -__virtualname__ = 'aws' - - -# Only load in this module if the AWS configurations are in place -def __virtual__(): - ''' - Set up the libcloud funcstions and check for AWS configs - ''' - try: - # Import botocore - import botocore.session - except ImportError: - # Botocore is not available, the Libcloud AWS module will be loaded - # instead. - return False - - # "Patch" the imported libcloud_aws to have the current __opts__ - libcloud_aws.__opts__ = __opts__ - libcloudfuncs.__opts__ = __opts__ - - if get_configured_provider() is False: - return False - - if get_dependencies() is False: - return False - - for provider, details in six.iteritems(__opts__['providers']): - if 'aws' not in details: - continue - - parameters = details['aws'] - if salt.utils.cloud.check_key_path_and_mode( - provider, parameters['private_key'] - ) is False: - return False - - # Let's bring the functions imported from libcloud_aws to the current - # namespace. - keysdiff = set(POST_IMPORT_LOCALS_KEYS).difference( - PRE_IMPORT_LOCALS_KEYS - ) - for key in keysdiff: - # only import callables that actually have __code__ (this includes - # functions but excludes Exception classes) - if (callable(POST_IMPORT_LOCALS_KEYS[key]) and - hasattr(POST_IMPORT_LOCALS_KEYS[key], "__code__")): - globals().update( - { - key: namespaced_function( - POST_IMPORT_LOCALS_KEYS[key], globals(), () - ) - } - ) - - global avail_images, avail_sizes, avail_locations, script - global list_nodes, list_nodes_full, list_nodes_select - - # open a connection in a specific region - conn = get_conn(**{'location': get_location()}) - - # Init the libcloud functions - avail_locations = namespaced_function(avail_locations, globals(), (conn,)) - avail_images = namespaced_function(avail_images, globals(), (conn,)) - avail_sizes = namespaced_function(avail_sizes, globals(), (conn,)) - script = namespaced_function(script, globals(), (conn,)) - list_nodes = namespaced_function(list_nodes, globals(), (conn,)) - list_nodes_full = namespaced_function(list_nodes_full, globals(), (conn,)) - list_nodes_select = namespaced_function( - list_nodes_select, globals(), (conn,) - ) - - log.warning('This driver has been deprecated and will be removed in the ' - 'Boron release of Salt. Please use the ec2 driver instead.') - - return __virtualname__ - - -def get_configured_provider(): - ''' - Return the first configured instance. - ''' - return config.is_provider_configured( - __opts__, - 'aws', - ('id', 'key', 'keyname', 'securitygroup', 'private_key') - ) - - -def get_dependencies(): - ''' - Warn if dependencies aren't met. - ''' - return config.check_driver_dependencies( - __virtualname__, - {'libcloud': HAS_LIBCLOUD} - ) - - -def enable_term_protect(name, call=None): - ''' - Enable termination protection on a node - - CLI Example: - - .. code-block:: bash - - salt-cloud -a enable_term_protect mymachine - ''' - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - return _toggle_term_protect(name, True) - - -def disable_term_protect(name, call=None): - ''' - Disable termination protection on a node - - CLI Example: - - .. code-block:: bash - - salt-cloud -a disable_term_protect mymachine - ''' - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - return _toggle_term_protect(name, False) - - -def _toggle_term_protect(name, enabled): - ''' - Toggle termination protection on a node - ''' - # region is required for all boto queries - region = get_location(None) - - # init botocore - vm_ = get_configured_provider() - session = botocore.session.get_session() # pylint: disable=E0602 - session.set_credentials( - access_key=config.get_cloud_config_value( - 'id', vm_, __opts__, search_global=False - ), - secret_key=config.get_cloud_config_value( - 'key', vm_, __opts__, search_global=False - ) - ) - - service = session.get_service('ec2') - endpoint = service.get_endpoint(region) - - # get the instance-id for the supplied node name - conn = get_conn(location=region) - node = get_node(conn, name) - - params = { - 'instance_id': node.id, - 'attribute': 'disableApiTermination', - 'value': 'true' if enabled else 'false', - } - - # get instance information - operation = service.get_operation('modify-instance-attribute') - http_response, response_data = operation.call(endpoint, **params) - - if http_response.status_code == 200: - msg = 'Termination protection successfully {0} on {1}'.format( - enabled and 'enabled' or 'disabled', - name - ) - log.info(msg) - return msg - - # No proper HTTP response!? - msg = 'Bad response from AWS: {0}'.format(http_response.status_code) - log.error(msg) - return msg diff --git a/salt/cloud/clouds/cloudstack.py b/salt/cloud/clouds/cloudstack.py index 44ce888342c7..a4d05d9a163f 100644 --- a/salt/cloud/clouds/cloudstack.py +++ b/salt/cloud/clouds/cloudstack.py @@ -238,7 +238,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'cloudstack', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/digital_ocean.py b/salt/cloud/clouds/digital_ocean.py index 4a69b9db14d8..90e71d7abec3 100644 --- a/salt/cloud/clouds/digital_ocean.py +++ b/salt/cloud/clouds/digital_ocean.py @@ -274,7 +274,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'digital_ocean', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass @@ -937,7 +938,7 @@ def list_floating_ips(call=None): ''' Return a list of the floating ips that are on the provider - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: @@ -977,7 +978,7 @@ def show_floating_ip(kwargs=None, call=None): ''' Show the details of a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: @@ -1010,7 +1011,7 @@ def create_floating_ip(kwargs=None, call=None): ''' Create a new floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: @@ -1052,7 +1053,7 @@ def delete_floating_ip(kwargs=None, call=None): ''' Delete a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: @@ -1087,7 +1088,7 @@ def assign_floating_ip(kwargs=None, call=None): ''' Assign a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: @@ -1120,7 +1121,7 @@ def unassign_floating_ip(kwargs=None, call=None): ''' Unassign a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index c65dc955849e..6a694d48a697 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -2295,7 +2295,8 @@ def create(vm_=None, call=None): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'ec2', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py index 861fbeaa6070..41b0b6a56c6e 100644 --- a/salt/cloud/clouds/gce.py +++ b/salt/cloud/clouds/gce.py @@ -2011,7 +2011,8 @@ def request_instance(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'gce', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/gogrid.py b/salt/cloud/clouds/gogrid.py index 9e92d37e3e6d..e02a26f2a58d 100644 --- a/salt/cloud/clouds/gogrid.py +++ b/salt/cloud/clouds/gogrid.py @@ -86,7 +86,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'gogrid', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/joyent.py b/salt/cloud/clouds/joyent.py index 847b3f315761..ac02f1657502 100644 --- a/salt/cloud/clouds/joyent.py +++ b/salt/cloud/clouds/joyent.py @@ -246,7 +246,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'joyent', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/libcloud_aws.py b/salt/cloud/clouds/libcloud_aws.py deleted file mode 100644 index 67ae4d17854b..000000000000 --- a/salt/cloud/clouds/libcloud_aws.py +++ /dev/null @@ -1,815 +0,0 @@ -# -*- coding: utf-8 -*- -''' -The AWS Cloud Module -==================== - -The AWS cloud module is used to interact with the Amazon Web Services system. - -This module has been replaced by the EC2 cloud module, and is no longer -supported. The documentation shown here is for reference only; it is highly -recommended to change all usages of this driver over to the EC2 driver. - -If this driver is still needed, set up the cloud configuration at - ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/aws.conf``: - -.. code-block:: yaml - - my-aws-config: - # The AWS API authentication id - id: GKTADJGHEIQSXMKKRBJ08H - # The AWS API authentication key - key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs - # The ssh keyname to use - keyname: default - # The amazon security group - securitygroup: ssh_open - # The location of the private key which corresponds to the keyname - private_key: /root/default.pem - - driver: aws - -''' -from __future__ import absolute_import -# pylint: disable=E0102 - -# Import python libs -import os -import uuid -import pprint -import logging - -# Import salt.cloud libs -import salt.utils.cloud -import salt.config as config -from salt.utils import namespaced_function - -from salt.exceptions import ( - SaltCloudException, - SaltCloudSystemExit, - SaltCloudConfigError, - SaltCloudExecutionTimeout, - SaltCloudExecutionFailure -) -import salt.ext.six as six - -try: - from salt.cloud.libcloudfuncs import * # pylint: disable=W0614,W0401 - from salt.cloud.libcloudfuncs import destroy as libcloudfuncs_destroy - from libcloud.compute.types import Provider - - EC2_LOCATIONS = { - 'ap-northeast-1': Provider.EC2_AP_NORTHEAST, - 'ap-southeast-1': Provider.EC2_AP_SOUTHEAST, - 'eu-west-1': Provider.EC2_EU_WEST, - 'sa-east-1': Provider.EC2_SA_EAST, - 'us-east-1': Provider.EC2_US_EAST, - 'us-west-1': Provider.EC2_US_WEST, - 'us-west-2': Provider.EC2_US_WEST_OREGON - } - DEFAULT_LOCATION = 'us-east-1' - if hasattr(Provider, 'EC2_AP_SOUTHEAST2'): - EC2_LOCATIONS['ap-southeast-2'] = Provider.EC2_AP_SOUTHEAST2 - - HAS_LIBCLOUD = True -except ImportError: - HAS_LIBCLOUD = False - -# Get logging started -log = logging.getLogger(__name__) - -# Define the module's virtual name -__virtualname__ = 'aws' - - -# Only load in this module if the AWS configurations are in place -def __virtual__(): - ''' - Set up the libcloud funcstions and check for AWS configs - ''' - try: - import botocore - # Since we have botocore, we won't load the libcloud AWS module - return False - except ImportError: - pass - - if get_configured_provider() is False: - return False - - if get_dependencies() is False: - return False - - for provider, details in six.iteritems(__opts__['providers']): - if 'aws' not in details: - continue - - parameters = details['aws'] - if salt.utils.cloud.check_key_path_and_mode( - provider, parameters['private_key'] - ) is False: - return False - - global avail_images, avail_sizes, script, list_nodes - global avail_locations, list_nodes_full, list_nodes_select, get_image - global get_size, libcloudfuncs_destroy, show_instance - - # open a connection in a specific region - conn = get_conn(**{'location': get_location()}) - - # Init the libcloud functions - get_size = namespaced_function(get_size, globals(), (conn,)) - get_image = namespaced_function(get_image, globals(), (conn,)) - avail_locations = namespaced_function(avail_locations, globals(), (conn,)) - avail_images = namespaced_function(avail_images, globals(), (conn,)) - avail_sizes = namespaced_function(avail_sizes, globals(), (conn,)) - script = namespaced_function(script, globals(), (conn,)) - list_nodes = namespaced_function(list_nodes, globals(), (conn,)) - list_nodes_full = namespaced_function(list_nodes_full, globals(), (conn,)) - list_nodes_select = namespaced_function( - list_nodes_select, globals(), (conn,) - ) - libcloudfuncs_destroy = namespaced_function( - libcloudfuncs_destroy, globals(), (conn,) - ) - show_instance = namespaced_function(show_instance, globals()) - - log.warning('This driver has been deprecated and will be removed in the ' - 'Boron release of Salt. Please use the ec2 driver instead.') - - return __virtualname__ - - -def get_configured_provider(): - ''' - Return the first configured instance. - ''' - return config.is_provider_configured( - __opts__, - __active_provider_name__ or 'aws', - ('id', 'key', 'keyname', 'securitygroup', 'private_key') - ) - - -def get_dependencies(): - ''' - Warn if dependencies aren't met. - ''' - return config.check_driver_dependencies( - __virtualname__, - {'libcloud': HAS_LIBCLOUD} - ) - - -def get_conn(**kwargs): - ''' - Return a conn object for the passed VM data - ''' - if 'location' in kwargs: - location = kwargs['location'] - if location not in EC2_LOCATIONS: - raise SaltCloudException( - 'The specified location does not seem to be valid: ' - '{0}\n'.format( - location - ) - ) - else: - location = DEFAULT_LOCATION - - driver = get_driver(EC2_LOCATIONS[location]) - vm_ = get_configured_provider() - return driver( - config.get_cloud_config_value('id', vm_, __opts__, search_global=False), - config.get_cloud_config_value('key', vm_, __opts__, search_global=False) - ) - - -def keyname(vm_): - ''' - Return the keyname - ''' - return config.get_cloud_config_value( - 'keyname', vm_, __opts__, search_global=False - ) - - -def securitygroup(vm_): - ''' - Return the security group - ''' - return config.get_cloud_config_value( - 'securitygroup', vm_, __opts__, search_global=False - ) - - -def iam_profile(vm_): - ''' - Return the IAM role - ''' - return config.get_cloud_config_value( - 'iam_profile', vm_, __opts__, search_global=False - ) - - -def block_device_mappings(vm_): - ''' - Return the block device mapping: - - :: - - [{'DeviceName': '/dev/sdb', 'VirtualName': 'ephemeral0'}, - {'DeviceName': '/dev/sdc', 'VirtualName': 'ephemeral1'}] - ''' - return config.get_cloud_config_value( - 'block_device_mappings', vm_, __opts__, search_global=False - ) - - -def ssh_username(vm_): - ''' - Return the ssh_username. Defaults to 'ec2-user'. - ''' - usernames = config.get_cloud_config_value( - 'ssh_username', vm_, __opts__ - ) - - if not isinstance(usernames, list): - usernames = [usernames] - - # get rid of None's or empty names - usernames = [x for x in usernames if x] - # Keep a copy of the usernames the user might have provided - initial = usernames[:] - - # Add common usernames to the list to be tested - for name in 'ec2-user', 'ubuntu', 'admin', 'bitnami', 'root': - if name not in usernames: - usernames.append(name) - # Add the user provided usernames to the end of the list since enough time - # might need to pass before the remote service is available for logins and - # the proper username might have passed its iteration. - # This has detected in a CentOS 5.7 EC2 image - usernames.extend(initial) - return usernames - - -def ssh_interface(vm_): - ''' - Return the ssh_interface type to connect to. Either 'public_ips' (default) - or 'private_ips'. - ''' - return config.get_cloud_config_value( - 'ssh_interface', vm_, __opts__, default='public_ips', - search_global=False - ) - - -def get_location(vm_=None): - ''' - Return the AWS region to use, in this order: - - CLI parameter - - Cloud profile setting - - Global salt-cloud config - ''' - return __opts__.get( - 'location', - config.get_cloud_config_value( - 'location', - vm_ or get_configured_provider(), __opts__, - default=DEFAULT_LOCATION - ) - ) - - -def get_availability_zone(conn, vm_): - ''' - Return the availability zone to use - ''' - avz = config.get_cloud_config_value( - 'availability_zone', vm_, __opts__, search_global=False - ) - - locations = conn.list_locations() - - if avz is None: - # Default to first zone - return locations[0] - - for loc in locations: - if loc.availability_zone.name == avz: - return loc - - -def create(vm_): - ''' - Create a single VM from a data dict - ''' - try: - # Check for required profile parameters before sending any API calls. - if vm_['profile'] and config.is_profile_configured(__opts__, - __active_provider_name__ or 'aws', - vm_['profile']) is False: - return False - except AttributeError: - pass - - key_filename = config.get_cloud_config_value( - 'private_key', vm_, __opts__, search_global=False, default=None - ) - if key_filename is not None and not os.path.isfile(key_filename): - raise SaltCloudConfigError( - 'The defined key_filename \'{0}\' does not exist'.format( - key_filename - ) - ) - - location = get_location(vm_) - log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location)) - conn = get_conn(location=location) - usernames = ssh_username(vm_) - kwargs = { - 'ssh_key': config.get_cloud_config_value( - 'private_key', vm_, __opts__, search_global=False - ), - 'name': vm_['name'], - 'image': get_image(conn, vm_), - 'size': get_size(conn, vm_), - 'location': get_availability_zone(conn, vm_) - } - ex_keyname = keyname(vm_) - if ex_keyname: - kwargs['ex_keyname'] = ex_keyname - ex_securitygroup = securitygroup(vm_) - if ex_securitygroup: - kwargs['ex_securitygroup'] = ex_securitygroup - ex_blockdevicemappings = block_device_mappings(vm_) - if ex_blockdevicemappings: - kwargs['ex_blockdevicemappings'] = ex_blockdevicemappings - - ex_iam_profile = iam_profile(vm_) - if ex_iam_profile: - # libcloud does not implement 'iam_profile' yet. - # A pull request has been suggested - # https://github.com/apache/libcloud/pull/150 - raise SaltCloudConfigError( - 'libcloud does not implement \'iam_profile\' yet. ' - 'Use EC2 driver instead.' - ) - - tags = config.get_cloud_config_value('tag', vm_, __opts__, {}, search_global=False) - if not isinstance(tags, dict): - raise SaltCloudConfigError( - '\'tag\' should be a dict.' - ) - kwargs['ex_metadata'] = config.get_cloud_config_value('metadata', vm_, __opts__, default={}, search_global=False) - if not isinstance(kwargs['ex_metadata'], dict): - raise SaltCloudConfigError( - '\'metadata\' should be a dict.' - ) - - try: - data = conn.create_node(**kwargs) - except Exception as exc: - log.error( - 'Error creating {0} on AWS\n\n' - 'The following exception was thrown by libcloud when trying to ' - 'run the initial deployment: {1}\n'.format( - vm_['name'], exc - ), - # Show the traceback if the debug logging level is enabled - exc_info_on_loglevel=logging.DEBUG - ) - return False - - log.info('Created node {0}'.format(vm_['name'])) - - def __get_node_data(conn, vm_name): - data = get_node(conn, vm_name) - - if data is None: - # Trigger a failure in the waiting function - return False - - if ssh_interface(vm_) == 'private_ips' and data.private_ips: - return data - - if ssh_interface(vm_) == 'public_ips' and data.public_ips: - return data - - try: - data = salt.utils.cloud.wait_for_ip( - __get_node_data, - update_args=(conn, vm_['name']), - timeout=config.get_cloud_config_value( - 'wait_for_ip_timeout', vm_, __opts__, default=5 * 60), - interval=config.get_cloud_config_value( - 'wait_for_ip_interval', vm_, __opts__, default=0.5), - ) - except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: - try: - # It might be already up, let's destroy it! - destroy(vm_['name']) - except SaltCloudSystemExit: - pass - finally: - raise SaltCloudSystemExit(str(exc)) - - if tags: - set_tags(vm_['name'], tags, call='action') - - if ssh_interface(vm_) == 'private_ips': - log.info('Salt node data. Private_ip: {0}'.format(data.private_ips[0])) - ip_address = data.private_ips[0] - else: - log.info('Salt node data. Public_ip: {0}'.format(data.public_ips[0])) - ip_address = data.public_ips[0] - - if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': - salt_ip_address = data.private_ips[0] - log.info('Salt interface set to: {0}'.format(salt_ip_address)) - else: - salt_ip_address = data.public_ips[0] - log.debug('Salt interface set to: {0}'.format(salt_ip_address)) - - username = 'ec2-user' - ssh_connect_timeout = config.get_cloud_config_value( - 'ssh_connect_timeout', vm_, __opts__, 900 # 15 minutes - ) - ssh_port = config.get_cloud_config_value( - 'ssh_port', vm_, __opts__, 22 - ) - if salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): - for user in usernames: - if salt.utils.cloud.wait_for_passwd( - host=ip_address, - username=user, - ssh_timeout=config.get_cloud_config_value( - 'wait_for_passwd_timeout', vm_, __opts__, - default=1 * 60 - ), - key_filename=key_filename, - known_hosts_file=config.get_cloud_config_value( - 'known_hosts_file', vm_, __opts__, - default='/dev/null' - ), - ): - username = user - break - else: - raise SaltCloudSystemExit( - 'Failed to authenticate against remote ssh' - ) - - ret = {} - if config.get_cloud_config_value('deploy', vm_, __opts__) is True: - deploy_script = script(vm_) - deploy_kwargs = { - 'opts': __opts__, - 'host': ip_address, - 'port': ssh_port, - 'salt_host': salt_ip_address, - 'username': username, - 'key_filename': key_filename, - 'tmp_dir': config.get_cloud_config_value( - 'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud' - ), - 'deploy_command': config.get_cloud_config_value( - 'deploy_command', vm_, __opts__, - default='/tmp/.saltcloud/deploy.sh', - ), - 'tty': config.get_cloud_config_value( - 'tty', vm_, __opts__, default=True - ), - 'script': deploy_script.script, - 'name': vm_['name'], - 'sudo': config.get_cloud_config_value( - 'sudo', vm_, __opts__, default=(username != 'root') - ), - 'sudo_password': config.get_cloud_config_value( - 'sudo_password', vm_, __opts__, default=None - ), - 'start_action': __opts__['start_action'], - 'parallel': __opts__['parallel'], - 'conf_file': __opts__['conf_file'], - 'sock_dir': __opts__['sock_dir'], - 'minion_pem': vm_['priv_key'], - 'minion_pub': vm_['pub_key'], - 'keep_tmp': __opts__['keep_tmp'], - 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), - 'display_ssh_output': config.get_cloud_config_value( - 'display_ssh_output', vm_, __opts__, default=True - ), - 'script_args': config.get_cloud_config_value( - 'script_args', vm_, __opts__ - ), - 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), - 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) - } - - # Deploy salt-master files, if necessary - if config.get_cloud_config_value('make_master', vm_, __opts__) is True: - deploy_kwargs['make_master'] = True - deploy_kwargs['master_pub'] = vm_['master_pub'] - deploy_kwargs['master_pem'] = vm_['master_pem'] - master_conf = salt.utils.cloud.master_config(__opts__, vm_) - deploy_kwargs['master_conf'] = master_conf - - if master_conf.get('syndic_master', None): - deploy_kwargs['make_syndic'] = True - - deploy_kwargs['make_minion'] = config.get_cloud_config_value( - 'make_minion', vm_, __opts__, default=True - ) - - # Check for Windows install params - win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__) - if win_installer: - deploy_kwargs['win_installer'] = win_installer - minion = salt.utils.cloud.minion_config(__opts__, vm_) - deploy_kwargs['master'] = minion['master'] - deploy_kwargs['username'] = config.get_cloud_config_value( - 'win_username', vm_, __opts__, default='Administrator' - ) - deploy_kwargs['password'] = config.get_cloud_config_value( - 'win_password', vm_, __opts__, default='' - ) - - # Store what was used to the deploy the VM - ret['deploy_kwargs'] = deploy_kwargs - - deployed = False - if win_installer: - deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs) - else: - deployed = salt.utils.cloud.deploy_script(**deploy_kwargs) - - if deployed: - log.info('Salt installed on {name}'.format(**vm_)) - else: - log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_)) - - ret.update(data.__dict__) - - log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) - log.debug( - '\'{0[name]}\' VM creation details:\n{1}'.format( - vm_, pprint.pformat(data.__dict__) - ) - ) - - volumes = config.get_cloud_config_value( - 'volumes', vm_, __opts__, search_global=True - ) - if volumes: - log.info('Create and attach volumes to node {0}'.format(data.name)) - create_attach_volumes(volumes, location, data) - - return ret - - -def create_attach_volumes(volumes, location, data): - ''' - Create and attach volumes to created node - ''' - conn = get_conn(location=location) - node_avz = data.__dict__.get('extra').get('availability') - avz = None - for avz in conn.list_locations(): - if avz.availability_zone.name == node_avz: - break - for volume in volumes: - volume_name = '{0} on {1}'.format(volume['device'], data.name) - created_volume = conn.create_volume(volume['size'], volume_name, avz) - attach = conn.attach_volume(data, created_volume, volume['device']) - if attach: - log.info( - '{0} attached to {1} (aka {2}) as device {3}'.format( - created_volume.id, data.id, data.name, volume['device'] - ) - ) - - -def stop(name, call=None): - ''' - Stop a node - ''' - data = {} - - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - try: - data = conn.ex_stop_node(node=node) - log.debug(data) - log.info('Stopped node {0}'.format(name)) - except Exception: - log.error('Failed to stop node {0}\n'.format(name), exc_info=True) - - return data - - -def start(name, call=None): - ''' - Start a node - ''' - data = {} - - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - try: - data = conn.ex_start_node(node=node) - log.debug(data) - log.info('Started node {0}'.format(name)) - except Exception: - log.error('Failed to start node {0}\n'.format(name), exc_info=True) - - return data - - -def set_tags(name, tags, call=None): - ''' - Set tags for a node - - CLI Example: - - .. code-block:: bash - - salt-cloud -a set_tags mymachine tag1=somestuff tag2='Other stuff' - ''' - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - try: - log.info('Setting tags for {0}'.format(name)) - conn.ex_create_tags(resource=node, tags=tags) - - # print the new tags- with special handling for renaming of a node - if 'Name' in tags: - return get_tags(tags['Name']) - return get_tags(name) - except Exception: - log.error('Failed to set tags for {0}\n'.format(name), exc_info=True) - - -def get_tags(name, call=None): - ''' - Retrieve tags for a node - ''' - data = {} - - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - try: - log.info('Retrieving tags from {0}'.format(name)) - data = conn.ex_describe_tags(resource=node) - log.info(data) - except Exception: - log.error( - 'Failed to retrieve tags from {0}\n'.format(name), - exc_info=True - ) - - return data - - -def del_tags(name, kwargs, call=None): - ''' - Delete tags for a node - - CLI Example: - - .. code-block:: bash - - salt-cloud -a del_tags mymachine tag1,tag2,tag3 - ''' - ret = {} - - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - current_tags = conn.ex_describe_tags(resource=node) - - tags = {} - for tag in kwargs['tags'].split(','): - tags[tag] = current_tags[tag] - - try: - conn.ex_delete_tags(resource=node, tags=tags) - log.info('Deleting tags from {0}'.format(name)) - ret = get_tags(name) - except Exception: - log.error( - 'Failed to delete tags from {0}\n'.format(name), - exc_info=True - ) - - return ret - - -def rename(name, kwargs, call=None): - ''' - Properly rename a node. Pass in the new name as "new name". - - CLI Example: - - .. code-block:: bash - - salt-cloud -a rename mymachine newname=yourmachine - ''' - if call != 'action': - raise SaltCloudSystemExit( - 'This action must be called with -a or --action.' - ) - - location = get_location() - conn = get_conn(location=location) - node = get_node(conn, name) - tags = {'Name': kwargs['newname']} - try: - log.info('Renaming {0} to {1}'.format(name, kwargs['newname'])) - conn.ex_create_tags(resource=node, tags=tags) - salt.utils.cloud.rename_key( - __opts__['pki_dir'], name, kwargs['newname'] - ) - except Exception as exc: - log.error( - 'Failed to rename {0} to {1}: {2}\n'.format( - name, kwargs['newname'], exc - ), - # Show the traceback if the debug logging level is enabled - exc_info_on_loglevel=logging.DEBUG - ) - return kwargs['newname'] - - -def destroy(name): - ''' - Wrap core libcloudfuncs destroy method, adding check for termination - protection - ''' - ret = {} - - newname = name - - # Default behavior is to rename AWS VMs when destroyed - # via salt-cloud, unless explicitly set to False. - rename_on_destroy = config.get_cloud_config_value('rename_on_destroy', - get_configured_provider(), - __opts__, - search_global=False) - if rename_on_destroy is not False: - newname = '{0}-DEL{1}'.format(name, uuid.uuid4().hex) - rename(name, kwargs={'newname': newname}, call='action') - log.info( - 'Machine will be identified as {0} until it has been ' - 'cleaned up by AWS.'.format( - newname - ) - ) - ret['newname'] = newname - - try: - result = libcloudfuncs_destroy(newname, get_conn()) - ret.update({'Destroyed': result}) - except Exception as exc: - if not str(exc).startswith('OperationNotPermitted'): - log.exception(exc) - raise exc - - log.info( - 'Failed: termination protection is enabled on {0}'.format( - name - ) - ) - - if __opts__.get('update_cachedir', False) is True: - salt.utils.cloud.delete_minion_cachedir(name, __active_provider_name__.split(':')[0], __opts__) - - return ret diff --git a/salt/cloud/clouds/linode.py b/salt/cloud/clouds/linode.py index e762925355c9..3c68cf5de35d 100644 --- a/salt/cloud/clouds/linode.py +++ b/salt/cloud/clouds/linode.py @@ -333,7 +333,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'linode', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass @@ -558,7 +559,7 @@ def create_config(kwargs=None, call=None): data_disk_id The Data Disk ID to be used for this config. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 kernel_id The ID of the kernel to use for this configuration profile. @@ -679,7 +680,7 @@ def create_data_disk(vm_=None, linode_id=None, data_size=None): r''' Create a data disk for the linode (type is hardcoded to ext4 at the moment) - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vm\_ The VM profile to create the data disk for. @@ -834,7 +835,7 @@ def get_data_disk_size(vm_, swap, linode_id): ''' Return the size of of the data disk in MB - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' disk_size = get_linode(kwargs={'linode_id': linode_id})['TOTALHD'] root_disk_size = config.get_cloud_config_value( @@ -1044,7 +1045,7 @@ def get_data_disk(vm_): ''' Return True if a data disk is requested - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' return config.get_cloud_config_value( 'allocate_data_disk', vm_, __opts__, default=False diff --git a/salt/cloud/clouds/msazure.py b/salt/cloud/clouds/msazure.py index 3bee28e185ed..b1e0090296e4 100644 --- a/salt/cloud/clouds/msazure.py +++ b/salt/cloud/clouds/msazure.py @@ -411,7 +411,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'azure', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/nova.py b/salt/cloud/clouds/nova.py index 8ac144c0b7c8..d0a073efb5e9 100644 --- a/salt/cloud/clouds/nova.py +++ b/salt/cloud/clouds/nova.py @@ -431,6 +431,17 @@ def rackconnect(vm_): ) +def rackconnectv3(vm_): + ''' + Determine if server is using rackconnectv3 or not + Return the rackconnect network name or False + ''' + return config.get_cloud_config_value( + 'rackconnectv3', vm_, __opts__, default=False, + search_global=False + ) + + def cloudnetwork(vm_): ''' Determine if we should use an extra network to bootstrap @@ -649,7 +660,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'nova', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass @@ -734,35 +746,11 @@ def __query_node_data(vm_, data): # Still not running, trigger another iteration return - rackconnectv3 = config.get_cloud_config_value( - 'rackconnectv3', vm_, __opts__, default=False, - search_global=False - ) - - if rackconnectv3: - networkname = rackconnectv3 - for network in node['addresses'].get(networkname, []): - if network['version'] is 4: - access_ip = network['addr'] - break - vm_['rackconnect'] = True - - if ssh_interface(vm_) in node['addresses']: - networkname = ssh_interface(vm_) - for network in node['addresses'].get(networkname, []): - if network['version'] is 4: - node['extra']['access_ip'] = network['addr'] - access_ip = network['addr'] - break - vm_['cloudnetwork'] = True - if rackconnect(vm_) is True: extra = node.get('extra', {}) rc_status = extra.get('metadata', {}).get( 'rackconnect_automation_status', '') - access_ip = extra.get('access_ip', '') - - if rc_status != 'DEPLOYED' and not rackconnectv3: + if rc_status != 'DEPLOYED': log.debug('Waiting for Rackconnect automation to complete') return @@ -777,6 +765,39 @@ def __query_node_data(vm_, data): log.debug('Waiting for managed cloud automation to complete') return + access_ip = node.get('extra', {}).get('access_ip', '') + + rcv3 = rackconnectv3(vm_) in node['addresses'] + sshif = ssh_interface(vm_) in node['addresses'] + + if any((rcv3, sshif)): + networkname = rackconnectv3(vm_) if rcv3 else ssh_interface(vm_) + for network in node['addresses'].get(networkname, []): + if network['version'] is 4: + access_ip = network['addr'] + break + vm_['cloudnetwork'] = True + + # Conditions to pass this + # + # Rackconnect v2: vm_['rackconnect'] = True + # If this is True, then the server will not be accessible from the ipv4 addres in public_ips. + # That interface gets turned off, and an ipv4 from the dedicated firewall is routed to the + # server. In this case we can use the private_ips for ssh_interface, or the access_ip. + # + # Rackconnect v3: vm['rackconnectv3'] = + # If this is the case, salt will need to use the cloud network to login to the server. There + # is no ipv4 address automatically provisioned for these servers when they are booted. SaltCloud + # also cannot use the private_ips, because that traffic is dropped at the hypervisor. + # + # CloudNetwork: vm['cloudnetwork'] = True + # If this is True, then we should have an access_ip at this point set to the ip on the cloud + # network. If that network does not exist in the 'addresses' dictionary, then SaltCloud will + # use the initial access_ip, and not overwrite anything. + if any((cloudnetwork(vm_), rackconnect(vm_))) and (ssh_interface(vm_) != 'private_ips' or rcv3): + data.public_ips = [access_ip, ] + return data + result = [] if 'private_ips' not in node and 'public_ips' not in node and \ @@ -808,10 +829,6 @@ def __query_node_data(vm_, data): if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) - if rackconnect(vm_) is True and (ssh_interface(vm_) != 'private_ips' or rackconnectv3): - data.public_ips = [access_ip, ] - return data - # populate return data with private_ips # when ssh_interface is set to private_ips and public_ips exist if not result and ssh_interface(vm_) == 'private_ips': @@ -820,10 +837,6 @@ def __query_node_data(vm_, data): if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) - if cloudnetwork(vm_) is True: - data.public_ips = access_ip - return data - if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': @@ -857,8 +870,6 @@ def __query_node_data(vm_, data): if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) - elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips': - ip_address = data.public_ips else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) @@ -866,8 +877,6 @@ def __query_node_data(vm_, data): if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) - elif rackconnect(vm_) is True and salt.utils.cloud.get_salt_interface(vm_, __opts__) != 'private_ips': - salt_ip_address = data.public_ips else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) @@ -939,7 +948,11 @@ def list_nodes(call=None, **kwargs): if not server_list: return {} for server in server_list: - server_tmp = conn.server_show(server_list[server]['id'])[server] + server_tmp = conn.server_show(server_list[server]['id']).get(server) + + # If the server is deleted while looking it up, skip + if server_tmp is None: + continue private = [] public = [] @@ -1172,7 +1185,7 @@ def floating_ip_pool_list(call=None): ''' List all floating IP pools - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'function': raise SaltCloudSystemExit( @@ -1187,7 +1200,7 @@ def floating_ip_list(call=None): ''' List floating IPs - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'function': raise SaltCloudSystemExit( @@ -1202,7 +1215,7 @@ def floating_ip_create(kwargs, call=None): ''' Allocate a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'function': raise SaltCloudSystemExit( @@ -1221,7 +1234,7 @@ def floating_ip_delete(kwargs, call=None): ''' De-allocate floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'function': raise SaltCloudSystemExit( @@ -1240,7 +1253,7 @@ def floating_ip_associate(name, kwargs, call=None): ''' Associate a floating IP address to a server - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'action': raise SaltCloudSystemExit( @@ -1260,7 +1273,7 @@ def floating_ip_disassociate(name, kwargs, call=None): ''' Disassociate a floating IP from a server - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call != 'action': raise SaltCloudSystemExit( diff --git a/salt/cloud/clouds/opennebula.py b/salt/cloud/clouds/opennebula.py index 028b75ceca31..b19ddb1e6aad 100644 --- a/salt/cloud/clouds/opennebula.py +++ b/salt/cloud/clouds/opennebula.py @@ -197,7 +197,7 @@ def list_clusters(call=None): ''' Returns a list of clusters in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -225,7 +225,7 @@ def list_datastores(call=None): ''' Returns a list of data stores on OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -253,7 +253,7 @@ def list_hosts(call=None): ''' Returns a list of hosts on OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -331,7 +331,7 @@ def list_security_groups(call=None): ''' Lists all security groups available to the user and the user's groups. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -359,7 +359,7 @@ def list_templates(call=None): ''' Lists all templates available to the user and the user's groups. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -387,7 +387,7 @@ def list_vns(call=None): ''' Lists all virtual networks available to the user and the user's groups. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -415,7 +415,7 @@ def reboot(name, call=None): ''' Reboot a VM. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to reboot. @@ -440,7 +440,7 @@ def start(name, call=None): ''' Start a VM. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to start. @@ -465,7 +465,7 @@ def stop(name, call=None): ''' Stop a VM. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to stop. @@ -490,7 +490,7 @@ def get_cluster_id(kwargs=None, call=None): ''' Returns a cluster's ID from the given cluster name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -526,7 +526,7 @@ def get_datastore_id(kwargs=None, call=None): ''' Returns a data store's ID from the given data store name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -562,7 +562,7 @@ def get_host_id(kwargs=None, call=None): ''' Returns a host's ID from the given host name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -617,7 +617,7 @@ def get_image_id(kwargs=None, call=None): ''' Returns an image's ID from the given image name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -679,7 +679,7 @@ def get_secgroup_id(kwargs=None, call=None): ''' Returns a security group's ID from the given security group name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -715,7 +715,7 @@ def get_template_id(kwargs=None, call=None): ''' Returns a template's ID from the given template name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -751,7 +751,7 @@ def get_vm_id(kwargs=None, call=None): ''' Returns a virtual machine's ID from the given virtual machine's name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -787,7 +787,7 @@ def get_vn_id(kwargs=None, call=None): ''' Returns a virtual network's ID from the given virtual network's name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -865,6 +865,8 @@ def create(vm_): 'image_id': get_image(vm_), 'region_id': get_location(vm_), } + if 'template' in vm_: + kwargs['image_id'] = get_template_id({'name': vm_['template']}) private_networking = config.get_cloud_config_value( 'private_networking', vm_, __opts__, search_global=False, default=None @@ -884,7 +886,7 @@ def create(vm_): try: server, user, password = _get_xml_rpc() auth = ':'.join([user, password]) - server.one.template.instantiate(auth, + cret = server.one.template.instantiate(auth, int(kwargs['image_id']), kwargs['name'], False, @@ -902,6 +904,10 @@ def create(vm_): ) return False + fqdn = vm_.get('fqdn_base') + if fqdn is not None: + fqdn = '{0}.{1}'.format(vm_['name'], fqdn) + def __query_node_data(vm_name): node_data = show_instance(vm_name, call='action') if not node_data: @@ -940,10 +946,15 @@ def __query_node_data(vm_name): ) ) - try: - private_ip = data['private_ips'][0] - except KeyError: - private_ip = data['template']['nic']['ip'] + if fqdn: + vm_['ssh_host'] = fqdn + private_ip = '0.0.0.0' + else: + try: + private_ip = data['private_ips'][0] + except KeyError: + private_ip = data['template']['nic']['ip'] + vm_['ssh_host'] = private_ip ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' @@ -951,7 +962,6 @@ def __query_node_data(vm_name): vm_['username'] = ssh_username vm_['key_filename'] = key_filename - vm_['ssh_host'] = private_ip ret = salt.utils.cloud.bootstrap(vm_, __opts__) @@ -1048,7 +1058,7 @@ def image_allocate(call=None, kwargs=None): ''' Allocates a new image in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 path The path to a file containing the template of the image to allocate. @@ -1135,7 +1145,7 @@ def image_clone(call=None, kwargs=None): ''' Clones an existing image. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the new image. @@ -1204,7 +1214,7 @@ def image_delete(call=None, kwargs=None): Deletes the given image from OpenNebula. Either a name or an image_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the image to delete. Can be used instead of ``image_id``. @@ -1263,7 +1273,7 @@ def image_info(call=None, kwargs=None): Retrieves information for a given image. Either a name or an image_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the image for which to gather information. Can be used instead @@ -1320,7 +1330,7 @@ def image_persistent(call=None, kwargs=None): ''' Sets the Image as persistent or not persistent. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the image to set. Can be used instead of ``image_id``. @@ -1389,7 +1399,7 @@ def image_snapshot_delete(call=None, kwargs=None): ''' Deletes a snapshot from the image. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 image_id The ID of the image from which to delete the snapshot. Can be used instead of @@ -1458,7 +1468,7 @@ def image_snapshot_revert(call=None, kwargs=None): ''' Reverts an image state to a previous snapshot. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 image_id The ID of the image to revert. Can be used instead of ``image_name``. @@ -1525,7 +1535,7 @@ def image_snapshot_flatten(call=None, kwargs=None): ''' Flattens the snapshot of an image and discards others. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 image_id The ID of the image. Can be used instead of ``image_name``. @@ -1593,7 +1603,7 @@ def image_update(call=None, kwargs=None): ''' Replaces the image template contents. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 image_id The ID of the image to update. Can be used instead of ``image_name``. @@ -1729,7 +1739,7 @@ def secgroup_allocate(call=None, kwargs=None): ''' Allocates a new security group in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 path The path to a file containing the template of the security group. Syntax @@ -1792,7 +1802,7 @@ def secgroup_clone(call=None, kwargs=None): ''' Clones an existing security group. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the new template. @@ -1863,7 +1873,7 @@ def secgroup_delete(call=None, kwargs=None): Deletes the given security group from OpenNebula. Either a name or a secgroup_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the security group to delete. Can be used instead of @@ -1923,7 +1933,7 @@ def secgroup_info(call=None, kwargs=None): Retrieves information for the given security group. Either a name or a secgroup_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the security group for which to gather information. Can be @@ -1980,7 +1990,7 @@ def secgroup_update(call=None, kwargs=None): ''' Replaces the security group template contents. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 secgroup_id The ID of the security group to update. Can be used instead of @@ -2091,7 +2101,7 @@ def template_allocate(call=None, kwargs=None): ''' Allocates a new template in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 path The path to a file containing the elements of the template to be allocated. @@ -2156,7 +2166,7 @@ def template_clone(call=None, kwargs=None): ''' Clones an existing virtual machine template. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the new template. @@ -2226,7 +2236,7 @@ def template_delete(call=None, kwargs=None): Deletes the given template from OpenNebula. Either a name or a template_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the template to delete. Can be used instead of ``template_id``. @@ -2284,7 +2294,7 @@ def template_instantiate(call=None, kwargs=None): ''' Instantiates a new virtual machine from a template. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. note:: ``template_instantiate`` creates a VM on OpenNebula from a template, but it @@ -2359,7 +2369,7 @@ def template_update(call=None, kwargs=None): ''' Replaces the template contents. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 template_id The ID of the template to update. Can be used instead of ``template_name``. @@ -2470,7 +2480,7 @@ def vm_action(name, kwargs=None, call=None): ''' Submits an action to be performed on a given virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to action. @@ -2535,7 +2545,7 @@ def vm_allocate(call=None, kwargs=None): ''' Allocates a new virtual machine in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 path The path to a file defining the template of the VM to allocate. @@ -2602,7 +2612,7 @@ def vm_attach(name, kwargs=None, call=None): ''' Attaches a new disk to the given virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM for which to attach the new disk. @@ -2668,7 +2678,7 @@ def vm_attach_nic(name, kwargs=None, call=None): ''' Attaches a new network interface to the given virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM for which to attach the new network interface. @@ -2734,7 +2744,7 @@ def vm_deploy(name, kwargs=None, call=None): ''' Initiates the instance of the given VM on the target host. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to deploy. @@ -2833,7 +2843,7 @@ def vm_detach(name, kwargs=None, call=None): ''' Detaches a disk from a virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM from which to detach the disk. @@ -2880,7 +2890,7 @@ def vm_detach_nic(name, kwargs=None, call=None): ''' Detaches a disk from a virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM from which to detach the network interface. @@ -2927,7 +2937,7 @@ def vm_disk_save(name, kwargs=None, call=None): ''' Sets the disk to be saved in the given image. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM containing the disk to save. @@ -2997,7 +3007,7 @@ def vm_disk_snapshot_create(name, kwargs=None, call=None): ''' Takes a new snapshot of the disk image. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM of which to take the snapshot. @@ -3053,7 +3063,7 @@ def vm_disk_snapshot_delete(name, kwargs=None, call=None): ''' Deletes a disk snapshot based on the given VM and the disk_id. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM containing the snapshot to delete. @@ -3109,7 +3119,7 @@ def vm_disk_snapshot_revert(name, kwargs=None, call=None): ''' Reverts a disk state to a previously taken snapshot. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM containing the snapshot. @@ -3165,7 +3175,7 @@ def vm_info(name, call=None): ''' Retrieves information for a given virtual machine. A VM name must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM for which to gather information. @@ -3199,7 +3209,7 @@ def vm_migrate(name, kwargs=None, call=None): ''' Migrates the specified virtual machine to the specified target host. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to migrate. @@ -3308,7 +3318,7 @@ def vm_monitoring(name, call=None): contains the complete dictionary of the VM with the updated information returned by the poll action. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM for which to gather monitoring records. @@ -3346,7 +3356,7 @@ def vm_resize(name, kwargs=None, call=None): ''' Changes the capacity of the virtual machine. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to resize. @@ -3420,7 +3430,7 @@ def vm_snapshot_create(vm_name, kwargs=None, call=None): ''' Creates a new virtual machine snapshot from the provided VM. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vm_name The name of the VM from which to create the snapshot. @@ -3467,7 +3477,7 @@ def vm_snapshot_delete(vm_name, kwargs=None, call=None): ''' Deletes a virtual machine snapshot from the provided VM. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vm_name The name of the VM from which to delete the snapshot. @@ -3514,7 +3524,7 @@ def vm_snapshot_revert(vm_name, kwargs=None, call=None): ''' Reverts a virtual machine to a snapshot - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vm_name The name of the VM to revert. @@ -3561,7 +3571,7 @@ def vm_update(name, kwargs=None, call=None): ''' Replaces the user template contents. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the VM to update. @@ -3647,7 +3657,7 @@ def vn_add_ar(call=None, kwargs=None): ''' Adds address ranges to a given virtual network. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vn_id The ID of the virtual network to add the address range. Can be used @@ -3733,7 +3743,7 @@ def vn_allocate(call=None, kwargs=None): ''' Allocates a new virtual network in OpenNebula. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 path The path to a file containing the template of the virtual network to allocate. @@ -3817,7 +3827,7 @@ def vn_delete(call=None, kwargs=None): Deletes the given virtual network from OpenNebula. Either a name or a vn_id must be supplied. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the virtual network to delete. Can be used instead of ``vn_id``. @@ -3875,7 +3885,7 @@ def vn_free_ar(call=None, kwargs=None): ''' Frees a reserved address range from a virtual network. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vn_id The ID of the virtual network from which to free an address range. @@ -3944,7 +3954,7 @@ def vn_hold(call=None, kwargs=None): ''' Holds a virtual network lease as used. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vn_id The ID of the virtual network from which to hold the lease. Can be used @@ -4029,7 +4039,7 @@ def vn_info(call=None, kwargs=None): ''' Retrieves information for the virtual network. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The name of the virtual network for which to gather information. Can be @@ -4088,7 +4098,7 @@ def vn_release(call=None, kwargs=None): ''' Releases a virtual network lease that was previously on hold. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vn_id The ID of the virtual network from which to release the lease. Can be @@ -4173,7 +4183,7 @@ def vn_reserve(call=None, kwargs=None): ''' Reserve network addresses. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 vn_id The ID of the virtual network from which to reserve addresses. Can be used @@ -4334,7 +4344,10 @@ def _list_nodes(full=False): private_ips = [] for nic in vm.find('TEMPLATE').findall('NIC'): - private_ips.append(nic.find('IP').text) + try: + private_ips.append(nic.find('IP').text) + except Exception: + pass vms[name]['id'] = vm.find('ID').text vms[name]['image'] = vm.find('TEMPLATE').find('TEMPLATE_ID').text diff --git a/salt/cloud/clouds/openstack.py b/salt/cloud/clouds/openstack.py index c2730f3573c4..880c543cb80e 100644 --- a/salt/cloud/clouds/openstack.py +++ b/salt/cloud/clouds/openstack.py @@ -556,7 +556,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'openstack', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/parallels.py b/salt/cloud/clouds/parallels.py index e2457a569dbf..658344ccb0fa 100644 --- a/salt/cloud/clouds/parallels.py +++ b/salt/cloud/clouds/parallels.py @@ -273,7 +273,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'parallels', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/proxmox.py b/salt/cloud/clouds/proxmox.py index be7cd05a1dfa..2d698368e19e 100644 --- a/salt/cloud/clouds/proxmox.py +++ b/salt/cloud/clouds/proxmox.py @@ -503,7 +503,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'proxmox', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/qingcloud.py b/salt/cloud/clouds/qingcloud.py index 229714168f64..47fcfc43147a 100644 --- a/salt/cloud/clouds/qingcloud.py +++ b/salt/cloud/clouds/qingcloud.py @@ -660,7 +660,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'qingcloud', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/rackspace.py b/salt/cloud/clouds/rackspace.py index 56af9911feed..df1252e6266e 100644 --- a/salt/cloud/clouds/rackspace.py +++ b/salt/cloud/clouds/rackspace.py @@ -194,7 +194,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'rackspace', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/scaleway.py b/salt/cloud/clouds/scaleway.py index 761c4866ed6a..6b604e3dfa9c 100644 --- a/salt/cloud/clouds/scaleway.py +++ b/salt/cloud/clouds/scaleway.py @@ -209,7 +209,8 @@ def create(server_): # Check for required profile parameters before sending any API calls. if server_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'scaleway', - server_['profile']) is False: + server_['profile'], + vm_=server_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/softlayer.py b/salt/cloud/clouds/softlayer.py index b217a314d0e1..eba22191af9b 100644 --- a/salt/cloud/clouds/softlayer.py +++ b/salt/cloud/clouds/softlayer.py @@ -246,7 +246,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'softlayer', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/softlayer_hw.py b/salt/cloud/clouds/softlayer_hw.py index 661ea85e47e9..a39a8ef63b4d 100644 --- a/salt/cloud/clouds/softlayer_hw.py +++ b/salt/cloud/clouds/softlayer_hw.py @@ -217,7 +217,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'softlayer_hw', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass @@ -657,7 +658,7 @@ def show_all_categories(call=None): ''' Return a dict of all available categories on the cloud provider. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if call == 'action': raise SaltCloudSystemExit( diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index cd0ca779a118..f10cfa1f2492 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -475,7 +475,7 @@ def _add_new_ide_controller_helper(ide_controller_label, properties, bus_number) ''' Helper function for adding new IDE controllers - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' random_key = randint(-200, -250) @@ -2107,7 +2107,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'vmware', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/vsphere.py b/salt/cloud/clouds/vsphere.py index f7738bbc0f5b..0a737a5898f5 100644 --- a/salt/cloud/clouds/vsphere.py +++ b/salt/cloud/clouds/vsphere.py @@ -245,7 +245,8 @@ def create(vm_): # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'vsphere', - vm_['profile']) is False: + vm_['profile'], + vm_=vm_) is False: return False except AttributeError: pass diff --git a/salt/cloud/clouds/vultrpy.py b/salt/cloud/clouds/vultrpy.py index fa48263780d4..5efa4a64fa72 100644 --- a/salt/cloud/clouds/vultrpy.py +++ b/salt/cloud/clouds/vultrpy.py @@ -3,7 +3,7 @@ Vultr Cloud Module using python-vultr bindings ============================================== -.. versionadded:: Boron +.. versionadded:: 2016.3.0 The Vultr cloud module is used to control access to the Vultr VPS system. diff --git a/salt/config/__init__.py b/salt/config/__init__.py index f8b0786dd2b8..9d7145c53459 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -14,6 +14,7 @@ import codecs import logging from copy import deepcopy +import types # Import third party libs import yaml @@ -54,10 +55,8 @@ # support in ZeroMQ, we want the default to be something that has a # chance of working. _DFLT_IPC_MODE = 'tcp' - _DFLT_MULTIPROCESSING_MODE = False else: _DFLT_IPC_MODE = 'ipc' - _DFLT_MULTIPROCESSING_MODE = True FLO_DIR = os.path.join( os.path.dirname(__file__), @@ -231,9 +230,15 @@ # A flag indicating that a master should accept any minion connection without any authentication 'open_mode': bool, - # Whether or not processes should be forked when needed. The altnerative is to use threading. + # Whether or not processes should be forked when needed. The alternative is to use threading. 'multiprocessing': bool, + # Whether or not the salt minion should run scheduled mine updates + 'mine_enabled': bool, + + # Whether or not scheduled mine updates should be accompanied by a job return for the job cache + 'mine_return_job': bool, + # Schedule a mine update every n number of seconds 'mine_interval': int, @@ -269,7 +274,7 @@ 'log_file': str, # The level of verbosity at which to log - 'log_level': bool, + 'log_level': str, # The log level to log to a given file 'log_level_logfile': bool, @@ -445,7 +450,7 @@ # Add the proxymodule LazyLoader object to opts. This breaks many things # but this was the default pre 2015.8.2. This should default to - # False in Boron + # False in 2016.3.0 'add_proxymodule_to_opts': bool, 'git_pillar_base': str, 'git_pillar_branch': str, @@ -537,6 +542,8 @@ 'runner_dirs': list, 'client_acl': dict, 'client_acl_blacklist': dict, + 'publisher_acl': dict, + 'publisher_acl_blacklist': dict, 'sudo_acl': bool, 'external_auth': dict, 'token_expire': int, @@ -560,7 +567,8 @@ 'autosign_timeout': int, # A mapping of external systems that can be used to generate topfile data. - 'master_tops': bool, # FIXME Should be dict? + # FIXME Should be dict? + 'master_tops': bool, # A flag that should be set on a top-level master when it is ordering around subordinate masters # via the use of a salt syndic @@ -802,6 +810,7 @@ 'cache_jobs': False, 'grains_cache': False, 'grains_cache_expiration': 300, + 'grains_deep_merge': False, 'conf_file': os.path.join(salt.syspaths.CONFIG_DIR, 'minion'), 'sock_dir': os.path.join(salt.syspaths.SOCK_DIR, 'minion'), 'backup_mode': '', @@ -815,7 +824,7 @@ 'pillar_cache': False, 'pillar_cache_ttl': 3600, 'pillar_cache_backend': 'disk', - 'extension_modules': '', + 'extension_modules': os.path.join(salt.syspaths.CACHE_DIR, 'minion', 'extmods'), 'state_top': 'top.sls', 'state_top_saltenv': None, 'startup_states': '', @@ -886,7 +895,9 @@ 'open_mode': False, 'auto_accept': True, 'autosign_timeout': 120, - 'multiprocessing': _DFLT_MULTIPROCESSING_MODE, + 'multiprocessing': True, + 'mine_enabled': True, + 'mine_return_job': False, 'mine_interval': 60, 'ipc_mode': _DFLT_IPC_MODE, 'ipv6': False, @@ -894,7 +905,7 @@ 'tcp_pub_port': 4510, 'tcp_pull_port': 4511, 'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'minion'), - 'log_level': None, + 'log_level': 'info', 'log_level_logfile': None, 'log_datefmt': _DFLT_LOG_DATEFMT, 'log_datefmt_logfile': _DFLT_LOG_DATEFMT_LOGFILE, @@ -928,8 +939,6 @@ 'recon_randomize': True, 'return_retry_timer': 5, 'return_retry_timer_max': 10, - 'syndic_log_file': os.path.join(salt.syspaths.LOGS_DIR, 'syndic'), - 'syndic_pidfile': os.path.join(salt.syspaths.PIDFILE_DIR, 'salt-syndic.pid'), 'random_reauth_delay': 10, 'winrepo_source_dir': 'salt://win/repo-ng/', 'winrepo_dir': os.path.join(salt.syspaths.BASE_FILE_ROOTS_DIR, 'win', 'repo'), @@ -1091,14 +1100,18 @@ 'peer': {}, 'preserve_minion_cache': False, 'syndic_master': '', + 'syndic_log_file': os.path.join(salt.syspaths.LOGS_DIR, 'syndic'), + 'syndic_pidfile': os.path.join(salt.syspaths.PIDFILE_DIR, 'salt-syndic.pid'), 'runner_dirs': [], 'outputter_dirs': [], 'client_acl': {}, 'client_acl_blacklist': {}, + 'publisher_acl': {}, + 'publisher_acl_blacklist': {}, 'sudo_acl': False, 'external_auth': {}, 'token_expire': 43200, - 'extension_modules': os.path.join(salt.syspaths.CACHE_DIR, 'extmods'), + 'extension_modules': os.path.join(salt.syspaths.CACHE_DIR, 'master', 'extmods'), 'file_recv': False, 'file_recv_max_size': 100, 'file_buffer_size': 1048576, @@ -1132,7 +1145,7 @@ 'tcp_master_publish_pull': 4514, 'tcp_master_workers': 4515, 'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'master'), - 'log_level': None, + 'log_level': 'info', 'log_level_logfile': None, 'log_datefmt': _DFLT_LOG_DATEFMT, 'log_datefmt_logfile': _DFLT_LOG_DATEFMT_LOGFILE, @@ -1186,6 +1199,10 @@ 'syndic_wait': 5, 'jinja_lstrip_blocks': False, 'jinja_trim_blocks': False, + 'tcp_keepalive': True, + 'tcp_keepalive_idle': 300, + 'tcp_keepalive_cnt': -1, + 'tcp_keepalive_intvl': -1, 'sign_pub_messages': False, 'keysize': 2048, 'transport': 'zeromq', @@ -1235,6 +1252,8 @@ 'dummy_pub': False, 'http_request_timeout': 1 * 60 * 60.0, # 1 hour 'http_max_body': 100 * 1024 * 1024 * 1024, # 100GB + 'python2_bin': 'python2', + 'python3_bin': 'python3', } @@ -1270,7 +1289,7 @@ 'deploy_scripts_search_path': 'cloud.deploy.d', # Logging defaults 'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'cloud'), - 'log_level': None, + 'log_level': 'info', 'log_level_logfile': None, 'log_datefmt': _DFLT_LOG_DATEFMT, 'log_datefmt_logfile': _DFLT_LOG_DATEFMT_LOGFILE, @@ -1462,9 +1481,8 @@ def _absolute_path(path, relative_to=None): _abspath = os.path.join(relative_to, path) if os.path.isfile(_abspath): log.debug( - 'Relative path {0!r} converted to existing absolute path {1!r}'.format( - path, _abspath - ) + 'Relative path \'{0}\' converted to existing absolute path ' + '\'{1}\''.format(path, _abspath) ) return _abspath return path @@ -1488,9 +1506,9 @@ def load_config(path, env_var, default_path=None): import inspect previous_frame = inspect.getframeinfo(inspect.currentframe().f_back) log.warning( - 'The function \'{0}()\' defined in {1!r} is not yet using the ' + 'The function \'{0}()\' defined in \'{1}\' is not yet using the ' 'new \'default_path\' argument to `salt.config.load_config()`. ' - 'As such, the {2!r} environment variable will be ignored'.format( + 'As such, the \'{2}\' environment variable will be ignored'.format( previous_frame.function, previous_frame.filename, env_var ) ) @@ -1558,11 +1576,11 @@ def include_config(include, orig_path, verbose): if verbose: log.warn( 'Warning parsing configuration file: "include" path/glob ' - '{0!r} matches no files'.format(path) + '\'{0}\' matches no files'.format(path) ) for fn_ in sorted(glob.glob(path)): - log.debug('Including configuration from {0!r}'.format(fn_)) + log.debug('Including configuration from \'{0}\''.format(fn_)) opts = _read_conf_file(fn_) include = opts.get('include', []) @@ -1982,18 +2000,22 @@ def apply_cloud_config(overrides, defaults=None): for detail in details: if 'provider' not in detail and 'driver' not in detail: raise salt.exceptions.SaltCloudConfigError( - 'The cloud provider alias {0!r} has an entry missing the required setting of either' - '\'provider\' or \'driver\'. Note that \'provider\' has been deprecated, so you should ' - 'use the \'driver\' notation.'.format( + 'The cloud provider alias \'{0}\' has an entry ' + 'missing the required setting of either ' + '\'provider\' or \'driver\'. Note that ' + '\'provider\' has been deprecated, so the ' + '\'driver\' notation should be used.'.format( alias ) ) elif 'provider' in detail: salt.utils.warn_until( 'Nitrogen', - 'The term \'provider\' is being deprecated in favor of \'driver\'. Support for ' - '\'provider\' will be removed in Salt Nitrogen. Please convert your cloud provider ' - 'configuration files to use \'driver\'.' + 'The term \'provider\' is being deprecated in ' + 'favor of \'driver\'. Support for \'provider\' ' + 'will be removed in Salt Nitrogen. Please convert ' + 'your cloud provider configuration files to use ' + '\'driver\'.' ) driver = detail['provider'] elif 'driver' in detail: @@ -2011,17 +2033,17 @@ def apply_cloud_config(overrides, defaults=None): elif isinstance(details, dict): if 'provider' not in details and 'driver' not in details: raise salt.exceptions.SaltCloudConfigError( - 'The cloud provider alias {0!r} has an entry missing the required setting of either' - '\'provider\' or \'driver\''.format( - alias - ) + 'The cloud provider alias \'{0}\' has an entry ' + 'missing the required setting of either ' + '\'provider\' or \'driver\''.format(alias) ) elif 'provider' in details: salt.utils.warn_until( 'Nitrogen', - 'The term \'provider\' is being deprecated in favor of \'driver\' and support for ' - '\'provider\' will be removed in Salt Nitrogen. Please convert your cloud provider' - 'configuration files to use \'driver\'.' + 'The term \'provider\' is being deprecated in favor ' + 'of \'driver\' and support for \'provider\' will be ' + 'removed in Salt Nitrogen. Please convert your cloud ' + 'provider configuration files to use \'driver\'.' ) driver = details['provider'] elif 'driver' in details: @@ -2125,7 +2147,7 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): continue if not isinstance(val, dict): raise salt.exceptions.SaltCloudConfigError( - 'The VM profiles configuration found in {0[conf_file]!r} is ' + 'The VM profiles configuration found in \'{0[conf_file]}\' is ' 'not in the proper format'.format(config) ) val['profile'] = key @@ -2138,10 +2160,13 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): alias, driver = details['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.trace( - 'The profile {0!r} is defining {1[provider]!r} as the ' - 'provider. Since there\'s no valid configuration for ' - 'that provider, the profile will be removed from the ' - 'available listing'.format(profile, details) + 'The profile \'{0}\' is defining \'{1[provider]}\' ' + 'as the provider. Since there is no valid ' + 'configuration for that provider, the profile will be ' + 'removed from the available listing'.format( + profile, + details + ) ) vms.pop(profile) continue @@ -2152,8 +2177,8 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): if details['provider'] not in providers: log.trace( - 'The profile {0!r} is defining {1[provider]!r} as the ' - 'provider. Since there\'s no valid configuration for ' + 'The profile \'{0}\' is defining \'{1[provider]}\' as the ' + 'provider. Since there is no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, details) ) @@ -2171,8 +2196,8 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): extends = details.pop('extends') if extends not in vms: log.error( - 'The {0!r} profile is trying to extend data from {1!r} ' - 'though {1!r} is not defined in the salt profiles loaded ' + 'The \'{0}\' profile is trying to extend data from \'{1}\' ' + 'though \'{1}\' is not defined in the salt profiles loaded ' 'data. Not extending and removing from listing!'.format( profile, extends ) @@ -2187,8 +2212,8 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): if ':' not in extended['provider']: if extended['provider'] not in providers: log.trace( - 'The profile {0!r} is defining {1[provider]!r} as the ' - 'provider. Since there\'s no valid configuration for ' + 'The profile \'{0}\' is defining \'{1[provider]}\' as the ' + 'provider. Since there is no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, extended) ) @@ -2204,10 +2229,10 @@ def apply_vm_profiles_config(providers, overrides, defaults=None): alias, driver = extended['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.trace( - 'The profile {0!r} is defining {1[provider]!r} as the ' - 'provider. Since there\'s no valid configuration for ' - 'that provider, the profile will be removed from the ' - 'available listing'.format(profile, extended) + 'The profile \'{0}\' is defining \'{1[provider]}\' as ' + 'the provider. Since there is no valid configuration ' + 'for that provider, the profile will be removed from ' + 'the available listing'.format(profile, extended) ) vms.pop(profile) continue @@ -2298,8 +2323,8 @@ def apply_cloud_providers_config(overrides, defaults=None): ) continue - # Since using "provider: " is deprecated, alias provider - # to use driver: "driver: " + # Since using "provider: " is deprecated, + # alias provider to use driver: "driver: " if 'provider' in details: details['driver'] = details.pop('provider') @@ -2312,8 +2337,8 @@ def apply_cloud_providers_config(overrides, defaults=None): 'forth.' ) raise salt.exceptions.SaltCloudConfigError( - 'The cloud provider alias {0!r} has multiple entries ' - 'for the {1[driver]!r} driver.'.format(key, details) + 'The cloud provider alias \'{0}\' has multiple entries ' + 'for the \'{1[driver]}\' driver.'.format(key, details) ) handled_providers.add(details['driver']) @@ -2323,8 +2348,9 @@ def apply_cloud_providers_config(overrides, defaults=None): if 'provider' in entry: salt.utils.warn_until( 'Nitrogen', - 'The term \'provider\' is being deprecated in favor of \'driver\'. Support for ' - '\'provider\' will be removed in Salt Nitrogen. Please convert your cloud provider ' + 'The term \'provider\' is being deprecated in favor of ' + '\'driver\'. Support for \'provider\' will be removed in ' + 'Salt Nitrogen. Please convert your cloud provider ' 'configuration files to use \'driver\'.' ) entry['driver'] = entry.pop('provider') @@ -2345,8 +2371,8 @@ def apply_cloud_providers_config(overrides, defaults=None): keep_looping = False for provider_alias, entries in six.iteritems(providers.copy()): for driver, details in six.iteritems(entries): - # Since using "provider: " is deprecated, alias provider - # to use driver: "driver: " + # Since using "provider: " is deprecated, + # alias provider to use driver: "driver: " if 'provider' in details: details['driver'] = details.pop('provider') @@ -2362,10 +2388,10 @@ def apply_cloud_providers_config(overrides, defaults=None): alias, provider = extends.split(':') if alias not in providers: raise salt.exceptions.SaltCloudConfigError( - 'The {0!r} cloud provider entry in {1!r} is ' - 'trying to extend data from {2!r} though {2!r} ' - 'is not defined in the salt cloud providers ' - 'loaded data.'.format( + 'The \'{0}\' cloud provider entry in \'{1}\' is ' + 'trying to extend data from \'{2}\' though ' + '\'{2}\' is not defined in the salt cloud ' + 'providers loaded data.'.format( details['driver'], provider_alias, alias @@ -2374,9 +2400,9 @@ def apply_cloud_providers_config(overrides, defaults=None): if provider not in providers.get(alias): raise salt.exceptions.SaltCloudConfigError( - 'The {0!r} cloud provider entry in {1!r} is ' + 'The \'{0}\' cloud provider entry in \'{1}\' is ' 'trying to extend data from \'{2}:{3}\' though ' - '{3!r} is not defined in {1!r}'.format( + '\'{3}\' is not defined in \'{1}\''.format( details['driver'], provider_alias, alias, @@ -2384,21 +2410,22 @@ def apply_cloud_providers_config(overrides, defaults=None): ) ) details['extends'] = '{0}:{1}'.format(alias, provider) - # change provider details '-only-extendable-' to extended provider name + # change provider details '-only-extendable-' to extended + # provider name details['driver'] = provider elif providers.get(extends): raise salt.exceptions.SaltCloudConfigError( - 'The {0!r} cloud provider entry in {1!r} is trying ' - 'to extend from {2!r} and no provider was specified. ' - 'Not extending!'.format( + 'The \'{0}\' cloud provider entry in \'{1}\' is ' + 'trying to extend from \'{2}\' and no provider was ' + 'specified. Not extending!'.format( details['driver'], provider_alias, extends ) ) elif extends not in providers: raise salt.exceptions.SaltCloudConfigError( - 'The {0!r} cloud provider entry in {1!r} is trying ' - 'to extend data from {2!r} though {2!r} is not ' - 'defined in the salt cloud providers loaded ' + 'The \'{0}\' cloud provider entry in \'{1}\' is ' + 'trying to extend data from \'{2}\' though \'{2}\' ' + 'is not defined in the salt cloud providers loaded ' 'data.'.format( details['driver'], provider_alias, extends ) @@ -2461,7 +2488,7 @@ def apply_cloud_providers_config(overrides, defaults=None): continue log.info( - 'There\'s at least one cloud driver under the {0!r} ' + 'There\'s at least one cloud driver under the \'{0}\' ' 'cloud provider alias which does not have the required ' '\'driver\' setting. Removing it from the available ' 'providers listing.'.format( @@ -2525,7 +2552,7 @@ def get_cloud_config_value(name, vm_, opts, default=None, search_global=True): # and there's more than one entry under the alias. # WARN the user!!!! log.error( - 'The {0!r} cloud provider definition has more than one ' + 'The \'{0}\' cloud provider definition has more than one ' 'entry. Your VM configuration should be specifying the ' 'provider as \'driver: {0}:\'. Since ' 'it\'s not, we\'re returning the first definition which ' @@ -2548,10 +2575,13 @@ def get_cloud_config_value(name, vm_, opts, default=None, search_global=True): if name and vm_ and name in vm_: # The setting name exists in VM configuration. - if isinstance(value, dict): - value.update(vm_[name].copy()) + if isinstance(vm_[name], types.GeneratorType): + value = next(vm_[name], '') else: - value = deepcopy(vm_[name]) + if isinstance(value, dict): + value.update(vm_[name].copy()) + else: + value = deepcopy(vm_[name]) return value @@ -2569,16 +2599,16 @@ def is_provider_configured(opts, provider, required_keys=()): return False for key in required_keys: if opts['providers'][alias][driver].get(key, None) is None: - # There's at least one require configuration key which is not set. + # There's at least one require configuration key which is not + # set. log.warning( - 'The required {0!r} configuration setting is missing from ' - 'the {1!r} driver, which is configured under the {2!r} ' - 'alias.'.format( - key, provider, alias - ) + 'The required \'{0}\' configuration setting is missing ' + 'from the \'{1}\' driver, which is configured under the ' + '\'{2}\' alias.'.format(key, provider, alias) ) return False - # If we reached this far, there's a properly configured provider. Return it! + # If we reached this far, there's a properly configured provider. + # Return it! return opts['providers'][alias][driver] for alias, drivers in six.iteritems(opts['providers']): @@ -2594,9 +2624,9 @@ def is_provider_configured(opts, provider, required_keys=()): # This provider does not include all necessary keys, # continue to next one. log.warning( - 'The required {0!r} configuration setting is missing ' - 'from the {1!r} driver, which is configured under the ' - '{2!r} alias.'.format( + 'The required \'{0}\' configuration setting is ' + 'missing from the \'{1}\' driver, which is configured ' + 'under the \'{2}\' alias.'.format( key, provider, alias ) ) @@ -2613,12 +2643,13 @@ def is_provider_configured(opts, provider, required_keys=()): return False -def is_profile_configured(opts, provider, profile_name): +def is_profile_configured(opts, provider, profile_name, vm_=None): ''' Check if the requested profile contains the minimum required parameters for a profile. - Required parameters include image, provider, and size keys. + Required parameters include image and provider for all drivers, while some + drivers also require size keys. .. versionadded:: 2015.8.0 ''' @@ -2658,20 +2689,25 @@ def is_profile_configured(opts, provider, profile_name): # Check if image and/or size are supplied in the provider config. If either # one is present, remove it from the required_keys list. - for item in required_keys: + for item in list(required_keys): if item in provider_key: required_keys.remove(item) + # If a vm_ dict was passed in, use that information to get any other configs + # that we might have missed thus far, such as a option provided in a map file. + if vm_: + for item in list(required_keys): + if item in vm_: + required_keys.remove(item) + # Check for remaining required parameters in the profile config. for item in required_keys: if profile_key.get(item, None) is None: # There's at least one required configuration item which is not set. log.error( - 'The required {0!r} configuration setting is missing from the ' - '{1!r} profile, which is configured ' - 'under the {2!r} alias.'.format( - item, profile_name, alias - ) + 'The required \'{0}\' configuration setting is missing from ' + 'the \'{1}\' profile, which is configured under the \'{2}\' ' + 'alias.'.format(item, profile_name, alias) ) return False @@ -2802,12 +2838,6 @@ def apply_minion_config(overrides=None, # nothing else! opts['open_mode'] = opts['open_mode'] is True - # set up the extension_modules location from the cachedir - opts['extension_modules'] = ( - opts.get('extension_modules') or - os.path.join(opts['cachedir'], 'extmods') - ) - # Set up the utils_dirs location from the extension_modules location opts['utils_dirs'] = ( opts.get('utils_dirs') or @@ -2973,8 +3003,8 @@ def apply_master_config(overrides=None, defaults=None): # to make `salt.modules.publish` not work under the test-suite. if opts['worker_threads'] < 3 and opts.get('peer', None): log.warning( - 'The \'worker_threads\' setting on {0!r} cannot be lower than 3. ' - 'Resetting it to the default value of 3.'.format( + 'The \'worker_threads\' setting on \'{0}\' cannot be lower than ' + '3. Resetting it to the default value of 3.'.format( opts['conf_file'] ) ) @@ -3109,7 +3139,6 @@ def apply_spm_config(overrides, defaults): Returns the spm configurations dict. .. versionadded:: 2015.8.1 - ''' opts = defaults.copy() if overrides: diff --git a/salt/crypt.py b/salt/crypt.py index 4cbd9bf86d27..cc2ab78c3817 100644 --- a/salt/crypt.py +++ b/salt/crypt.py @@ -59,6 +59,9 @@ def dropfile(cachedir, user=None): mask = os.umask(191) try: log.info('Rotating AES key') + if os.path.isfile(dfn): + log.info('AES key rotation already requested') + return if os.path.isfile(dfn) and not os.access(dfn, os.W_OK): os.chmod(dfn, stat.S_IRUSR | stat.S_IWUSR) diff --git a/salt/engines/__init__.py b/salt/engines/__init__.py index 72a5eac725ac..3befa28de2d0 100644 --- a/salt/engines/__init__.py +++ b/salt/engines/__init__.py @@ -50,6 +50,7 @@ def start_engines(opts, proc_mgr): if fun in engines: start_func = engines[fun] name = '{0}.Engine({1})'.format(__name__, start_func.__module__) + log.info('Starting Engine {0}'.format(name)) proc_mgr.add_process( Engine, args=( diff --git a/salt/engines/logentries.py b/salt/engines/logentries.py index f6264ab4c0c1..0fe422edfe97 100644 --- a/salt/engines/logentries.py +++ b/salt/engines/logentries.py @@ -7,7 +7,7 @@ :depends: ssl, certifi :platform: all -.. versionadded: Boron +.. versionadded: 2016.3.0 To enable this engine the master and/or minion will need the following python libraries diff --git a/salt/engines/redis_sentinel.py b/salt/engines/redis_sentinel.py index 0a445f70ed5d..8f4e80731336 100644 --- a/salt/engines/redis_sentinel.py +++ b/salt/engines/redis_sentinel.py @@ -3,7 +3,7 @@ An engine that reads messages from the redis sentinel pubsub and sends reactor events based on the channels they are subscribed to. -.. versionadded: Boron +.. versionadded: 2016.3.0 :configuration: diff --git a/salt/engines/slack.py b/salt/engines/slack.py index ce22749870b2..37dab26e8f30 100644 --- a/salt/engines/slack.py +++ b/salt/engines/slack.py @@ -5,7 +5,7 @@ via Slack by setting the control paramter to True and using command prefaced with a !. -.. versionadded: Boron +.. versionadded: 2016.3.0 :configuration: diff --git a/salt/engines/thorium.py b/salt/engines/thorium.py index afd73fa354c9..61c6b376f748 100644 --- a/salt/engines/thorium.py +++ b/salt/engines/thorium.py @@ -8,9 +8,14 @@ import salt.thorium -def start(): +def start(grains=False, grain_keys=None, pillar=False, pillar_keys=None): ''' Execute the Thorium runtime ''' - state = salt.thorium.ThorState(__opts__) + state = salt.thorium.ThorState( + __opts__, + grains, + grain_keys, + pillar, + pillar_keys) state.start_runtime() diff --git a/salt/fileclient.py b/salt/fileclient.py index 575ebd2b3b63..766338bd12e7 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -112,10 +112,10 @@ def _cache_loc(self, path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -161,10 +161,10 @@ def cache_file(self, path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -178,10 +178,10 @@ def cache_files(self, paths, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -199,10 +199,10 @@ def cache_master(self, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -219,10 +219,10 @@ def cache_dir(self, path, saltenv='base', include_empty=False, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -296,10 +296,10 @@ def file_local_list(self, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -317,10 +317,10 @@ def file_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -333,10 +333,10 @@ def dir_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -349,10 +349,10 @@ def symlink_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -366,10 +366,10 @@ def is_cached(self, path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -470,10 +470,10 @@ def get_dir(self, path, dest='', saltenv='base', gzip=None, env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -537,10 +537,10 @@ def get_url(self, url, dest, makedirs=False, saltenv='base', env=None, no_cache= ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -720,10 +720,10 @@ def get_template( ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -825,10 +825,10 @@ def get_file(self, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -846,10 +846,10 @@ def file_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -874,10 +874,10 @@ def file_list_emptydirs(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -901,10 +901,10 @@ def dir_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -928,10 +928,10 @@ def hash_file(self, path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -965,10 +965,10 @@ def list_env(self, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1056,10 +1056,10 @@ def get_file(self, if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1191,10 +1191,10 @@ def file_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1211,10 +1211,10 @@ def file_list_emptydirs(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1230,10 +1230,10 @@ def dir_list(self, saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1260,10 +1260,10 @@ def hash_file(self, path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -1293,10 +1293,10 @@ def list_env(self, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index c40e512d940c..abbd3a7f7577 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -507,10 +507,10 @@ def find_file(self, path, saltenv, back=None): kwargs[args[0]] = args[1] if 'env' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) saltenv = kwargs.pop('env') elif 'saltenv' in kwargs: @@ -535,10 +535,10 @@ def serve_file(self, load): 'dest': ''} if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') @@ -561,10 +561,10 @@ def file_hash(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') @@ -588,10 +588,10 @@ def file_list(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') @@ -619,10 +619,10 @@ def file_list_emptydirs(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') @@ -650,10 +650,10 @@ def dir_list(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') @@ -681,10 +681,10 @@ def symlink_list(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/azurefs.py b/salt/fileserver/azurefs.py index c4041d2e8a92..ae377dd9fd4f 100644 --- a/salt/fileserver/azurefs.py +++ b/salt/fileserver/azurefs.py @@ -75,9 +75,9 @@ def find_file(path, saltenv='base', env=None, **kwargs): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -115,9 +115,9 @@ def serve_file(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index 2a395e3be1c3..96c9133e3d63 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -699,9 +699,9 @@ def serve_file(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -729,9 +729,9 @@ def file_hash(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -762,9 +762,9 @@ def _file_lists(load, form): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -809,9 +809,9 @@ def _get_file_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -853,9 +853,9 @@ def _get_dir_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/minionfs.py b/salt/fileserver/minionfs.py index 69274c73772e..0149ee98fe2e 100644 --- a/salt/fileserver/minionfs.py +++ b/salt/fileserver/minionfs.py @@ -156,9 +156,9 @@ def file_hash(load, fnd): ret = {} if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -225,9 +225,9 @@ def file_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -308,9 +308,9 @@ def dir_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/roots.py b/salt/fileserver/roots.py index c3b9a004c16a..1e7ae70870a9 100644 --- a/salt/fileserver/roots.py +++ b/salt/fileserver/roots.py @@ -37,9 +37,9 @@ def find_file(path, saltenv='base', env=None, **kwargs): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -89,9 +89,9 @@ def serve_file(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -176,9 +176,9 @@ def file_hash(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -255,9 +255,9 @@ def _file_lists(load, form): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') if load['saltenv'] not in __opts__['file_roots']: @@ -351,9 +351,9 @@ def symlink_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/s3fs.py b/salt/fileserver/s3fs.py index 622e1ebb7bec..ed544ac2f8d7 100644 --- a/salt/fileserver/s3fs.py +++ b/salt/fileserver/s3fs.py @@ -125,9 +125,9 @@ def find_file(path, saltenv='base', env=None, **kwargs): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -167,9 +167,9 @@ def file_hash(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -199,9 +199,9 @@ def serve_file(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -240,9 +240,9 @@ def file_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -280,9 +280,9 @@ def dir_list(load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/fileserver/svnfs.py b/salt/fileserver/svnfs.py index 4685c1c38e4b..c5f0f136b107 100644 --- a/salt/fileserver/svnfs.py +++ b/salt/fileserver/svnfs.py @@ -593,9 +593,9 @@ def serve_file(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -623,9 +623,9 @@ def file_hash(load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -680,9 +680,9 @@ def _file_lists(load, form): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/grains/core.py b/salt/grains/core.py index 08f586473efd..6a70dbae2f70 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -1706,7 +1706,7 @@ def dns(): ''' Parse the resolver configuration file - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if salt.utils.is_windows() or 'proxyminion' in __opts__: diff --git a/salt/grains/external_ip.py b/salt/grains/external_ip.py deleted file mode 100644 index b47b7f2c0204..000000000000 --- a/salt/grains/external_ip.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -# This file is here to ensure that upgrades of salt remove the external_ip -# grain, this file should be removed in the Boron release diff --git a/salt/loader.py b/salt/loader.py index b42b61dce967..7893b415c317 100644 --- a/salt/loader.py +++ b/salt/loader.py @@ -434,10 +434,11 @@ def thorium(opts, functions, runners): ''' Load the thorium runtime modules ''' + pack = {'__salt__': functions, '__runner__': runners, '__context__': {}} ret = LazyLoader(_module_dirs(opts, 'thorium', 'thorium'), opts, tag='thorium', - pack={'__salt__': functions, '__runner__': runners}) + pack=pack) ret.pack['__thorium__'] = ret return ret @@ -1201,8 +1202,9 @@ def _load_module(self, name): mod = None fpath, suffix = self.file_mapping[name] self.loaded_files.add(name) + fpath_dirname = os.path.dirname(fpath) try: - sys.path.append(os.path.dirname(fpath)) + sys.path.append(fpath_dirname) if suffix == '.pyx': mod = pyximport.load_module(name, fpath, tempfile.gettempdir()) elif suffix == '.o': @@ -1268,7 +1270,7 @@ def _load_module(self, name): ) return False finally: - sys.path.pop() + sys.path.remove(fpath_dirname) if hasattr(mod, '__opts__'): mod.__opts__.update(self.opts) diff --git a/salt/minion.py b/salt/minion.py index 838b810c4185..0e9f2fed2eee 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -266,10 +266,10 @@ def parse_args_and_kwargs(func, args, data=None): Wrap load_args_and_kwargs ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'salt.minion.parse_args_and_kwargs() has been renamed to ' 'salt.minion.load_args_and_kwargs(). Please change this function call ' - 'before the Boron release of Salt.' + 'before the Carbon release of Salt.' ) return load_args_and_kwargs(func, args, data=data) @@ -294,7 +294,7 @@ def load_args_and_kwargs(func, args, data=None, ignore_invalid=False): _args.append(arg) elif string_kwarg: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The list of function args and kwargs should be parsed ' 'by salt.utils.args.parse_input() before calling ' 'salt.minion.load_args_and_kwargs().' @@ -1169,6 +1169,13 @@ def _thread_return(cls, minion_instance, opts, data): function_name = data['fun'] if function_name in minion_instance.functions: try: + if minion_instance.opts['pillar'].get('minion_blackout', False): + # this minion is blacked out. Only allow saltutil.refresh_pillar + if function_name != 'saltutil.refresh_pillar' and \ + function_name not in minion_instance.opts['pillar'].get('minion_blackout_whitelist', []): + raise SaltInvocationError('Minion in blackout mode. Set \'minion_blackout\' ' + 'to False in pillar to resume operations. Only ' + 'saltutil.refresh_pillar allowed in blackout mode.') func = minion_instance.functions[function_name] args, kwargs = load_args_and_kwargs( func, @@ -1333,6 +1340,13 @@ def _thread_multi_return(cls, minion_instance, opts, data): for ind in range(0, len(data['fun'])): ret['success'][data['fun'][ind]] = False try: + if minion_instance.opts['pillar'].get('minion_blackout', False): + # this minion is blacked out. Only allow saltutil.refresh_pillar + if data['fun'][ind] != 'saltutil.refresh_pillar' and \ + data['fun'][ind] not in minion_instance.opts['pillar'].get('minion_blackout_whitelist', []): + raise SaltInvocationError('Minion in blackout mode. Set \'minion_blackout\' ' + 'to False in pillar to resume operations. Only ' + 'saltutil.refresh_pillar allowed in blackout mode.') func = minion_instance.functions[data['fun'][ind]] args, kwargs = load_args_and_kwargs( func, @@ -2761,7 +2775,7 @@ def _post_master_init(self, master): # functions here, and then force a grains sync in modules_refresh self.opts['grains'] = salt.loader.grains(self.opts, force_refresh=True) - # Check config 'add_proxymodule_to_opts' Remove this in Boron. + # Check config 'add_proxymodule_to_opts' Remove this in Carbon. if self.opts['add_proxymodule_to_opts']: self.opts['proxymodule'] = self.proxy diff --git a/salt/modules/alternatives.py b/salt/modules/alternatives.py index a35000f0b2c6..1bd7e7dccd2a 100644 --- a/salt/modules/alternatives.py +++ b/salt/modules/alternatives.py @@ -92,7 +92,7 @@ def check_exists(name, path): salt '*' alternatives.check_exists name path ''' - cmd = [_get_cmd(), '--list', name] + cmd = [_get_cmd(), '--display', name] out = __salt__['cmd.run_all'](cmd, python_shell=False) if out['retcode'] > 0 and out['stderr'] != '': diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index 946eabe05062..66b998ede3a6 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -879,7 +879,8 @@ def purge(name=None, pkgs=None, **kwargs): def upgrade(refresh=True, dist_upgrade=False, **kwargs): ''' - Upgrades all packages via ``apt-get dist-upgrade`` + Upgrades all packages via ``apt-get upgrade`` or ``apt-get dist-upgrade`` + if ``dist_upgrade`` is ``True``. Returns a dict containing the changes:: diff --git a/salt/modules/augeas_cfg.py b/salt/modules/augeas_cfg.py index 187dfe016578..6b1f1e7b1bf7 100644 --- a/salt/modules/augeas_cfg.py +++ b/salt/modules/augeas_cfg.py @@ -144,7 +144,7 @@ def execute(context=None, lens=None, commands=(), load_path=None): commands The Augeas commands to execute - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched @@ -274,7 +274,7 @@ def get(path, value='', load_path=None): value The optional value to get - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched @@ -404,7 +404,7 @@ def match(path, value='', load_path=None): value The value to match on - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched @@ -443,7 +443,7 @@ def remove(path, load_path=None): path The path to remove - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched @@ -482,7 +482,7 @@ def ls(path, load_path=None): # pylint: disable=C0103 path The path to list - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched @@ -533,7 +533,7 @@ def tree(path, load_path=None): path The base of the recursive listing - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A colon-spearated list of directories that modules should be searched diff --git a/salt/modules/bcache.py b/salt/modules/bcache.py index b4d3b8eee381..f7d7cdff5735 100644 --- a/salt/modules/bcache.py +++ b/salt/modules/bcache.py @@ -12,7 +12,7 @@ This module needs the bcache userspace tools to function. -.. versionadded: Boron +.. versionadded: 2016.3.0 ''' # Import python libs diff --git a/salt/modules/blockdev.py b/salt/modules/blockdev.py index ac1fc99a52e3..97a3149c2722 100644 --- a/salt/modules/blockdev.py +++ b/salt/modules/blockdev.py @@ -3,7 +3,7 @@ Module for managing block devices .. versionadded:: 2014.7.0 -.. deprecated:: Boron +.. deprecated:: Carbon Merged to `disk` module ''' @@ -42,7 +42,7 @@ def tune(device, **kwargs): ''' Set attributes for the specified device - .. deprecated:: Boron + .. deprecated:: Carbon Use `disk.tune` CLI Example: @@ -69,7 +69,7 @@ def wipe(device): ''' Remove the filesystem information - .. deprecated:: Boron + .. deprecated:: Carbon Use `disk.tune` CLI Example: @@ -89,7 +89,7 @@ def dump(device, args=None): ''' Return all contents of dumpe2fs for a specified device - .. deprecated:: Boron + .. deprecated:: Carbon Use `disk.dump` args @@ -215,7 +215,7 @@ def resize2fs(device): ''' Resizes the filesystem. - .. deprecated:: Boron + .. deprecated:: Carbon Use `disk.resize2fs` CLI Example: diff --git a/salt/modules/boto_cloudtrail.py b/salt/modules/boto_cloudtrail.py index 0ceae80c5381..f81e76d85a8d 100644 --- a/salt/modules/boto_cloudtrail.py +++ b/salt/modules/boto_cloudtrail.py @@ -2,7 +2,7 @@ ''' Connection module for Amazon CloudTrail -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module accepts explicit Lambda credentials but can also utilize IAM roles assigned to the instance trough Instance Profiles. diff --git a/salt/modules/boto_datapipeline.py b/salt/modules/boto_datapipeline.py index dd2693960e49..579865f03b87 100644 --- a/salt/modules/boto_datapipeline.py +++ b/salt/modules/boto_datapipeline.py @@ -2,7 +2,7 @@ ''' Connection module for Amazon Data Pipeline -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :depends: boto3 ''' diff --git a/salt/modules/boto_dynamodb.py b/salt/modules/boto_dynamodb.py index 50fa756187b9..046b3dba3b81 100644 --- a/salt/modules/boto_dynamodb.py +++ b/salt/modules/boto_dynamodb.py @@ -74,7 +74,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, 'The module boto_dynamodb could not be loaded: boto libraries not found') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'dynamodb2', pack=__salt__) return True diff --git a/salt/modules/boto_ec2.py b/salt/modules/boto_ec2.py index b8beb20117c6..9682d54b8e66 100644 --- a/salt/modules/boto_ec2.py +++ b/salt/modules/boto_ec2.py @@ -81,10 +81,345 @@ def __virtual__(): if not HAS_BOTO: return False elif _LooseVersion(boto.__version__) < _LooseVersion(required_boto_version): +<<<<<<< HEAD return False else: __utils__['boto.assign_funcs'](__name__, 'ec2', pack=__salt__) return True +======= + return (False, "The boto_ec2 module cannot be loaded: boto library version incorrect ") + else: + __utils__['boto.assign_funcs'](__name__, 'ec2', pack=__salt__) + return True + + +def __init__(opts): + salt.utils.compat.pack_dunder(__name__) + if HAS_BOTO: + __utils__['boto.assign_funcs'](__name__, 'ec2') + + +def _get_all_eip_addresses(addresses=None, allocation_ids=None, region=None, + key=None, keyid=None, profile=None): + ''' + Get all EIP's associated with the current credentials. + + addresses + (list) - Optional list of addresses. If provided, only those those in the + list will be returned. + allocation_ids + (list) - Optional list of allocation IDs. If provided, only the + addresses associated with the given allocation IDs will be returned. + + returns + (list) - The requested Addresses as a list of :class:`boto.ec2.address.Address` + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + try: + return conn.get_all_addresses(addresses=addresses, allocation_ids=allocation_ids) + except boto.exception.BotoServerError as e: + log.error(e) + return [] + + +def get_all_eip_addresses(addresses=None, allocation_ids=None, region=None, + key=None, keyid=None, profile=None): + ''' + Get public addresses of some, or all EIPs associated with the current account. + + addresses + (list) - Optional list of addresses. If provided, only the addresses + associated with those in the list will be returned. + allocation_ids + (list) - Optional list of allocation IDs. If provided, only the + addresses associated with the given allocation IDs will be returned. + + returns + (list) - A list of the requested EIP addresses + + CLI Example: + + .. code-block:: bash + + salt-call boto_ec2.get_all_eip_addresses + + .. versionadded:: 2016.3.0 + ''' + return [x.public_ip for x in _get_all_eip_addresses(addresses, allocation_ids, region, + key, keyid, profile)] + + +def get_unassociated_eip_address(domain='standard', region=None, key=None, + keyid=None, profile=None): + ''' + Return the first unassociated EIP + + domain + Indicates whether the address is a EC2 address or a VPC address + (standard|vpc). + + CLI Example: + + .. code-block:: bash + + salt-call boto_ec2.get_unassociated_eip_address + + .. versionadded:: 2016.3.0 + ''' + eip = None + for address in get_all_eip_addresses(region=region, key=key, keyid=keyid, + profile=profile): + address_info = get_eip_address_info(addresses=address, region=region, + key=key, keyid=keyid, + profile=profile)[0] + if address_info['instance_id']: + log.debug('{0} is already associated with the instance {1}'.format( + address, address_info['instance_id'])) + continue + + if address_info['network_interface_id']: + log.debug('{0} is already associated with the network interface {1}' + .format(address, address_info['network_interface_id'])) + continue + + if address_info['domain'] == domain: + log.debug("The first unassociated EIP address in the domain '{0}' " + "is {1}".format(domain, address)) + eip = address + break + + if not eip: + log.debug('No unassociated Elastic IP found!') + + return eip + + +def get_eip_address_info(addresses=None, allocation_ids=None, region=None, key=None, + keyid=None, profile=None): + ''' + Get 'interesting' info about some, or all EIPs associated with the current account. + + addresses + (list) - Optional list of addresses. If provided, only the addresses + associated with those in the list will be returned. + allocation_ids + (list) - Optional list of allocation IDs. If provided, only the + addresses associated with the given allocation IDs will be returned. + + returns + (list of dicts) - A list of dicts, each containing the info for one of the requested EIPs. + + CLI Example: + + .. code-block:: bash + + salt-call boto_ec2.get_eip_address_info addresses=52.4.2.15 + + .. versionadded:: 2016.3.0 + ''' + if type(addresses) == (type('string')): + addresses = [addresses] + if type(allocation_ids) == (type('string')): + allocation_ids = [allocation_ids] + + ret = _get_all_eip_addresses(addresses=addresses, allocation_ids=allocation_ids, + region=region, key=key, keyid=keyid, profile=profile) + + interesting = ['allocation_id', 'association_id', 'domain', 'instance_id', + 'network_interface_id', 'network_interface_owner_id', 'public_ip', + 'private_ip_address'] + + return [dict([(x, getattr(address, x)) for x in interesting]) for address in ret] + + +def allocate_eip_address(domain=None, region=None, key=None, keyid=None, profile=None): + ''' + Allocate a new Elastic IP address and associate it with your account. + + domain + (string) Optional param - if set to exactly 'vpc', the address will be + allocated to the VPC. The default simply maps the EIP to your + account container. + + returns + (dict) dict of 'interesting' information about the newly allocated EIP, + with probably the most interesting keys being 'public_ip'; and + 'allocation_id' iff 'domain=vpc' was passed. + + CLI Example: + + .. code-block:: bash + + salt-call boto_ec2.allocate_eip_address domain=vpc + + .. versionadded:: 2016.3.0 + ''' + if domain and domain != 'vpc': + raise SaltInvocationError('The only permitted value for the \'domain\' param is \'vpc\'.') + + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + try: + address = conn.allocate_address(domain=domain) + except boto.exception.BotoServerError as e: + log.error(e) + return False + + interesting = ['allocation_id', 'association_id', 'domain', 'instance_id', + 'network_interface_id', 'network_interface_owner_id', 'public_ip', + 'private_ip_address'] + + return dict([(x, getattr(address, x)) for x in interesting]) + + +def release_eip_address(public_ip=None, allocation_id=None, region=None, key=None, + keyid=None, profile=None): + ''' + Free an Elastic IP address. Pass either a public IP address to release a 'standard' + EC2 Elastic IP address, or an AllocationId to release a VPC Elastic IP address. + + public_ip + (string) - The public IP address - for EC2 elastic IPs. + allocation_id + (string) - The Allocation ID - for VPC elastic IPs. + + returns + (bool) - True on success, False on failure + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.release_eip_address allocation_id=eipalloc-ef382c8a + + .. versionadded:: 2016.3.0 + ''' + if not salt.utils.exactly_one((public_ip, allocation_id)): + raise SaltInvocationError('Exactly one (but not both) of \'public_ip\' ' + 'or \'allocation_id\' must be provided') + + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + try: + return conn.release_address(public_ip, allocation_id) + except boto.exception.BotoServerError as e: + log.error(e) + return False + + +def associate_eip_address(instance_id=None, instance_name=None, public_ip=None, + allocation_id=None, network_interface_id=None, + network_interface_name=None, private_ip_address=None, + allow_reassociation=False, region=None, key=None, + keyid=None, profile=None): + ''' + Associate an Elastic IP address with a currently running instance or a network interface. + This requires exactly one of either 'public_ip' or 'allocation_id', depending + on whether you’re associating a VPC address or a plain EC2 address. + + instance_id + (string) – ID of the instance to associate with (exclusive with 'instance_name') + instance_name + (string) – Name tag of the instance to associate with (exclusive with 'instance_id') + public_ip + (string) – Public IP address, for standard EC2 based allocations. + allocation_id + (string) – Allocation ID for a VPC-based EIP. + network_interface_id + (string) - ID of the network interface to associate the EIP with + network_interface_name + (string) - Name of the network interface to associate the EIP with + private_ip_address + (string) – The primary or secondary private IP address to associate with the Elastic IP address. + allow_reassociation + (bool) – Allow a currently associated EIP to be re-associated with the new instance or interface. + + returns + (bool) - True on success, False otherwise + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.associate_eip_address instance_name=bubba.ho.tep allocation_id=eipalloc-ef382c8a + + .. versionadded:: 2016.3.0 + ''' + if not salt.utils.exactly_one((instance_id, instance_name, + network_interface_id, + network_interface_name)): + raise SaltInvocationError("Exactly one of 'instance_id', " + "'instance_name', 'network_interface_id', " + "'network_interface_name' must be provided") + + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + if instance_name: + try: + instance_id = get_id(name=instance_name, region=region, key=key, + keyid=keyid, profile=profile) + except boto.exception.BotoServerError as e: + log.error(e) + return False + if not instance_id: + log.error("Given instance_name '{0}' cannot be mapped to an " + "instance_id".format(instance_name)) + return False + + if network_interface_name: + try: + network_interface_id = get_network_interface_id( + network_interface_name, region=region, key=key, keyid=keyid, + profile=profile) + except boto.exception.BotoServerError as e: + log.error(e) + return False + if not network_interface_id: + log.error("Given network_interface_name '{0}' cannot be mapped to " + "an network_interface_id".format(network_interface_name)) + return False + + try: + return conn.associate_address(instance_id=instance_id, public_ip=public_ip, + allocation_id=allocation_id, network_interface_id=network_interface_id, + private_ip_address=private_ip_address, allow_reassociation=allow_reassociation) + except boto.exception.BotoServerError as e: + log.error(e) + return False + + +def disassociate_eip_address(public_ip=None, association_id=None, region=None, + key=None, keyid=None, profile=None): + ''' + Disassociate an Elastic IP address from a currently running instance. This + requires exactly one of either 'association_id' or 'public_ip', depending + on whether you’re associating a VPC address or a plain EC2 address. + + public_ip + (string) – Public IP address, for standard EC2 based allocations. + association_id + (string) – Association ID for a VPC-based EIP. + + returns + (bool) - True on success, False otherwise + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.disassociate_eip_address association_id=eipassoc-e3ba2d16 + + .. versionadded:: 2016.3.0 + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + try: + return conn.disassociate_address(public_ip, association_id) + except boto.exception.BotoServerError as e: + log.error(e) + return False +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def get_zones(region=None, key=None, keyid=None, profile=None): @@ -502,3 +837,379 @@ def set_attribute(attribute, attribute_value, instance_name=None, instance_id=No except boto.exception.BotoServerError as exc: log.error(exc) return False +<<<<<<< HEAD +======= + + +def get_network_interface_id(name, region=None, key=None, keyid=None, + profile=None): + ''' + Get an Elastic Network Interface id from its name tag. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.get_network_interface_id name=my_eni + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + try: + enis = conn.get_all_network_interfaces(filters={'tag:Name': name}) + if not enis: + r['error'] = {'message': 'No ENIs found.'} + elif len(enis) > 1: + r['error'] = {'message': 'Name specified is tagged on multiple ENIs.'} + else: + eni = enis[0] + r['result'] = eni.id + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + + +def get_network_interface(name=None, network_interface_id=None, region=None, + key=None, keyid=None, profile=None): + ''' + Get an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.get_network_interface name=my_eni + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + result = _get_network_interface(conn, name, network_interface_id) + if 'error' in result: + if result['error']['message'] == 'No ENIs found.': + r['result'] = None + return r + return result + eni = result['result'] + r['result'] = _describe_network_interface(eni) + return r + + +def _get_network_interface(conn, name=None, network_interface_id=None): + r = {} + if not (name or network_interface_id): + raise SaltInvocationError( + 'Either name or network_interface_id must be provided.' + ) + try: + if network_interface_id: + enis = conn.get_all_network_interfaces([network_interface_id]) + else: + enis = conn.get_all_network_interfaces(filters={'tag:Name': name}) + + if not enis: + r['error'] = {'message': 'No ENIs found.'} + elif len(enis) > 1: + r['error'] = {'message': 'Name specified is tagged on multiple ENIs.'} + else: + eni = enis[0] + r['result'] = eni + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + + +def _describe_network_interface(eni): + r = {} + for attr in ['status', 'description', 'availability_zone', 'requesterId', + 'requester_managed', 'mac_address', 'private_ip_address', + 'vpc_id', 'id', 'source_dest_check', 'owner_id', 'tags', + 'subnet_id', 'associationId', 'publicDnsName', 'owner_id', + 'ipOwnerId', 'publicIp', 'allocationId']: + if hasattr(eni, attr): + r[attr] = getattr(eni, attr) + r['region'] = eni.region.name + r['groups'] = [] + for group in eni.groups: + r['groups'].append({'name': group.name, 'id': group.id}) + r['private_ip_addresses'] = [] + for address in eni.private_ip_addresses: + r['private_ip_addresses'].append( + {'private_ip_address': address.private_ip_address, + 'primary': address.primary} + ) + r['attachment'] = {} + for attr in ['status', 'attach_time', 'device_index', + 'delete_on_termination', 'instance_id', + 'instance_owner_id', 'id']: + if hasattr(eni.attachment, attr): + r['attachment'][attr] = getattr(eni.attachment, attr) + return r + + +def create_network_interface(name, subnet_id=None, subnet_name=None, + private_ip_address=None, description=None, + groups=None, region=None, key=None, keyid=None, + profile=None): + ''' + Create an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.create_network_interface my_eni subnet-12345 description=my_eni groups=['my_group'] + ''' + if not salt.utils.exactly_one((subnet_id, subnet_name)): + raise SaltInvocationError('One (but not both) of subnet_id or ' + 'subnet_name must be provided.') + + if subnet_name: + resource = __salt__['boto_vpc.get_resource_id']('subnet', subnet_name, + region=region, key=key, + keyid=keyid, + profile=profile) + if 'id' not in resource: + log.warning('Couldn\'t resolve subnet name {0}.').format( + subnet_name) + return False + subnet_id = resource['id'] + + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + result = _get_network_interface(conn, name) + if 'result' in result: + r['error'] = {'message': 'An ENI with this Name tag already exists.'} + return r + vpc_id = __salt__['boto_vpc.get_subnet_association']( + [subnet_id], region=region, key=key, keyid=keyid, profile=profile + ) + vpc_id = vpc_id.get('vpc_id') + if not vpc_id: + msg = 'subnet_id {0} does not map to a valid vpc id.'.format(subnet_id) + r['error'] = {'message': msg} + return r + _groups = __salt__['boto_secgroup.convert_to_group_ids']( + groups, vpc_id=vpc_id, region=region, key=key, + keyid=keyid, profile=profile + ) + try: + eni = conn.create_network_interface( + subnet_id, + private_ip_address=private_ip_address, + description=description, + groups=_groups + ) + eni.add_tag('Name', name) + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + r['result'] = _describe_network_interface(eni) + return r + + +def delete_network_interface( + name=None, network_interface_id=None, region=None, key=None, + keyid=None, profile=None): + ''' + Create an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.create_network_interface my_eni subnet-12345 description=my_eni groups=['my_group'] + ''' + if not (name or network_interface_id): + raise SaltInvocationError( + 'Either name or network_interface_id must be provided.' + ) + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + result = _get_network_interface(conn, name, network_interface_id) + if 'error' in result: + return result + eni = result['result'] + try: + info = _describe_network_interface(eni) + network_interface_id = info['id'] + except KeyError: + r['error'] = {'message': 'ID not found for this network interface.'} + return r + try: + r['result'] = conn.delete_network_interface(network_interface_id) + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + + +def attach_network_interface(device_index, name=None, network_interface_id=None, + instance_name=None, instance_id=None, + region=None, key=None, keyid=None, profile=None): + ''' + Attach an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.attach_network_interface my_eni instance_name=salt-master device_index=0 + ''' + if not salt.utils.exactly_one((name, network_interface_id)): + raise SaltInvocationError( + "Exactly one (but not both) of 'name' or 'network_interface_id' " + "must be provided." + ) + + if not salt.utils.exactly_one((instance_name, instance_id)): + raise SaltInvocationError( + "Exactly one (but not both) of 'instance_name' or 'instance_id' " + "must be provided." + ) + + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + result = _get_network_interface(conn, name, network_interface_id) + if 'error' in result: + return result + eni = result['result'] + try: + info = _describe_network_interface(eni) + network_interface_id = info['id'] + except KeyError: + r['error'] = {'message': 'ID not found for this network interface.'} + return r + + if instance_name: + try: + instance_id = get_id(name=instance_name, region=region, key=key, + keyid=keyid, profile=profile) + except boto.exception.BotoServerError as e: + log.error(e) + return False + + try: + r['result'] = conn.attach_network_interface( + network_interface_id, instance_id, device_index + ) + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + + +def detach_network_interface( + name=None, network_interface_id=None, attachment_id=None, + force=False, region=None, key=None, keyid=None, profile=None): + ''' + Detach an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.detach_network_interface my_eni + ''' + if not (name or network_interface_id or attachment_id): + raise SaltInvocationError( + 'Either name or network_interface_id or attachment_id must be' + ' provided.' + ) + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + r = {} + if not attachment_id: + result = _get_network_interface(conn, name, network_interface_id) + if 'error' in result: + return result + eni = result['result'] + info = _describe_network_interface(eni) + try: + attachment_id = info['attachment']['id'] + except KeyError: + r['error'] = {'message': 'Attachment id not found for this ENI.'} + return r + try: + r['result'] = conn.detach_network_interface(attachment_id, force) + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r + + +def modify_network_interface_attribute( + name=None, network_interface_id=None, attr=None, + value=None, region=None, key=None, keyid=None, profile=None): + ''' + Modify an attribute of an Elastic Network Interface. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_ec2.modify_network_interface_attribute my_eni attr=description value='example description' + ''' + if not (name or network_interface_id): + raise SaltInvocationError( + 'Either name or network_interface_id must be provided.' + ) + if attr is None and value is None: + raise SaltInvocationError( + 'attr and value must be provided.' + ) + r = {} + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + result = _get_network_interface(conn, name, network_interface_id) + if 'error' in result: + return result + eni = result['result'] + info = _describe_network_interface(eni) + network_interface_id = info['id'] + # munge attr into what the API requires + if attr == 'groups': + _attr = 'groupSet' + elif attr == 'source_dest_check': + _attr = 'sourceDestCheck' + elif attr == 'delete_on_termination': + _attr = 'deleteOnTermination' + else: + _attr = attr + _value = value + if info.get('vpc_id') and _attr == 'groupSet': + _value = __salt__['boto_secgroup.convert_to_group_ids']( + value, vpc_id=info.get('vpc_id'), region=region, key=key, + keyid=keyid, profile=profile + ) + if not _value: + r['error'] = { + 'message': ('Security groups do not map to valid security' + ' group ids') + } + return r + _attachment_id = None + if _attr == 'deleteOnTermination': + try: + _attachment_id = info['attachment']['id'] + except KeyError: + r['error'] = { + 'message': ('No attachment id found for this ENI. The ENI must' + ' be attached before delete_on_termination can be' + ' modified') + } + return r + try: + r['result'] = conn.modify_network_interface_attribute( + network_interface_id, _attr, _value, attachment_id=_attachment_id + ) + except boto.exception.EC2ResponseError as e: + r['error'] = __utils__['boto.get_error'](e) + return r +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b diff --git a/salt/modules/boto_elasticache.py b/salt/modules/boto_elasticache.py index 8ff698cfb8b9..be3977fcf64d 100644 --- a/salt/modules/boto_elasticache.py +++ b/salt/modules/boto_elasticache.py @@ -73,7 +73,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, 'The modle boto_elasticache could not be loaded: boto libraries not found') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'elasticache', pack=__salt__) return True diff --git a/salt/modules/boto_elb.py b/salt/modules/boto_elb.py index a207f8562193..edd77d1f2345 100644 --- a/salt/modules/boto_elb.py +++ b/salt/modules/boto_elb.py @@ -85,7 +85,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, "The boto_elb module cannot be loaded: boto library not found") +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'elb', module='ec2.elb', pack=__salt__) return True @@ -195,7 +199,7 @@ def create(name, availability_zones, listeners=None, subnets=None, return False except boto.exception.BotoServerError as error: log.debug(error) - msg = 'Failed to create ELB {0}: {1}'.format(name, error) + msg = 'Failed to create ELB {0}: {1}: {2}'.format(name, error.error_code, error.message) log.error(msg) return False @@ -686,3 +690,252 @@ def get_instance_health(name, region=None, key=None, keyid=None, profile=None, i except boto.exception.BotoServerError as error: log.debug(error) return [] +<<<<<<< HEAD +======= + + +def create_policy(name, policy_name, policy_type, policy, region=None, + key=None, keyid=None, profile=None): + ''' + Create an ELB policy. + + .. versionadded:: 2016.3.0 + + CLI example: + + .. code-block:: bash + + salt myminion boto_elb.create_policy myelb mypolicy LBCookieStickinessPolicyType '{"CookieExpirationPeriod": 3600}' + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + if not exists(name, region, key, keyid, profile): + return False + try: + success = conn.create_lb_policy(name, policy_name, policy_type, policy) + if success: + log.info('Created policy {0} on ELB {1}'.format(policy_name, name)) + return True + else: + msg = 'Failed to create policy {0} on ELB {1}'.format(policy_name, name) + log.error(msg) + return False + except boto.exception.BotoServerError as e: + log.debug(e) + msg = 'Failed to create policy {0} on ELB {1}: {2}'.format(policy_name, name, e.message) + log.error(msg) + return False + + +def delete_policy(name, policy_name, region=None, key=None, keyid=None, + profile=None): + ''' + Delete an ELB policy. + + .. versionadded:: 2016.3.0 + + CLI example: + + .. code-block:: bash + + salt myminion boto_elb.delete_policy myelb mypolicy + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + if not exists(name, region, key, keyid, profile): + return True + try: + conn.delete_lb_policy(name, policy_name) + log.info('Deleted policy {0} on ELB {1}'.format(policy_name, name)) + return True + except boto.exception.BotoServerError as e: + log.debug(e) + msg = 'Failed to delete policy {0} on ELB {1}: {2}'.format(policy_name, name, e.message) + log.error(msg) + return False + + +def set_listener_policy(name, port, policies=None, region=None, key=None, + keyid=None, profile=None): + ''' + Set the policies of an ELB listener. + + .. versionadded:: 2016.3.0 + + CLI example: + + .. code-block:: Bash + + salt myminion boto_elb.set_listener_policy myelb 443 "[policy1,policy2]" + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + if not exists(name, region, key, keyid, profile): + return True + if policies is None: + policies = [] + try: + conn.set_lb_policies_of_listener(name, port, policies) + log.info('Set policies {0} on ELB {1} listener {2}'.format(policies, name, port)) + except boto.exception.BotoServerError as e: + log.debug(e) + log.info('Failed to set policy {0} on ELB {1} listener {2}: {3}'.format(policies, name, port, e.message)) + return False + return True + + +def set_backend_policy(name, port, policies=None, region=None, key=None, + keyid=None, profile=None): + ''' + Set the policies of an ELB backend server. + + CLI example: + + salt myminion boto_elb.set_backend_policy myelb 443 "[policy1,policy2]" + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + + if not exists(name, region, key, keyid, profile): + return True + if policies is None: + policies = [] + try: + conn.set_lb_policies_of_backend_server(name, port, policies) + log.info('Set policies {0} on ELB {1} backend server {2}'.format(policies, name, port)) + except boto.exception.BotoServerError as e: + log.debug(e) + log.info('Failed to set policy {0} on ELB {1} backend server {2}: {3}'.format(policies, name, port, e.message)) + return False + return True + + +def set_tags(name, tags, region=None, key=None, keyid=None, profile=None): + ''' + Add the tags on an ELB + + .. versionadded:: 2016.3.0 + + name + name of the ELB + + tags + dict of name/value pair tags + + CLI Example: + + .. code-block:: bash + + salt myminion boto_elb.set_tags my-elb-name "{'Tag1': 'Value', 'Tag2': 'Another Value'}" + ''' + + if exists(name, region, key, keyid, profile): + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + ret = _add_tags(conn, name, tags) + return ret + else: + return False + + +def delete_tags(name, tags, region=None, key=None, keyid=None, profile=None): + ''' + Add the tags on an ELB + + name + name of the ELB + + tags + list of tags to remove + + CLI Example: + + .. code-block:: bash + + salt myminion boto_elb.delete_tags my-elb-name ['TagToRemove1', 'TagToRemove2'] + ''' + if exists(name, region, key, keyid, profile): + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + ret = _remove_tags(conn, name, tags) + return ret + else: + return False + + +def _build_tag_param_list(params, tags): + ''' + helper function to build a tag parameter list to send + ''' + keys = sorted(tags.keys()) + i = 1 + for key in keys: + value = tags[key] + params['Tags.member.{0}.Key'.format(i)] = key + if value is not None: + params['Tags.member.{0}.Value'.format(i)] = value + i += 1 + + +def _get_all_tags(conn, load_balancer_names=None): + ''' + Retrieve all the metadata tags associated with your ELB(s). + + :type load_balancer_names: list + :param load_balancer_names: An optional list of load balancer names. + + :rtype: list + :return: A list of :class:`boto.ec2.elb.tag.Tag` objects + ''' + params = {} + if load_balancer_names: + conn.build_list_params(params, load_balancer_names, + 'LoadBalancerNames.member.%d') + + tags = conn.get_object( + 'DescribeTags', + params, + __utils__['boto_elb_tag.get_tag_descriptions'](), + verb='POST' + ) + if tags[load_balancer_names]: + return tags[load_balancer_names] + else: + return None + + +def _add_tags(conn, load_balancer_names, tags): + ''' + Create new metadata tags for the specified resource ids. + + :type load_balancer_names: list + :param load_balancer_names: A list of load balancer names. + + :type tags: dict + :param tags: A dictionary containing the name/value pairs. + If you want to create only a tag name, the + value for that tag should be the empty string + (e.g. ''). + ''' + params = {} + conn.build_list_params(params, load_balancer_names, + 'LoadBalancerNames.member.%d') + _build_tag_param_list(params, tags) + return conn.get_status('AddTags', params, verb='POST') + + +def _remove_tags(conn, load_balancer_names, tags): + ''' + Delete metadata tags for the specified resource ids. + + :type load_balancer_names: list + :param load_balancer_names: A list of load balancer names. + + :type tags: list + :param tags: A list containing just tag names for the tags to be + deleted. + ''' + params = {} + conn.build_list_params(params, load_balancer_names, + 'LoadBalancerNames.member.%d') + conn.build_list_params(params, tags, + 'Tags.member.%d.Key') + return conn.get_status('RemoveTags', params, verb='POST') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b diff --git a/salt/modules/boto_iam.py b/salt/modules/boto_iam.py index 0df5d8b7b18a..0584ddfd3829 100644 --- a/salt/modules/boto_iam.py +++ b/salt/modules/boto_iam.py @@ -66,11 +66,24 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False __utils__['boto.assign_funcs'](__name__, 'iam', pack=__salt__) return True +======= + return (False, 'The boto_iam module could not be loaded: boto libraries not found') + return True + + +def __init__(opts): + salt.utils.compat.pack_dunder(__name__) + if HAS_BOTO: + __utils__['boto.assign_funcs'](__name__, 'iam', pack=__salt__) + + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def instance_profile_exists(name, region=None, key=None, keyid=None, profile=None): ''' @@ -400,6 +413,45 @@ def get_group(group_name, marker=None, max_items=None, region=None, key=None, return False +<<<<<<< HEAD +======= +def get_group_members(group_name, region=None, key=None, keyid=None, profile=None): + ''' + Get group information. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_iam.get_group mygroup + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + try: + marker = None + truncated = True + users = [] + while truncated: + info = conn.get_group(group_name, marker=marker, max_items=1000) + if not info: + return False + truncated = bool(info['get_group_response']['get_group_result']['is_truncated']) + if truncated and 'marker' in info['get_group_response']['get_group_result']: + marker = info['get_group_response']['get_group_result']['marker'] + else: + marker = None + truncated = False + users += info['get_group_response']['get_group_result']['users'] + return users + except boto.exception.BotoServerError as e: + log.debug(e) + msg = 'Failed to get group {0} members.' + log.error(msg.format(group_name)) + return False + + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def add_user_to_group(user_name, group_name, region=None, key=None, keyid=None, profile=None): ''' @@ -645,6 +697,109 @@ def create_login_profile(user_name, password, region=None, key=None, return False +<<<<<<< HEAD +======= +def delete_login_profile(user_name, region=None, key=None, keyid=None, + profile=None): + ''' + Deletes a login profile for the specified user. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_iam.delete_login_profile user_name + ''' + user = get_user(user_name, region, key, keyid, profile) + if not user: + msg = 'Username {0} does not exist' + log.error(msg.format(user_name)) + return False + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + try: + info = conn.delete_login_profile(user_name) + log.info('Deleted login profile for user {0}.'.format(user_name)) + return True + except boto.exception.BotoServerError as e: + log.debug(e) + if 'Not Found' in e: + log.info('Login profile already deleted for user {0}.'.format(user_name)) + return True + msg = 'Failed to delete login profile for user {0}.' + log.error(msg.format(user_name)) + return False + + +def get_all_mfa_devices(user_name, region=None, key=None, keyid=None, + profile=None): + ''' + Get all MFA devices associated with an IAM user. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_iam.get_all_mfa_devices user_name + ''' + user = get_user(user_name, region, key, keyid, profile) + if not user: + msg = 'Username {0} does not exist' + log.error(msg.format(user_name)) + return False + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + try: + result = conn.get_all_mfa_devices(user_name) + devices = result['list_mfa_devices_response']['list_mfa_devices_result']['mfa_devices'] + return devices + except boto.exception.BotoServerError as e: + log.debug(e) + if 'Not Found' in e: + log.info('Could not find user {0}.'.format(user_name)) + return [] + msg = 'Failed to get all MFA devices for user {0}.' + log.error(msg.format(user_name, serial)) + return False + + +def deactivate_mfa_device(user_name, serial, region=None, key=None, keyid=None, + profile=None): + ''' + Deactivates the specified MFA device and removes it from association with + the user. + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt myminion boto_iam.deactivate_mfa_device user_name serial_num + ''' + user = get_user(user_name, region, key, keyid, profile) + if not user: + msg = 'Username {0} does not exist' + log.error(msg.format(user_name)) + return False + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + try: + conn.deactivate_mfa_device(user_name, serial) + log.info('Deactivated MFA device {1} for user {0}.'.format(user_name, serial)) + return True + except boto.exception.BotoServerError as e: + log.debug(e) + if 'Not Found' in e: + log.info('MFA device {1} not associated with user {0}.'.format(user_name, serial)) + return True + msg = 'Failed to deactivate MFA device {1} for user {0}.' + log.error(msg.format(user_name, serial)) + return False + + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def update_account_password_policy(allow_users_to_change_password=None, hard_expiry=None, max_password_age=None, minimum_password_length=None, @@ -1277,3 +1432,67 @@ def delete_server_cert(cert_name, region=None, key=None, keyid=None, profile=Non msg = 'Failed to delete certificate {0}.' log.error(msg.format(cert_name)) return False +<<<<<<< HEAD +======= + + +def _safe_dump(data): + ########################################### + # this presenter magic makes yaml.safe_dump + # work with the objects returned from + # boto.export_users() + ########################################### + def ordered_dict_presenter(dumper, data): + return dumper.represent_dict(data.items()) + + yaml.add_representer(odict.OrderedDict, ordered_dict_presenter, + Dumper=yaml.dumper.SafeDumper) + + return yaml.safe_dump(data, default_flow_style=False, indent=2) + + +def export_users(path_prefix='/', region=None, key=None, keyid=None, + profile=None): + ''' + Get all IAM user details. Produces results that can be used to create an + sls file. + + .. versionadded:: 2016.3.0 + + CLI Example: + + salt-call boto_iam.export_users --out=txt | sed "s/local: //" > iam_users.sls + ''' + conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) + if not conn: + return None + results = odict.OrderedDict() + _users = conn.get_all_users(path_prefix=path_prefix) + users = _users.list_users_response.list_users_result.users + marker = getattr( + _users.list_users_response.list_users_result, 'marker', None + ) + while marker: + _users = conn.get_all_users(path_prefix=path_prefix, marker=marker) + users = users + _users.list_users_response.list_users_result.users + marker = getattr( + _users.list_users_response.list_users_result, 'marker', None + ) + for user in users: + name = user.user_name + _policies = conn.get_all_user_policies(name, max_items=100) + _policies = _policies.list_user_policies_response.list_user_policies_result.policy_names + policies = {} + for policy_name in _policies: + _policy = conn.get_user_policy(name, policy_name) + _policy = json.loads(_unquote( + _policy.get_user_policy_response.get_user_policy_result.policy_document + )) + policies[policy_name] = _policy + user_sls = [] + user_sls.append({"name": name}) + user_sls.append({"policies": policies}) + user_sls.append({"path": user.path}) + results["manage user " + name] = {"boto_iam.user_present": user_sls} + return _safe_dump(results) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b diff --git a/salt/modules/boto_iot.py b/salt/modules/boto_iot.py index 57a768cc5443..203c91674a53 100644 --- a/salt/modules/boto_iot.py +++ b/salt/modules/boto_iot.py @@ -2,7 +2,7 @@ ''' Connection module for Amazon IoT -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module accepts explicit Lambda credentials but can also utilize IAM roles assigned to the instance trough Instance Profiles. diff --git a/salt/modules/boto_lambda.py b/salt/modules/boto_lambda.py index a2e729f23f3b..4edd34133e7b 100644 --- a/salt/modules/boto_lambda.py +++ b/salt/modules/boto_lambda.py @@ -2,7 +2,7 @@ ''' Connection module for Amazon Lambda -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module accepts explicit Lambda credentials but can also utilize IAM roles assigned to the instance trough Instance Profiles. diff --git a/salt/modules/boto_rds.py b/salt/modules/boto_rds.py index 922ec5c208ad..1d6cbc863f83 100644 --- a/salt/modules/boto_rds.py +++ b/salt/modules/boto_rds.py @@ -69,7 +69,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, 'The boto_rds module could not be loaded: boto libraries not found') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'rds', module='rds2', pack=__salt__) return True diff --git a/salt/modules/boto_s3_bucket.py b/salt/modules/boto_s3_bucket.py index cf2bf45f4433..90032deb2162 100644 --- a/salt/modules/boto_s3_bucket.py +++ b/salt/modules/boto_s3_bucket.py @@ -2,7 +2,7 @@ ''' Connection module for Amazon S3 Buckets -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module accepts explicit Lambda credentials but can also utilize IAM roles assigned to the instance trough Instance Profiles. diff --git a/salt/modules/boto_secgroup.py b/salt/modules/boto_secgroup.py index e94c8d666bfe..71988aec0225 100644 --- a/salt/modules/boto_secgroup.py +++ b/salt/modules/boto_secgroup.py @@ -540,7 +540,7 @@ def set_tags(tags, ''' sets tags on a security group - .. versionadded:: Boron + .. versionadded:: 2016.3.0 tags a dict of key:value pair of tags to set on the security group @@ -604,7 +604,7 @@ def delete_tags(tags, ''' deletes tags from a security group - .. versionadded:: Boron + .. versionadded:: 2016.3.0 tags a list of tags to remove diff --git a/salt/modules/boto_sns.py b/salt/modules/boto_sns.py index 208ca44e1601..1db64839af1c 100644 --- a/salt/modules/boto_sns.py +++ b/salt/modules/boto_sns.py @@ -65,7 +65,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, 'The boto_sns module could not be loaded: boto libraries not found') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'sns', pack=__salt__) return True diff --git a/salt/modules/boto_sqs.py b/salt/modules/boto_sqs.py index 0179a7208ef0..0241781d41ee 100644 --- a/salt/modules/boto_sqs.py +++ b/salt/modules/boto_sqs.py @@ -72,7 +72,11 @@ def __virtual__(): Only load if boto libraries exist. ''' if not HAS_BOTO: +<<<<<<< HEAD return False +======= + return (False, 'The boto_sqs module could not be loaded: boto libraries not found') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __utils__['boto.assign_funcs'](__name__, 'sqs', pack=__salt__) return True diff --git a/salt/modules/boto_vpc.py b/salt/modules/boto_vpc.py index 8e77ce523a08..9a2137584bee 100644 --- a/salt/modules/boto_vpc.py +++ b/salt/modules/boto_vpc.py @@ -139,7 +139,7 @@ def check_vpc(vpc_id=None, vpc_name=None, region=None, key=None, both vpc_id and vpc_name are None. Optionally raise a CommandExecutionError if the VPC does not exist. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -1238,7 +1238,7 @@ def get_dhcp_options(dhcp_options_name=None, dhcp_options_id=None, salt myminion boto_vpc.get_dhcp_options 'myfunnydhcpoptionsname' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if not any((dhcp_options_name, dhcp_options_id)): raise SaltInvocationError('At least one of the following must be specified: ' @@ -1319,40 +1319,6 @@ def associate_dhcp_options_to_vpc(dhcp_options_id, vpc_id=None, vpc_name=None, return {'associated': False, 'error': salt.utils.boto.get_error(e)} -def associate_new_dhcp_options_to_vpc(vpc_id, domain_name=None, domain_name_servers=None, ntp_servers=None, - netbios_name_servers=None, netbios_node_type=None, - region=None, key=None, keyid=None, profile=None): - ''' - ..deprecated:: Boron - This function has been deprecated in favor of - :py:func:`boto_vpc.create_dhcp_options `, - which now takes vpc_id or vpc_name as kwargs. - - This function will be removed in the Salt Boron release. - - Given valid DHCP options and a valid VPC id, create and associate the DHCP options record with the VPC. - - CLI Example: - - .. code-block:: bash - - salt myminion boto_vpc.associate_new_dhcp_options_to_vpc 'vpc-6b1fe402' domain_name='example.com' domain_name_servers='[1.2.3.4]' ntp_servers='[5.6.7.8]' netbios_name_servers='[10.0.0.1]' netbios_node_type=1 - - ''' - salt.utils.warn_until( - 'Boron', - 'Support for \'associate_new_dhcp_options_to_vpc\' has been deprecated ' - 'and will be removed in Salt Boron. Please use \'create_dhcp_options\' instead.' - ) - - return create_dhcp_options(vpc_id=vpc_id, domain_name=domain_name, - domain_name_servers=domain_name_servers, - ntp_servers=ntp_servers, - netbios_name_servers=netbios_name_servers, - region=region, key=key, keyid=keyid, - profile=profile) - - def dhcp_options_exists(dhcp_options_id=None, name=None, dhcp_options_name=None, tags=None, region=None, key=None, keyid=None, profile=None): ''' @@ -1550,38 +1516,6 @@ def associate_network_acl_to_subnet(network_acl_id=None, subnet_id=None, return {'associated': False, 'error': salt.utils.boto.get_error(e)} -def associate_new_network_acl_to_subnet(vpc_id, subnet_id, network_acl_name=None, tags=None, - region=None, key=None, keyid=None, profile=None): - ''' - ..deprecated:: Boron - This function has been deprecated in favor of - :py:func:`boto_vpc.create_network_acl `, - which now takes subnet_id or subnet_name as kwargs. - - This function will be removed in the Salt Boron release. - - Given a vpc ID and a subnet ID, associates a new network act to a subnet. - - Returns a dictionary containing the network acl id and the new association id if successful. If unsuccessful, - returns False. - - CLI Example: - - .. code-block:: bash - - salt myminion boto_vpc.associate_new_network_acl_to_subnet 'vpc-6b1fe402' 'subnet-6a1fe403' - ''' - salt.utils.warn_until( - 'Boron', - 'Support for \'associate_new_network_acl_to_subnet\' has been deprecated ' - 'and will be removed in Salt Boron. Please use \'create_network_acl\' instead.' - ) - - return create_network_acl(vpc_id=vpc_id, subnet_id=subnet_id, - network_acl_name=network_acl_name, tags=tags, - region=region, key=key, keyid=keyid, profile=profile) - - def disassociate_network_acl(subnet_id=None, vpc_id=None, subnet_name=None, vpc_name=None, region=None, key=None, keyid=None, profile=None): ''' diff --git a/salt/modules/cmdmod.py b/salt/modules/cmdmod.py index 4c1bf235c5e5..77ee09c78781 100644 --- a/salt/modules/cmdmod.py +++ b/salt/modules/cmdmod.py @@ -697,7 +697,7 @@ def run(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -925,7 +925,7 @@ def shell(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param int shell: Shell to execute under. Defaults to the system default shell. @@ -1109,7 +1109,7 @@ def run_stdout(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -1290,7 +1290,7 @@ def run_stderr(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -1473,7 +1473,7 @@ def run_all(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -1664,7 +1664,7 @@ def retcode(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -1898,7 +1898,7 @@ def script(source, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -2000,9 +2000,9 @@ def _cleanup_tempfile(path): if isinstance(__env__, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' not ' - '\'__env__\'. This functionality will be removed in Salt Boron.' + '\'__env__\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = __env__ @@ -2112,7 +2112,7 @@ def script_retcode(source, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -2595,7 +2595,7 @@ def powershell(cmd, ''' Execute the passed PowerShell command and return the output as a string. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. warning :: @@ -2621,7 +2621,7 @@ def powershell(cmd, :param str password: Windows only. Pass a password if you specify runas. This parameter will be ignored for other OS's - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param str shell: Shell to execute under. Defaults to the system default shell. @@ -2756,7 +2756,7 @@ def run_bg(cmd, saltenv='base', **kwargs): r''' - .. versionadded: Boron + .. versionadded: 2016.3.0 Execute the passed command in the background and return it's PID diff --git a/salt/modules/cp.py b/salt/modules/cp.py index 9a17c8533c4f..6a60a5deee17 100644 --- a/salt/modules/cp.py +++ b/salt/modules/cp.py @@ -185,9 +185,9 @@ def get_file(path, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -230,9 +230,9 @@ def get_template(path, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -269,9 +269,9 @@ def get_dir(path, dest, saltenv='base', template=None, gzip=None, env=None, **kw ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -299,9 +299,9 @@ def get_url(path, dest, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -325,9 +325,9 @@ def get_file_str(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -351,9 +351,9 @@ def cache_file(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -388,9 +388,9 @@ def cache_files(paths, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -434,9 +434,9 @@ def cache_dir(path, saltenv='base', include_empty=False, include_pat=None, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -459,9 +459,9 @@ def cache_master(saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -510,9 +510,9 @@ def list_states(saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -533,9 +533,9 @@ def list_master(saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -556,9 +556,9 @@ def list_master_dirs(saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -579,9 +579,9 @@ def list_master_symlinks(saltenv='base', prefix='', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -602,9 +602,9 @@ def list_minion(saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -626,9 +626,9 @@ def is_cached(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -651,9 +651,9 @@ def hash_file(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -686,7 +686,7 @@ def push(path, keep_symlinks=False, upload_path=None, remove_source=False): remove_source Remove the source file on the minion - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/data.py b/salt/modules/data.py index 7bbffa97c2ca..22b9840dcb0e 100644 --- a/salt/modules/data.py +++ b/salt/modules/data.py @@ -102,48 +102,6 @@ def update(key, value): return True -def getval(key): - ''' - Get a value from the minion datastore - - .. deprecated:: Boron - Use ``get`` instead - - CLI Example: - - .. code-block:: bash - - salt '*' data.getval - ''' - salt.utils.warn_until( - 'Boron', - 'Support for \'getval\' has been deprecated and will be removed ' - 'in Salt Boron. Please use \'get\' instead.' - ) - return get(key) - - -def getvals(*keylist): - ''' - Get values from the minion datastore - - .. deprecated:: Boron - Use ``get`` instead - - CLI Example: - - .. code-block:: bash - - salt '*' data.getvals [ ...] - ''' - salt.utils.warn_until( - 'Boron', - 'Support for \'getvals\' has been deprecated and will be removed ' - 'in Salt Boron. Please use \'get\' instead.' - ) - return get(keylist) - - def cas(key, value, old_value): ''' Check and set a value in the minion datastore @@ -194,7 +152,8 @@ def get(key, default=None): .. code-block:: bash - salt '*' data.get + salt '*' data.get key + salt '*' data.get '["key1", "key2"]' ''' store = load() diff --git a/salt/modules/deb_apache.py b/salt/modules/deb_apache.py index 8213f3ede27c..191d8e408074 100644 --- a/salt/modules/deb_apache.py +++ b/salt/modules/deb_apache.py @@ -232,7 +232,7 @@ def a2dismod(mod): def check_conf_enabled(conf): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Checks to see if the specific conf symlink is in /etc/apache2/conf-enabled. @@ -256,7 +256,7 @@ def check_conf_enabled(conf): @salt.utils.decorators.which('a2enconf') def a2enconf(conf): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Runs a2enconf for the given conf. @@ -293,7 +293,7 @@ def a2enconf(conf): @salt.utils.decorators.which('a2disconf') def a2disconf(conf): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Runs a2disconf for the given conf. diff --git a/salt/modules/debconfmod.py b/salt/modules/debconfmod.py index 44e8625cefc0..897ec44f1b81 100644 --- a/salt/modules/debconfmod.py +++ b/salt/modules/debconfmod.py @@ -184,9 +184,9 @@ def set_file(path, saltenv='base', **kwargs): ''' if '__env__' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' not ' - '\'__env__\'. This functionality will be removed in Salt Boron.' + '\'__env__\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = kwargs['__env__'] diff --git a/salt/modules/debian_ip.py b/salt/modules/debian_ip.py index 9506ec83f6b5..99f6e53f896d 100644 --- a/salt/modules/debian_ip.py +++ b/salt/modules/debian_ip.py @@ -1945,8 +1945,9 @@ def build_network_settings(**settings): # Only write the hostname if it has changed if not opts['hostname'] == current_network_settings['hostname']: - # TODO replace wiht a call to network.mod_hostname instead - _write_file_network(hostname, _DEB_HOSTNAME_FILE) + if not ('test' in settings and settings['test']): + # TODO replace wiht a call to network.mod_hostname instead + _write_file_network(hostname, _DEB_HOSTNAME_FILE) new_domain = False if len(sline) > 1: @@ -2013,7 +2014,8 @@ def build_network_settings(**settings): new_resolv = ''.join(new_contents) # Write /etc/resolv.conf - _write_file_network(new_resolv, _DEB_RESOLV_FILE) + if not ('test' in settings and settings['test']): + _write_file_network(new_resolv, _DEB_RESOLV_FILE) # used for returning the results back try: diff --git a/salt/modules/disk.py b/salt/modules/disk.py index 19d9c1363199..7fb0348814cf 100644 --- a/salt/modules/disk.py +++ b/salt/modules/disk.py @@ -395,7 +395,7 @@ def hdparms(disks, args=None): parse 'em into a nice dict (which, considering hdparms output, is quite a hassle) - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: .. code-block:: bash @@ -479,7 +479,7 @@ def hpa(disks, size=None): .. warning:: Setting the HPA might clobber your data, be very careful with this on active disks! - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -531,7 +531,7 @@ def smart_attributes(dev, attributes=None, values=None): set (https://www.backblaze.com/blog/hard-drive-smart-stats/): (5,187,188,197,198) - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -599,7 +599,7 @@ def iostat(interval=1, count=5, disks=None): ''' Gather and return (averaged) IO stats. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/dockercompose.py b/salt/modules/dockercompose.py index ac6b5e0941d0..606d0f60c0ce 100644 --- a/salt/modules/dockercompose.py +++ b/salt/modules/dockercompose.py @@ -3,7 +3,7 @@ ''' Module to import docker-compose via saltstack -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :maintainer: Jean Praloran :maturity: new diff --git a/salt/modules/dockerio.py b/salt/modules/dockerio.py index 0d4d2a32625a..013f81f17eb2 100644 --- a/salt/modules/dockerio.py +++ b/salt/modules/dockerio.py @@ -2173,10 +2173,10 @@ def _script(status, if isinstance(env, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -2274,10 +2274,10 @@ def script(container, if isinstance(env, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -2334,10 +2334,10 @@ def script_retcode(container, if isinstance(env, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/modules/dracr.py b/salt/modules/dracr.py index 63f78103b530..09a4163b56ad 100644 --- a/salt/modules/dracr.py +++ b/salt/modules/dracr.py @@ -1371,6 +1371,7 @@ def idrac_general(blade_name, command, idrac_password=None, return ret +<<<<<<< HEAD def bare_rac_cmd(cmd, host=None, admin_username=None, admin_password=None): @@ -1385,6 +1386,8 @@ def bare_rac_cmd(cmd, host=None, return ret +======= +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def _update_firmware(cmd, host=None, admin_username=None, diff --git a/salt/modules/etcd_mod.py b/salt/modules/etcd_mod.py index f3c9ca4c445e..caec5d5b2953 100644 --- a/salt/modules/etcd_mod.py +++ b/salt/modules/etcd_mod.py @@ -103,7 +103,7 @@ def set_(key, value, profile=None, ttl=None, directory=False): def update(fields, path='', profile=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Sets a dictionary of values in one call. Useful for large updates in syndic environments. The dictionary can contain a mix of formats @@ -156,7 +156,7 @@ def update(fields, path='', profile=None): def watch(key, recurse=False, profile=None, timeout=0, index=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Makes a best effort to watch for a key or tree change in etcd. Returns a dict containing the new key value ( or None if the key was diff --git a/salt/modules/ethtool.py b/salt/modules/ethtool.py index fc288127bc70..9f28db3670e7 100644 --- a/salt/modules/ethtool.py +++ b/salt/modules/ethtool.py @@ -2,7 +2,7 @@ ''' Module for running ethtool command -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :codeauthor: Krzysztof Pawlowski :maturity: new diff --git a/salt/modules/file.py b/salt/modules/file.py index 080bc5efe7dd..25da6260c386 100644 --- a/salt/modules/file.py +++ b/salt/modules/file.py @@ -2792,7 +2792,7 @@ def link(src, path): def is_link(path): ''' - Check if the path is a symlink + Check if the path is a symbolic link CLI Example: @@ -2810,7 +2810,7 @@ def is_link(path): def symlink(src, path): ''' - Create a symbolic link to a file + Create a symbolic link (symlink, soft link) to a file CLI Example: @@ -3956,9 +3956,9 @@ def get_diff( if isinstance(env, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' not ' - '\'env\'. This functionality will be removed in Salt Boron.' + '\'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/modules/firewalld.py b/salt/modules/firewalld.py index e7d214d01190..6a727669dc79 100644 --- a/salt/modules/firewalld.py +++ b/salt/modules/firewalld.py @@ -639,7 +639,7 @@ def make_permanent(): ''' Make current runtime configuration permanent. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -654,7 +654,7 @@ def get_interfaces(zone): ''' List interfaces bound to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -669,7 +669,7 @@ def add_interface(zone, interface): ''' Bind an interface to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -687,7 +687,7 @@ def remove_interface(zone, interface): ''' Remove an interface bound to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -705,7 +705,7 @@ def get_sources(zone): ''' List sources bound to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -720,7 +720,7 @@ def add_source(zone, source): ''' Bind a source to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -738,7 +738,7 @@ def remove_source(zone, source): ''' Remove a source bound to a zone - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/git.py b/salt/modules/git.py index 7acaf38301c0..36e0b5e444a2 100644 --- a/salt/modules/git.py +++ b/salt/modules/git.py @@ -166,10 +166,24 @@ def _git_run(command, cwd=None, runas=None, identity=None, # try each of the identities, independently for id_file in identity: +<<<<<<< HEAD if not os.path.isfile(id_file): missing_keys.append(id_file) log.warning('Identity file {0} does not exist'.format(id_file)) continue +======= + if 'salt://' in id_file: + _id_file = id_file + id_file = __salt__['cp.cache_file'](id_file) + if not id_file: + log.error('identity {0} does not exist.'.format(_id_file)) + continue + else: + if not __salt__['file.file_exists'](id_file): + missing_keys.append(id_file) + log.error('identity {0} does not exist.'.format(id_file)) + continue +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b env = { 'GIT_IDENTITY': id_file @@ -719,9 +733,17 @@ def clone(cwd, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b https_user Set HTTP Basic Auth username. Only accepted for HTTPS URLs. @@ -1417,9 +1439,17 @@ def fetch(cwd, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b ignore_retcode : False If ``True``, do not log an error to the minion log if the git command @@ -2051,9 +2081,17 @@ def ls_remote(cwd=None, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b https_user Set HTTP Basic Auth username. Only accepted for HTTPS URLs. @@ -2475,9 +2513,17 @@ def pull(cwd, opts='', user=None, identity=None, ignore_retcode=False): .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b ignore_retcode : False If ``True``, do not log an error to the minion log if the git command @@ -2561,9 +2607,17 @@ def push(cwd, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b ignore_retcode : False If ``True``, do not log an error to the minion log if the git command @@ -2763,9 +2817,17 @@ def remote_refs(url, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b https_user Set HTTP Basic Auth username. Only accepted for HTTPS URLs. @@ -3341,9 +3403,17 @@ def submodule(cwd, .. _`sshd(8)`: http://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE%20FORMAT .. versionchanged:: 2015.8.7 + Salt will no longer attempt to use passphrase-protected keys unless invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + + Key can also be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionchanged:: 2016.3.0 +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b ignore_retcode : False If ``True``, do not log an error to the minion log if the git command diff --git a/salt/modules/github.py b/salt/modules/github.py index c38e77cab3b1..8338dbf2a551 100644 --- a/salt/modules/github.py +++ b/salt/modules/github.py @@ -2,7 +2,7 @@ ''' Module for interop with the Github v3 API -.. versionadded:: Boron. +.. versionadded:: 2016.3.0. :depends: - PyGithub python module :configuration: Configure this module by specifying the name of a configuration diff --git a/salt/modules/glance.py b/salt/modules/glance.py index 32f059acde7b..80b91389cd45 100644 --- a/salt/modules/glance.py +++ b/salt/modules/glance.py @@ -379,9 +379,9 @@ def image_show(id=None, name=None, profile=None): # pylint: disable=C0103 image.name, pformat(image))) ret_details = {} # I may want to use this code on Beryllium - # until we got Boron packages for Ubuntu + # until we got 2016.3.0 packages for Ubuntu # so please keep this code until Carbon! - warn_until('Carbon', 'Starting with \'Boron\' image_show() ' + warn_until('Carbon', 'Starting with \'2016.3.0\' image_show() ' 'will stop wrapping the returned image in another ' 'dictionary.') if CUR_VER < BORON: @@ -413,9 +413,9 @@ def image_list(id=None, profile=None, name=None): # pylint: disable=C0103 # return False # # I may want to use this code on Beryllium - # until we got Boron packages for Ubuntu + # until we got 2016.3.0 packages for Ubuntu # so please keep this code until Carbon! - warn_until('Carbon', 'Starting in \'Boron\' image_list() ' + warn_until('Carbon', 'Starting in \'2016.3.0\' image_list() ' 'will return a list of images instead of a dictionary ' 'keyed with the images\' names.') if CUR_VER < BORON: @@ -494,9 +494,9 @@ def image_update(id=None, name=None, profile=None, **kwargs): # pylint: disable g_client = _auth(profile) updated = g_client.images.update(image['id'], **to_update) # I may want to use this code on Beryllium - # until we got Boron packages for Ubuntu + # until we got 2016.3.0 packages for Ubuntu # so please keep this code until Carbon! - warn_until('Carbon', 'Starting with \'Boron\' image_update() ' + warn_until('Carbon', 'Starting with \'2016.3.0\' image_update() ' 'will stop wrapping the returned, updated image in ' 'another dictionary.') if CUR_VER < BORON: diff --git a/salt/modules/glusterfs.py b/salt/modules/glusterfs.py index afa2a6967d40..afd61fa73d81 100644 --- a/salt/modules/glusterfs.py +++ b/salt/modules/glusterfs.py @@ -159,7 +159,12 @@ def peer(name): 'Invalid characters in peer name "{0}"'.format(name)) cmd = 'peer probe {0}'.format(name) - return _gluster_xml(cmd).find('opRet').text == '0' + + op_result = { + "exitval": _gluster_xml(cmd).find('opRet').text, + "output": _gluster_xml(cmd).find('output').text + } + return op_result def create(name, bricks, stripe=False, replica=False, device_vg=False, diff --git a/salt/modules/grains.py b/salt/modules/grains.py index a6a5a8f1b76a..7e94994f244f 100644 --- a/salt/modules/grains.py +++ b/salt/modules/grains.py @@ -356,7 +356,7 @@ def remove(key, val, delimiter=DEFAULT_TARGET_DELIM): You can now append values to a list in nested dictionary grains. If the list doesn't exist at this level, it will be created. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/hashutil.py b/salt/modules/hashutil.py index 65a7947837fb..77ce7798fdb5 100644 --- a/salt/modules/hashutil.py +++ b/salt/modules/hashutil.py @@ -80,7 +80,7 @@ def base64_b64encode(instr): Among other possible differences, the "modern" encoder does not include newline ('\\n') characters in the encoded output. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -99,7 +99,7 @@ def base64_b64decode(instr): ''' Decode a base64-encoded string using the "modern" Python interface - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -144,7 +144,7 @@ def base64_encodefile(fname): ''' Read a file from the file system and return as a base64 encoded string - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Pillar example: diff --git a/salt/modules/hosts.py b/salt/modules/hosts.py index ddcf5a671e6c..28a80c33034b 100644 --- a/salt/modules/hosts.py +++ b/salt/modules/hosts.py @@ -143,7 +143,7 @@ def set_host(ip, alias): Set the host entry in the hosts file for the given ip, this will overwrite any previous entry for the given ip - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 If ``alias`` does not include any host names (it is the empty string or contains only whitespace), all entries for the given IP address are removed. diff --git a/salt/modules/infoblox.py b/salt/modules/infoblox.py index a1e3a0dddadf..f4bc700b09fa 100644 --- a/salt/modules/infoblox.py +++ b/salt/modules/infoblox.py @@ -4,7 +4,7 @@ Will look for pillar data infoblox:server, infoblox:user, infoblox:password if not passed to functions -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :depends: - requests diff --git a/salt/modules/jenkins.py b/salt/modules/jenkins.py index 89d51610167d..07dfad0567cd 100644 --- a/salt/modules/jenkins.py +++ b/salt/modules/jenkins.py @@ -2,7 +2,7 @@ ''' Module for controlling Jenkins -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module can be used by either passing an api key and version directly or by specifying both in a configuration profile in the salt diff --git a/salt/modules/k8s.py b/salt/modules/k8s.py index 694c633a8552..028cfb348a7d 100644 --- a/salt/modules/k8s.py +++ b/salt/modules/k8s.py @@ -2,7 +2,7 @@ ''' Salt module to manage Kubernetes cluster -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Roadmap: diff --git a/salt/modules/ldap3.py b/salt/modules/ldap3.py index 108907e10c4f..5a379163f913 100644 --- a/salt/modules/ldap3.py +++ b/salt/modules/ldap3.py @@ -3,7 +3,7 @@ Query and modify an LDAP database (alternative interface) ========================================================= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 This is an alternative to the ``ldap`` interface provided by the :py:mod:`ldapmod ` execution module. diff --git a/salt/modules/localemod.py b/salt/modules/localemod.py index b0b3aa034ef9..8785818627ef 100644 --- a/salt/modules/localemod.py +++ b/salt/modules/localemod.py @@ -272,7 +272,7 @@ def gen_locale(locale, **kwargs): locale_info = salt.utils.locales.split_locale(locale) # if the charmap has not been supplied, normalize by appening it - if not locale_info['charmap']: + if not locale_info['charmap'] and not on_ubuntu: locale_info['charmap'] = locale_info['codeset'] locale = salt.utils.locales.join_locale(locale_info) diff --git a/salt/modules/lxc.py b/salt/modules/lxc.py index 91e72493f446..fbcf3d987ce7 100644 --- a/salt/modules/lxc.py +++ b/salt/modules/lxc.py @@ -561,7 +561,7 @@ def _get_profile(key, old_key, name, **kwargs): 'lxc.{1}:{0}'.format(name, old_key), None) if profile_match is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'lxc.{1} has been deprecated, please configure LXC ' 'container profiles under lxc.{0} instead'.format( key, old_key)) @@ -1326,7 +1326,7 @@ def init(name, profile = get_container_profile(copy.deepcopy(profile)) if bool(nic) and nic is not _marker: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'nic\' argument to \'lxc.init\' has been deprecated, ' 'please use \'network_profile\' instead.' ) @@ -1342,7 +1342,7 @@ def init(name, pass else: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'clone\' argument to \'lxc.init\' has been deprecated, ' 'please use \'clone_from\' instead.' ) @@ -1385,8 +1385,8 @@ def select(key, default=None): clone_from = select('clone_from') if password and password_encrypted is None: salt.utils.warn_until( - 'Boron', - 'Starting with the Boron release, passwords passed to the ' + 'Carbon', + 'Starting with the Carbon release, passwords passed to the ' '\'lxc.init\' function will be assumed to be hashed, unless ' 'password_encrypted=False. Please keep this in mind.' ) @@ -2434,7 +2434,7 @@ def start(name, **kwargs): _ensure_exists(name, path=path) if kwargs.get('restart', False): salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'restart\' argument to \'lxc.start\' has been deprecated, ' 'please use \'lxc.restart\' instead.' ) @@ -3732,7 +3732,7 @@ def run_cmd(name, Use :mod:`lxc.run ` instead ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'lxc.run_cmd has been deprecated, please use one of the lxc.run ' 'functions (or lxc.retcode). See the documentation for more ' 'information.' @@ -4568,12 +4568,12 @@ def reconfigure(name, utsname utsname of the container. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 rootfs rootfs of the container. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 cpu Select a random number of cpu cores and assign it to the cpuset, if the diff --git a/salt/modules/mac_group.py b/salt/modules/mac_group.py index 9515cc304f8b..9a2f02ca85f2 100644 --- a/salt/modules/mac_group.py +++ b/salt/modules/mac_group.py @@ -129,7 +129,7 @@ def deluser(group, name): ''' Remove a user from the group - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -148,7 +148,7 @@ def members(name, members_list): ''' Replaces members of the group with a provided list. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/mac_power.py b/salt/modules/mac_power.py index 96d3f22b1e71..3ec183b24436 100644 --- a/salt/modules/mac_power.py +++ b/salt/modules/mac_power.py @@ -2,13 +2,15 @@ ''' Module for editing power settings on Mac OS X - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' from __future__ import absolute_import # Import salt libs import salt.utils -from salt.exceptions import CommandExecutionError, SaltInvocationError +from salt.utils.mac_utils import execute_return_result, \ + execute_return_success, parse_return, validate_enabled +from salt.exceptions import SaltInvocationError from salt.ext.six.moves import range __virtualname__ = 'power' @@ -25,57 +27,6 @@ def __virtual__(): return __virtualname__ -def _execute_return_success(cmd): - ''' - Helper function to execute the command - Returns: bool - ''' - ret = __salt__['cmd.run_all'](cmd) - - if 'not supported' in ret['stdout'].lower(): - return 'Not supported on this machine' - - if ret['retcode'] != 0: - msg = 'Command Failed: {0}\n'.format(cmd) - msg += 'Return Code: {0}\n'.format(ret['retcode']) - msg += 'Output: {0}\n'.format(ret['stdout']) - raise CommandExecutionError(msg) - - return True - - -def _execute_return_result(cmd): - ''' - Helper function to execute the command - Returns: the results of the command - ''' - ret = __salt__['cmd.run_all'](cmd) - - if ret['retcode'] != 0: - msg = 'Command failed: {0}'.format(ret['stderr']) - raise CommandExecutionError(msg) - - return ret['stdout'] - - -def _parse_return(data): - ''' - Parse a return in the format: - ``Time Zone: America/Denver`` - to return only: - ``America/Denver`` - - Returns: The value portion of a return - ''' - - if ': ' in data: - return data.split(': ')[1] - if ':\n' in data: - return data.split(':\n')[1] - else: - return data - - def _validate_sleep(minutes): ''' Helper function that validates the minutes parameter. Can be any number @@ -118,26 +69,6 @@ def _validate_sleep(minutes): raise SaltInvocationError(msg) -def _validate_enabled(enabled): - ''' - Helper function to validate the enabled parameter. Boolean values are - converted to "on" and "off". String values are checked to make sure they are - either "on" or "off". Int 1+ and 0 are converted to "on" and "off" - - Returns: "on" or "off" or errors - ''' - if isinstance(enabled, str): - if enabled.lower() not in ['on', 'off']: - msg = '\nMac Power: Invalid String Value for Enabled.\n' \ - 'String values must be \'on\' or \'off\'.\n' \ - 'Passed: {0}'.format(enabled) - raise SaltInvocationError(msg) - - return enabled.lower() - - return 'on' if bool(enabled) else 'off' - - def get_sleep(): ''' Displays the amount of idle time until the machine sleeps. Settings for @@ -179,7 +110,7 @@ def set_sleep(minutes): ''' value = _validate_sleep(minutes) cmd = 'systemsetup -setsleep {0}'.format(value) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_computer_sleep(): @@ -195,8 +126,8 @@ def get_computer_sleep(): salt '*' power.get_computer_sleep ''' - ret = _execute_return_result('systemsetup -getcomputersleep') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getcomputersleep') + return parse_return(ret) def set_computer_sleep(minutes): @@ -219,7 +150,7 @@ def set_computer_sleep(minutes): ''' value = _validate_sleep(minutes) cmd = 'systemsetup -setcomputersleep {0}'.format(value) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_display_sleep(): @@ -235,8 +166,8 @@ def get_display_sleep(): salt '*' power.get_display_sleep ''' - ret = _execute_return_result('systemsetup -getdisplaysleep') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getdisplaysleep') + return parse_return(ret) def set_display_sleep(minutes): @@ -259,7 +190,7 @@ def set_display_sleep(minutes): ''' value = _validate_sleep(minutes) cmd = 'systemsetup -setdisplaysleep {0}'.format(value) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_harddisk_sleep(): @@ -275,8 +206,8 @@ def get_harddisk_sleep(): salt '*' power.get_harddisk_sleep ''' - ret = _execute_return_result('systemsetup -getharddisksleep') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getharddisksleep') + return parse_return(ret) def set_harddisk_sleep(minutes): @@ -299,7 +230,7 @@ def set_harddisk_sleep(minutes): ''' value = _validate_sleep(minutes) cmd = 'systemsetup -setharddisksleep {0}'.format(value) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_wake_on_modem(): @@ -315,8 +246,8 @@ def get_wake_on_modem(): salt '*' power.get_wake_on_modem ''' - ret = _execute_return_result('systemsetup -getwakeonmodem') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getwakeonmodem') + return parse_return(ret) def set_wake_on_modem(enabled): @@ -337,9 +268,9 @@ def set_wake_on_modem(enabled): salt '*' power.set_wake_on_modem True ''' - state = _validate_enabled(enabled) + state = validate_enabled(enabled) cmd = 'systemsetup -setwakeonmodem {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_wake_on_network(): @@ -355,8 +286,8 @@ def get_wake_on_network(): salt '*' power.get_wake_on_network ''' - ret = _execute_return_result('systemsetup -getwakeonnetworkaccess') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getwakeonnetworkaccess') + return parse_return(ret) def set_wake_on_network(enabled): @@ -377,9 +308,9 @@ def set_wake_on_network(enabled): salt '*' power.set_wake_on_network True ''' - state = _validate_enabled(enabled) + state = validate_enabled(enabled) cmd = 'systemsetup -setwakeonnetworkaccess {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_restart_power_failure(): @@ -395,8 +326,8 @@ def get_restart_power_failure(): salt '*' power.get_restart_power_failure ''' - ret = _execute_return_result('systemsetup -getrestartpowerfailure') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getrestartpowerfailure') + return parse_return(ret) def set_restart_power_failure(enabled): @@ -417,9 +348,9 @@ def set_restart_power_failure(enabled): salt '*' power.set_restart_power_failure True ''' - state = _validate_enabled(enabled) + state = validate_enabled(enabled) cmd = 'systemsetup -setrestartpowerfailure {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_restart_freeze(): @@ -435,8 +366,8 @@ def get_restart_freeze(): salt '*' power.get_restart_freeze ''' - ret = _execute_return_result('systemsetup -getrestartfreeze') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getrestartfreeze') + return parse_return(ret) def set_restart_freeze(enabled): @@ -459,9 +390,9 @@ def set_restart_freeze(enabled): salt '*' power.set_restart_freeze True ''' - state = _validate_enabled(enabled) + state = validate_enabled(enabled) cmd = 'systemsetup -setrestartfreeze {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_sleep_on_power_button(): @@ -479,8 +410,8 @@ def get_sleep_on_power_button(): salt '*' power.get_sleep_on_power_button ''' - ret = _execute_return_result('systemsetup -getallowpowerbuttontosleepcomputer') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getallowpowerbuttontosleepcomputer') + return parse_return(ret) def set_sleep_on_power_button(enabled): @@ -500,6 +431,6 @@ def set_sleep_on_power_button(enabled): salt '*' power.set_sleep_on_power_button True ''' - state = _validate_enabled(enabled) + state = validate_enabled(enabled) cmd = 'systemsetup -setallowpowerbuttontosleepcomputer {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) diff --git a/salt/modules/mac_service.py b/salt/modules/mac_service.py index dc6148806c56..72a8d9dcd555 100644 --- a/salt/modules/mac_service.py +++ b/salt/modules/mac_service.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ''' The service module for Mac OS X -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import diff --git a/salt/modules/mac_system.py b/salt/modules/mac_system.py index 100481cc1d8a..570670b8cab6 100644 --- a/salt/modules/mac_system.py +++ b/salt/modules/mac_system.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ''' -.. versionadded:: Boron +.. versionadded:: 2016.3.0 System module for sleeping, restarting, and shutting down the system on Mac OS X. @@ -15,7 +15,9 @@ # Import salt libs import salt.utils -from salt.exceptions import CommandExecutionError, SaltInvocationError +from salt.utils.mac_utils import execute_return_result, \ + execute_return_success, parse_return, validate_enabled +from salt.exceptions import CommandExecutionError __virtualname__ = 'system' @@ -30,7 +32,7 @@ def __virtual__(): if not _atrun_enabled(): if not _enable_atrun(): - return (False, 'atrun could not be enabled on this system') + return False, 'atrun could not be enabled on this system' return __virtualname__ @@ -47,7 +49,8 @@ def _enable_atrun(): ''' Start and enable the atrun daemon ''' - cmd = 'launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist' + cmd = 'launchctl load -w ' \ + '/System/Library/LaunchDaemons/com.apple.atrun.plist' __salt__['cmd.retcode'](cmd) return _atrun_enabled() @@ -67,77 +70,6 @@ def _execute_command(cmd, at_time=None): return not bool(__salt__['cmd.retcode'](cmd, python_shell=True)) -def _execute_return_success(cmd): - ''' - Helper function to execute the command - Returns: bool - ''' - ret = __salt__['cmd.run_all'](cmd) - - if 'not supported' in ret['stdout'].lower(): - return 'Not supported on this machine' - - if ret['retcode'] != 0: - msg = 'Command Failed: {0}\n'.format(cmd) - msg += 'Return Code: {0}\n'.format(ret['retcode']) - msg += 'Output: {0}\n'.format(ret['stdout']) - raise CommandExecutionError(msg) - - return True - - -def _execute_return_result(cmd): - ''' - Helper function to execute the command - Returns: the results of the command - ''' - ret = __salt__['cmd.run_all'](cmd) - - if ret['retcode'] != 0: - msg = 'Command failed: {0}'.format(ret['stderr']) - raise CommandExecutionError(msg) - - return ret['stdout'] - - -def _parse_return(data): - ''' - Parse a return in the format: - ``Time Zone: America/Denver`` - to return only: - ``America/Denver`` - - Returns: The value portion of a return - ''' - - if ': ' in data: - return data.split(': ')[1] - if ':\n' in data: - return data.split(':\n')[1] - else: - return data - - -def _validate_enabled(enabled): - ''' - Helper function to validate the enabled parameter. Boolean values are - converted to "on" and "off". String values are checked to make sure they are - either "on" or "off". All other values return an error. - - Returns: "on" or "off" or errors - ''' - if isinstance(enabled, str): - if enabled.lower() not in ['on', 'off']: - msg = '\nMac Power: Invalid String Value for Enabled.\n' \ - 'String values must be \'on\' or \'off\'.\n' \ - 'Passed: {0}'.format(enabled) - raise SaltInvocationError(msg) - - return enabled.lower() - - return 'on' if bool(enabled) else 'off' - - def halt(at_time=None): ''' Halt a running system @@ -263,8 +195,8 @@ def get_remote_login(): salt '*' system.get_remote_login ''' - ret = _execute_return_result('systemsetup -getremotelogin') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getremotelogin') + return parse_return(ret) def set_remote_login(enable): @@ -284,9 +216,9 @@ def set_remote_login(enable): salt '*' system.set_remote_login True ''' - state = _validate_enabled(enable) + state = validate_enabled(enable) cmd = 'systemsetup -f -setremotelogin {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_remote_events(): @@ -302,8 +234,8 @@ def get_remote_events(): salt '*' system.get_remote_events ''' - ret = _execute_return_result('systemsetup -getremoteappleevents') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getremoteappleevents') + return parse_return(ret) def set_remote_events(enable): @@ -324,9 +256,9 @@ def set_remote_events(enable): salt '*' system.set_remote_events On ''' - state = _validate_enabled(enable) + state = validate_enabled(enable) cmd = 'systemsetup -setremoteappleevents {0}'.format(state) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_computer_name(): @@ -342,8 +274,8 @@ def get_computer_name(): salt '*' system.get_computer_name ''' - ret = _execute_return_result('systemsetup -getcomputername') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getcomputername') + return parse_return(ret) def set_computer_name(name): @@ -362,7 +294,7 @@ def set_computer_name(name): salt '*' system.set_computer_name "Mike's Mac" ''' cmd = 'systemsetup -setcomputername "{0}"'.format(name) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_subnet_name(): @@ -378,8 +310,8 @@ def get_subnet_name(): salt '*' system.get_subnet_name ''' - ret = _execute_return_result('systemsetup -getlocalsubnetname') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getlocalsubnetname') + return parse_return(ret) def set_subnet_name(name): @@ -402,7 +334,7 @@ def set_subnet_name(name): salt '*' system.set_subnet_name "Mike's Mac" ''' cmd = 'systemsetup -setlocalsubnetname "{0}"'.format(name) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_startup_disk(): @@ -418,8 +350,8 @@ def get_startup_disk(): salt '*' system.get_startup_disk ''' - ret = _execute_return_result('systemsetup -getstartupdisk') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getstartupdisk') + return parse_return(ret) def list_startup_disks(): @@ -435,7 +367,7 @@ def list_startup_disks(): salt '*' system.list_startup_disks ''' - ret = _execute_return_result('systemsetup -liststartupdisks') + ret = execute_return_result('systemsetup -liststartupdisks') return ret.splitlines() @@ -455,14 +387,14 @@ def set_startup_disk(path): salt '*' system.set_startup_disk True ''' - # TODO Validate path if path not in list_startup_disks(): msg = '\nInvalid value passed for path.\n' \ - 'Must be a valid startup disk as found in system.list_startup_disks. \n' \ + 'Must be a valid startup disk as found in ' \ + 'system.list_startup_disks.\n' \ 'Passed: {0}'.format(path) raise CommandExecutionError(msg) cmd = 'systemsetup -setstartupdisk {0}'.format(path) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_restart_delay(): @@ -480,8 +412,8 @@ def get_restart_delay(): salt '*' system.get_restart_delay ''' - ret = _execute_return_result('systemsetup -getwaitforstartupafterpowerfailure') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getwaitforstartupafterpowerfailure') + return parse_return(ret) def set_restart_delay(seconds): @@ -511,7 +443,7 @@ def set_restart_delay(seconds): 'Passed: {0}'.format(seconds) raise CommandExecutionError(msg) cmd = 'systemsetup -setwaitforstartupafterpowerfailure {0}'.format(seconds) - return _execute_return_success(cmd) + return execute_return_success(cmd) def get_disable_keyboard_on_lock(): @@ -528,14 +460,14 @@ def get_disable_keyboard_on_lock(): salt '*' system.get_disable_keyboard_on_lock ''' - ret = _execute_return_result('systemsetup -getdisablekeyboardwhenenclosurelockisengaged') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getdisablekeyboardwhenenclosurelockisengaged') + return parse_return(ret) def set_disable_keyboard_on_lock(enable): ''' - Get whether or not the keyboard should be disabled when the X Serve enclosure - lock is engaged. + Get whether or not the keyboard should be disabled when the X Serve + enclosure lock is engaged. :param bool enable: True to enable, False to disable. "On" and "Off" are also acceptable values. Additionally you can pass 1 and 0 to represent True @@ -551,9 +483,10 @@ def set_disable_keyboard_on_lock(enable): salt '*' system.set_disable_keyboard_on_lock False ''' - state = _validate_enabled(enable) - cmd = 'systemsetup -setdisablekeyboardwhenenclosurelockisengaged {0}'.format(state) - return _execute_return_success(cmd) + state = validate_enabled(enable) + cmd = 'systemsetup -setdisablekeyboardwhenenclosurelockisengaged ' \ + 'k{0}'.format(state) + return execute_return_success(cmd) def get_boot_arch(): @@ -569,8 +502,8 @@ def get_boot_arch(): salt '*' system.get_boot_arch ''' - ret = _execute_return_result('systemsetup -getkernelbootarchitecturesetting') - return _parse_return(ret) + ret = execute_return_result('systemsetup -getkernelbootarchitecturesetting') + return parse_return(ret) def set_boot_arch(arch='default'): @@ -606,4 +539,4 @@ def set_boot_arch(arch='default'): 'Passed: {0}'.format(arch) raise CommandExecutionError(msg) cmd = 'systemsetup -setkernelbootarchitecture {0}'.format(arch) - return _execute_return_success(cmd) + return execute_return_success(cmd) diff --git a/salt/modules/mac_user.py b/salt/modules/mac_user.py index b196f25ae737..c08441b2abbf 100644 --- a/salt/modules/mac_user.py +++ b/salt/modules/mac_user.py @@ -454,7 +454,7 @@ def rename(name, new_name): def get_auto_login(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Gets the current setting for Auto Login @@ -477,7 +477,7 @@ def get_auto_login(): def enable_auto_login(name): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Configures the machine to auto login with the specified user @@ -504,7 +504,7 @@ def enable_auto_login(name): def disable_auto_login(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Disables auto login on the machine diff --git a/salt/modules/mdata.py b/salt/modules/mdata.py index 571041eed4d7..39e5ac8304e2 100644 --- a/salt/modules/mdata.py +++ b/salt/modules/mdata.py @@ -2,7 +2,7 @@ ''' Module for managaging metadata in SmartOS Zones -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :maintainer: Jorge Schrauwen :maturity: new diff --git a/salt/modules/mine.py b/salt/modules/mine.py index 50e8237fbeab..40bff002108e 100644 --- a/salt/modules/mine.py +++ b/salt/modules/mine.py @@ -103,6 +103,13 @@ def update(clear=False): salt '*' mine.update ''' m_data = __salt__['config.merge']('mine_functions', {}) +<<<<<<< HEAD +======= + # If we don't have any mine functions configured, then we should just bail out + if not m_data: + return + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b data = {} for func in m_data: try: diff --git a/salt/modules/monit.py b/salt/modules/monit.py index 801545ef38c1..a595c7e61797 100644 --- a/salt/modules/monit.py +++ b/salt/modules/monit.py @@ -162,7 +162,7 @@ def status(svc_name=''): def reload_(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Reload monit configuration @@ -178,7 +178,7 @@ def reload_(): def configtest(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Test monit configuration syntax @@ -206,7 +206,7 @@ def configtest(): def version(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Return version from monit -V @@ -224,7 +224,7 @@ def version(): def id_(reset=False): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Return monit unique id. @@ -252,7 +252,7 @@ def id_(reset=False): def validate(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Check all services diff --git a/salt/modules/netaddress.py b/salt/modules/netaddress.py index 0f6484138bf7..3d5b9c617bc3 100644 --- a/salt/modules/netaddress.py +++ b/salt/modules/netaddress.py @@ -2,7 +2,7 @@ ''' Module for getting information about network addresses. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :depends: netaddr ''' diff --git a/salt/modules/network.py b/salt/modules/network.py index 4008fda02b62..d169d6694a36 100644 --- a/salt/modules/network.py +++ b/salt/modules/network.py @@ -840,7 +840,7 @@ def convert_cidr(cidr): ''' returns the network and subnet mask of a cidr addr - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/npm.py b/salt/modules/npm.py index 0d2ed95af0ed..774eaf6f9ee1 100644 --- a/salt/modules/npm.py +++ b/salt/modules/npm.py @@ -106,7 +106,7 @@ def install(pkg=None, silent Whether or not to run NPM install with --silent flag. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 dry_run Whether or not to run NPM install with --dry-run flag. diff --git a/salt/modules/opkg.py b/salt/modules/opkg.py index d9781e880cf1..58919c6a364a 100644 --- a/salt/modules/opkg.py +++ b/salt/modules/opkg.py @@ -2,7 +2,7 @@ ''' Support for Opkg -.. versionadded: Boron +.. versionadded: 2016.3.0 .. note:: diff --git a/salt/modules/pillar.py b/salt/modules/pillar.py index f881bcb1346d..30a47ffe2ec0 100644 --- a/salt/modules/pillar.py +++ b/salt/modules/pillar.py @@ -313,7 +313,7 @@ def keys(key, delimiter=DEFAULT_TARGET_DELIM): def file_exists(path, saltenv=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 This is a master-only function. Calling from the minion is not supported. diff --git a/salt/modules/pip.py b/salt/modules/pip.py index ff4b027b34ce..c151ca23cca9 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py @@ -566,15 +566,15 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914 # the `bin_env` argument and we'll take care of the rest. if env and not bin_env: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing \'env\' to the pip module is deprecated. Use bin_env instead. ' - 'This functionality will be removed in Salt Boron.' + 'This functionality will be removed in Salt Carbon.' ) bin_env = env if activate: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing \'activate\' to the pip module is deprecated. If ' 'bin_env refers to a virtualenv, there is no need to activate ' 'that virtualenv before using pip to install packages in it.' @@ -582,10 +582,10 @@ def install(pkgs=None, # pylint: disable=R0912,R0913,R0914 if isinstance(__env__, string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'__env__\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = __env__ @@ -920,10 +920,10 @@ def uninstall(pkgs=None, if isinstance(__env__, string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'__env__\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = __env__ diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py index 3a4452a6c95f..732a97ced1f9 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py @@ -105,10 +105,10 @@ def parse_targets(name=None, ''' if '__env__' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'__env__\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = kwargs['__env__'] diff --git a/salt/modules/pkgin.py b/salt/modules/pkgin.py index 42b555d06ce5..2563565bbcce 100644 --- a/salt/modules/pkgin.py +++ b/salt/modules/pkgin.py @@ -128,7 +128,7 @@ def search(pkg_name): def latest_version(*names, **kwargs): ''' - .. versionchanged: Boron + .. versionchanged: 2016.3.0 Return the latest version of the named package available for upgrade or installation. @@ -235,7 +235,7 @@ def refresh_db(): def list_pkgs(versions_as_list=False, **kwargs): ''' - .. versionchanged: Boron + .. versionchanged: 2016.3.0 List the packages currently installed as a dict:: {'': ''} @@ -592,7 +592,7 @@ def file_list(package): def file_dict(*packages): ''' - .. versionchanged: Boron + .. versionchanged: 2016.3.0 List the files that belong to a package. CLI Examples: diff --git a/salt/modules/postgres.py b/salt/modules/postgres.py index 07f1eb68cc05..0a6c6eb9b6fa 100644 --- a/salt/modules/postgres.py +++ b/salt/modules/postgres.py @@ -2101,7 +2101,7 @@ def language_list( password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Return a list of languages in a database. @@ -2157,7 +2157,7 @@ def language_exists( password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Checks if language exists in a database. @@ -2206,7 +2206,7 @@ def language_create(name, password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Installs a language into a database @@ -2263,7 +2263,7 @@ def language_remove(name, password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Removes a language from a database @@ -2537,7 +2537,7 @@ def privileges_list( password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Return a list of privileges for the specified object. @@ -2637,7 +2637,7 @@ def has_privileges(name, password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Check if a role has the specified privileges on an object @@ -2759,7 +2759,7 @@ def privileges_grant(name, password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Grant privileges on a postgres object @@ -2885,7 +2885,7 @@ def privileges_revoke(name, password=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Revoke privileges on a postgres object @@ -2991,7 +2991,7 @@ def datadir_init(name, locale=None, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Initializes a postgres data directory @@ -3039,7 +3039,7 @@ def datadir_init(name, def datadir_exists(name): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Checks if postgres data directory has been initialized diff --git a/salt/modules/pushover_notify.py b/salt/modules/pushover_notify.py index 59070811ddeb..868fbc581a6f 100644 --- a/salt/modules/pushover_notify.py +++ b/salt/modules/pushover_notify.py @@ -2,7 +2,7 @@ ''' Module for sending messages to Pushover (https://www.pushover.net) -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module can be used by either passing an api key and version directly or by specifying both in a configuration profile in the salt diff --git a/salt/modules/pw_user.py b/salt/modules/pw_user.py index b0af07e10ce8..deb727cc22f1 100644 --- a/salt/modules/pw_user.py +++ b/salt/modules/pw_user.py @@ -432,7 +432,7 @@ def get_loginclass(name): ''' Get the login class of the user - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index d5294ea38af6..c6fbdd1dbc0d 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -295,7 +295,7 @@ def clear_password(name, runas=None): def check_password(name, password, runas=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Checks if a user's password is valid. diff --git a/salt/modules/redismod.py b/salt/modules/redismod.py index 4f2f7d8280c4..1d1a31c31679 100644 --- a/salt/modules/redismod.py +++ b/salt/modules/redismod.py @@ -509,7 +509,7 @@ def sentinel_get_master_ip(master, host=None, port=None, password=None): ''' Get ip for sentinel master - .. versionadded: Boron + .. versionadded: 2016.3.0 CLI Example: @@ -526,7 +526,7 @@ def get_master_ip(host=None, port=None, password=None): ''' Get host information about slave - .. versionadded: Boron + .. versionadded: 2016.3.0 CLI Example: diff --git a/salt/modules/reg.py b/salt/modules/reg.py index 3814c848fd8a..557e0d2ce6ef 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -4,9 +4,6 @@ Manage the Windows registry =========================== -The read_key and set_key functions will be updated in Boron to reflect proper -registry usage. The registry has three main components. Hives, Keys, and Values. - ----- Hives ----- @@ -29,9 +26,6 @@ :depends: - winreg Python module ''' - -# TODO: Figure out the exceptions _winreg can raise and properly catch them - # Import python libs from __future__ import absolute_import import logging @@ -55,6 +49,21 @@ __virtualname__ = 'reg' +def __virtual__(): + ''' + Only works on Windows systems with the _winreg python module + ''' + if not salt.utils.is_windows(): + return (False, 'reg execution module failed to load: ' + 'The module will only run on Windows systems') + + if not HAS_WINDOWS_MODULES: + return (False, 'reg execution module failed to load: ' + 'The _winreg python library could not be loaded') + + return __virtualname__ + + class Registry(object): ''' Delay '_winreg' usage until this module is used @@ -99,15 +108,6 @@ def __getattr__(self, k): raise CommandExecutionError(msg.format(k, hkeys)) -def __virtual__(): - ''' - Only works on Windows systems - ''' - if salt.utils.is_windows() and HAS_WINDOWS_MODULES: - return __virtualname__ - return (False, 'reg execution module failed to load: either the system is not Windows or the _winreg python library not available.') - - def _key_exists(hive, key, use_32bit_registry=False): ''' Check that the key is found in the registry @@ -127,67 +127,17 @@ def _key_exists(hive, key, use_32bit_registry=False): handle = _winreg.OpenKey(hkey, key, 0, access_mask) _winreg.CloseKey(handle) return True - except WindowsError as exc: # pylint: disable=E0602 + except WindowsError: # pylint: disable=E0602 return False def broadcast_change(): ''' Refresh the windows environment. - :return: ''' # https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx - _, res = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, - SMTO_ABORTIFHUNG, 5000) - return not bool(res) - - -def read_key(hkey, path, key=None, use_32bit_registry=False): - ''' - .. important:: - The name of this function is misleading and will be changed to reflect - proper usage in the Boron release of Salt. The path option will be removed - and the key will be the actual key. See the following issue: - - https://github.com/saltstack/salt/issues/25618 - - In order to not break existing state files this function will call the - read_value function if a key is passed. Key will be passed as the value - name. If key is not passed, this function will return the default value for - the key. - - In the Boron release this function will be removed in favor of read_value. - - Read registry key value - - Returns the first unnamed value (Default) as a string. - Returns none if first unnamed value is empty. - Returns False if key not found. - - CLI Example: - - .. code-block:: bash - - salt '*' reg.read_key HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' - ''' - - ret = {'hive': hkey, - 'key': path, - 'vdata': None, - 'success': True} - - if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', 'Use reg.read_value to read a registry ' - 'value. This functionality will be ' - 'removed in Salt Boron') - return read_value(hive=hkey, - key=path, - vname=key, - use_32bit_registry=use_32bit_registry) - - return read_value(hive=hkey, - key=path, - use_32bit_registry=use_32bit_registry) + SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, + SMTO_ABORTIFHUNG, 5000) def read_value(hive, key, vname=None, use_32bit_registry=False): @@ -203,14 +153,13 @@ def read_value(hive, key, vname=None, use_32bit_registry=False): :param str key: The key (looks like a path) to the value name. :param str vname: The value name. These are the individual name/data pairs - under the key. If not passed, the key (Default) value will be returned + under the key. If not passed, the key (Default) value will be returned :param bool use_32bit_registry: Accesses the 32bit portion of the registry - on 64 bit installations. On 32bit machines this is ignored. + on 64bit installations. On 32bit machines this is ignored. :return: A dictionary containing the passed settings as well as the - value_data if successful. If unsuccessful, sets success to False - + value_data if successful. If unsuccessful, sets success to False :rtype: dict If vname is not passed: @@ -251,7 +200,7 @@ def read_value(hive, key, vname=None, use_32bit_registry=False): ret['vdata'] = vdata else: ret['comment'] = 'Empty Value' - except WindowsError as exc: # pylint: disable=E0602 + except WindowsError: # pylint: disable=E0602 ret['vdata'] = ('(value not set)') ret['vtype'] = 'REG_SZ' except WindowsError as exc: # pylint: disable=E0602 @@ -263,63 +212,11 @@ def read_value(hive, key, vname=None, use_32bit_registry=False): return ret -def set_key(hkey, - path, - value, - key=None, - vtype='REG_DWORD', - reflection=True, - use_32bit_registry=False): - ''' - .. important :: - The name of this function is misleading and will be changed to reflect - proper usage in the Boron release of Salt. The path option will be removed - and the key will be the actual key. See the following issue: - - https://github.com/saltstack/salt/issues/25618 - - In order to not break existing state files this function will call the - set_value function if a key is passed. Key will be passed as the value - name. If key is not passed, this function will return the default value for - the key. - - In the Boron release this function will be removed in favor of set_value. - - Set a registry key - - vtype: http://docs.python.org/2/library/_winreg.html#value-types - - CLI Example: - - .. code-block:: bash - - salt '*' reg.set_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version' '0.97' REG_DWORD - ''' - - if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry ' - 'value. This functionality will be ' - 'removed in Salt Boron') - return set_value(hive=hkey, - key=path, - vname=key, - vdata=value, - vtype=vtype, - use_32bit_registry=use_32bit_registry) - - return set_value(hive=hkey, - key=path, - vdata=value, - vtype=vtype, - use_32bit_registry=use_32bit_registry) - - def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', - reflection=True, use_32bit_registry=False): ''' Sets a registry value entry or the default value for a key. @@ -333,7 +230,7 @@ def set_value(hive, :param str key: The key (looks like a path) to the value name. :param str vname: The value name. These are the individual name/data pairs - under the key. If not passed, the key (Default) value will be set. + under the key. If not passed, the key (Default) value will be set. :param str vdata: The value data to be set. @@ -345,17 +242,10 @@ def set_value(hive, - REG_MULTI_SZ - REG_SZ - :param bool reflection: A boolean value indicating that the value should - also be set in the Wow6432Node portion of the registry. Only applies to 64 - bit Windows. This setting is ignored for 32 bit Windows. - - .. deprecated:: 2015.8.2 - Use ``use_32bit_registry`` instead. The parameter seems to have no effect - since Windows 7 / Windows 2008R2 removed support for reflection. The - parameter will be removed in Boron. + :param bool use_32bit_registry: Sets the 32bit portion of the registry on + 64bit installations. On 32bit machines this is ignored. :return: Returns True if successful, False if not - :rtype: bool CLI Example: @@ -384,141 +274,6 @@ def set_value(hive, return False -def create_key(hkey, - path, - key=None, - value=None, - reflection=True, - use_32bit_registry=False): - ''' - .. important :: - The name of this function is misleading and will be changed to reflect - proper usage in the Boron release of Salt. The path option will be removed - and the key will be the actual key. See the following issue: - - https://github.com/saltstack/salt/issues/25618 - - In order to not break existing state files this function will call the - set_value function if key is passed. Key will be passed as the value name. - If key is not passed, this function will return the default value for the - key. - - In the Boron release path will be removed and key will be the path. You will - not pass value. - - Create a registry key - - CLI Example: - - .. code-block:: bash - - salt '*' reg.create_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version' '0.97' - ''' - if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', 'Use reg.set_value to create a registry ' - 'value. This functionality will be ' - 'removed in Salt Boron') - return set_value(hive=hkey, - key=path, - vname=key, - vdata=value, - use_32bit_registry=use_32bit_registry) - - return set_value(hive=hkey, key=path, use_32bit_registry=use_32bit_registry) - - -def delete_key(hkey, - path, - key=None, - reflection=True, - force=False, - use_32bit_registry=False): - ''' - .. important:: - The name of this function is misleading and will be changed to reflect - proper usage in the Boron release of Salt. The path option will be removed - and the key will be the actual key. See the following issue: - - https://github.com/saltstack/salt/issues/25618 - - In order to not break existing state files this function will call the - delete_value function if a key is passed. Key will be passed as the value - name. If key is not passed, this function will return the default value for - the key. - - In the Boron release path will be removed and key will be the path. - reflection will also be removed. - - Delete a registry key - - CLI Example: - - .. code-block:: bash - - salt '*' reg.delete_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' - - :param str hkey: (will be changed to hive) The name of the hive. Can be one - of the following - - - HKEY_LOCAL_MACHINE or HKLM - - HKEY_CURRENT_USER or HKCU - - HKEY_USER or HKU - - :param str path: (will be changed to key) The key (looks like a path) to - remove. - - :param str key: (used incorrectly) Will be removed in Boron - - :param bool reflection: A boolean value indicating that the value should - also be removed from the Wow6432Node portion of the registry. Only applies - to 64 bit Windows. This setting is ignored for 32 bit Windows. - - Only applies to delete value. If the key parameter is passed, this function - calls delete_value instead. Will be changed in Boron. - - :param bool force: A boolean value indicating that all subkeys should be - removed as well. If this is set to False (default) and there are subkeys, - the delete_key function will fail. - - :return: Returns True if successful, False if not. If force=True, the - results of delete_key_recursive are returned. - - :rtype: bool - ''' - - if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', - 'Variable names will be changed to match Windows ' - 'Registry terminology. These changes will be ' - 'made in Boron') - return delete_value(hive=hkey, - key=path, - vname=key, - reflection=reflection, - use_32bit_registry=use_32bit_registry) - - if force: - return delete_key_recursive(hkey, - path, - use_32bit_registry=use_32bit_registry) - - registry = Registry() - hive = registry.hkeys[hkey] - key = path - access_mask = registry.registry_32[use_32bit_registry] - - try: - # Can't use delete_value to delete a key - key_handle = _winreg.OpenKey(hive, key, 0, access_mask) - _winreg.DeleteKey(key_handle, '') - _winreg.CloseKey(key_handle) - broadcast_change() - return True - except WindowsError as exc: # pylint: disable=E0602 - log.error(exc, exc_info=True) - return False - - def delete_key_recursive(hive, key, use_32bit_registry=False): ''' .. versionadded:: 2015.5.4 @@ -533,9 +288,11 @@ def delete_key_recursive(hive, key, use_32bit_registry=False): :param key: The key to remove (looks like a path) + :param bool use_32bit_registry: Deletes the 32bit portion of the registry on + 64bit installations. On 32bit machines this is ignored. + :return: A dictionary listing the keys that deleted successfully as well as those that failed to delete. - :rtype: dict The following example will remove ``salt`` and all its subkeys from the @@ -557,23 +314,23 @@ def delete_key_recursive(hive, key, use_32bit_registry=False): return False # Functions for traversing the registry tree - def subkeys(key): + def subkeys(_key): i = 0 while True: try: - subkey = _winreg.EnumKey(key, i) + subkey = _winreg.EnumKey(_key, i) yield subkey i += 1 except WindowsError: # pylint: disable=E0602 break - def traverse_registry_tree(hkey, keypath, ret, access_mask): - key = _winreg.OpenKey(hkey, keypath, 0, access_mask) - for subkeyname in subkeys(key): - subkeypath = r'{0}\{1}'.format(keypath, subkeyname) - ret = traverse_registry_tree(hkey, subkeypath, ret, access_mask) - ret.append('{0}'.format(subkeypath)) - return ret + def traverse_registry_tree(_hkey, _keypath, _ret, _access_mask): + _key = _winreg.OpenKey(_hkey, _keypath, 0, _access_mask) + for subkeyname in subkeys(_key): + subkeypath = r'{0}\{1}'.format(_keypath, subkeyname) + _ret = traverse_registry_tree(_hkey, subkeypath, _ret, access_mask) + _ret.append('{0}'.format(subkeypath)) + return _ret # Get a reverse list of registry keys to be deleted key_list = [] @@ -599,7 +356,7 @@ def traverse_registry_tree(hkey, keypath, ret, access_mask): return ret -def delete_value(hive, key, vname=None, reflection=True, use_32bit_registry=False): +def delete_value(hive, key, vname=None, use_32bit_registry=False): ''' Delete a registry value entry or the default value for a key. @@ -612,19 +369,12 @@ def delete_value(hive, key, vname=None, reflection=True, use_32bit_registry=Fals :param str key: The key (looks like a path) to the value name. :param str vname: The value name. These are the individual name/data pairs - under the key. If not passed, the key (Default) value will be deleted. - - :param bool reflection: A boolean value indicating that the value should - also be set in the Wow6432Node portion of the registry. Only applies to 64 - bit Windows. This setting is ignored for 32 bit Windows. + under the key. If not passed, the key (Default) value will be deleted. - .. deprecated:: 2015.8.2 - Use ``use_32bit_registry`` instead. The parameter seems to have no effect - since Windows 7 / Windows 2008R2 removed support for reflection. This - parameter will be removed in Boron. + :param bool use_32bit_registry: Deletes the 32bit portion of the registry on + 64bit installations. On 32bit machines this is ignored. :return: Returns True if successful, False if not - :rtype: bool CLI Example: @@ -634,15 +384,19 @@ def delete_value(hive, key, vname=None, reflection=True, use_32bit_registry=Fals salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version' ''' registry = Registry() - hive = registry.hkeys[hive] + h_hive = registry.hkeys[hive] access_mask = registry.registry_32[use_32bit_registry] try: - handle = _winreg.OpenKey(hive, key, 0, access_mask) + handle = _winreg.OpenKey(h_hive, key, 0, access_mask) _winreg.DeleteValue(handle, vname) _winreg.CloseKey(handle) broadcast_change() return True except WindowsError as exc: # pylint: disable=E0602 log.error(exc, exc_info=True) + log.error('Hive: {0}'.format(hive)) + log.error('Key: {0}'.format(key)) + log.error('ValueName: {0}'.format(vname)) + log.error('32bit Reg: {0}'.format(use_32bit_registry)) return False diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index c425cde85cef..1019c179d714 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -199,6 +199,28 @@ def _sysv_disable(name): return not __salt__['cmd.retcode'](cmd, python_shell=False) +def _sysv_delete(name): + ''' + Delete the named sysv service from the system. The service will be + deleted using chkconfig. + ''' + if not _service_is_chkconfig(name): + return False + cmd = '/sbin/chkconfig --del {0}'.format(name) + return not __salt__['cmd.retcode'](cmd) + + +def _upstart_delete(name): + ''' + Delete an upstart service. This will only rename the .conf file + ''' + if HAS_UPSTART: + if os.path.exists('/etc/init/{0}.conf'.format(name)): + os.rename('/etc/init/{0}.conf'.format(name), + '/etc/init/{0}.conf.removed'.format(name)) + return True + + def _upstart_services(): ''' Return list of upstart services. @@ -214,9 +236,17 @@ def _sysv_services(): ''' Return list of sysv services. ''' - ret = [] - return [name for name in os.listdir('/etc/init.d') - if _service_is_sysv(name)] + _services = [] + output = __salt__['cmd.run'](['chkconfig', '--list'], python_shell=False) + for line in output.splitlines(): + comps = line.split() + try: + if comps[1].startswith('0:'): + _services.append(comps[0]) + except IndexError: + continue + # Return only the services that have an initscript present + return [x for x in _services if _service_is_sysv(x)] def get_enabled(limit=''): @@ -435,6 +465,24 @@ def status(name, sig=None): return __salt__['cmd.retcode'](cmd, python_shell=False, ignore_retcode=True) == 0 +def delete(name, **kwargs): + ''' + Delete the named service + + .. versionadded:: 2016.3 + + CLI Example: + + .. code-block:: bash + + salt '*' service.delete + ''' + if _service_is_upstart(name): + return _upstart_delete(name) + else: + return _sysv_delete(name) + + def enable(name, **kwargs): ''' Enable the named service to start at boot diff --git a/salt/modules/rsync.py b/salt/modules/rsync.py index 1de853c628c5..402d8f10dc34 100644 --- a/salt/modules/rsync.py +++ b/salt/modules/rsync.py @@ -52,7 +52,7 @@ def rsync(src, exclude=None, excludefrom=None): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return data now contains just the output of the rsync command, instead of a dictionary as returned from :py:func:`cmd.run_all `. @@ -95,7 +95,7 @@ def rsync(src, def version(): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return data now contains just the version number as a string, instead of a dictionary as returned from :py:func:`cmd.run_all `. @@ -122,7 +122,7 @@ def version(): def config(conf_path='/etc/rsyncd.conf'): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return data now contains just the contents of the rsyncd.conf as a string, instead of a dictionary as returned from :py:func:`cmd.run_all `. diff --git a/salt/modules/s3.py b/salt/modules/s3.py index 1c4676525bfb..17ba3aa21f4a 100644 --- a/salt/modules/s3.py +++ b/salt/modules/s3.py @@ -292,7 +292,7 @@ def _get_key(key, keyid, service_url, verify_ssl, kms_keyid, location, role_arn) if location is None and __salt__['config.option']('s3.location') is not None: location = __salt__['config.option']('s3.location') - if role_arn is None and __salt__['config.option']('s3.role_arn') is not None: + if role_arn is None and __salt__['config.option']('s3.role_arn'): role_arn = __salt__['config.option']('s3.role_arn') return key, keyid, service_url, verify_ssl, kms_keyid, location, role_arn diff --git a/salt/modules/selinux.py b/salt/modules/selinux.py index 3d8a2f6d9347..f3139b9fb99b 100644 --- a/salt/modules/selinux.py +++ b/salt/modules/selinux.py @@ -203,7 +203,7 @@ def getsemod(module): salt '*' selinux.getsemod mysql - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' return list_semod().get(module, {}) @@ -218,7 +218,7 @@ def setsemod(module, state): salt '*' selinux.setsemod nagios Enabled - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if state.lower() == 'enabled': cmd = 'semodule -e {0}'.format(module) @@ -238,7 +238,7 @@ def list_semod(): salt '*' selinux.list_semod - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' mdata = __salt__['cmd.run']('semodule -l').splitlines() ret = {} diff --git a/salt/modules/smartos_virt.py b/salt/modules/smartos_virt.py index 002b02950f73..e7b90563ec86 100644 --- a/salt/modules/smartos_virt.py +++ b/salt/modules/smartos_virt.py @@ -244,7 +244,7 @@ def get_macs(domain): # Deprecated aliases def create(domain): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.start` instead. Start a defined domain @@ -261,7 +261,7 @@ def create(domain): def destroy(domain): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.stop` instead. Power off a defined domain @@ -278,7 +278,7 @@ def destroy(domain): def list_vms(): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.list_domains` instead. List all virtual machines. diff --git a/salt/modules/solaris_fmadm.py b/salt/modules/solaris_fmadm.py index dba5e7e58eed..59aaa6f267c1 100644 --- a/salt/modules/solaris_fmadm.py +++ b/salt/modules/solaris_fmadm.py @@ -6,7 +6,7 @@ :maturity: new :platform: solaris,illumos -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import diff --git a/salt/modules/solaris_system.py b/salt/modules/solaris_system.py index 24ed016efb5e..5335146e4600 100644 --- a/salt/modules/solaris_system.py +++ b/salt/modules/solaris_system.py @@ -4,7 +4,7 @@ This module is assumes we are using solaris-like shutdown -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import diff --git a/salt/modules/splunk.py b/salt/modules/splunk.py index 8f41f1a4ae7a..7fd589264d99 100644 --- a/salt/modules/splunk.py +++ b/salt/modules/splunk.py @@ -2,7 +2,7 @@ ''' Module for interop with the Splunk API -.. versionadded:: Boron. +.. versionadded:: 2016.3.0. :depends: - splunk-sdk python module diff --git a/salt/modules/ssh.py b/salt/modules/ssh.py index c208ae51aa63..53d2694e5c20 100644 --- a/salt/modules/ssh.py +++ b/salt/modules/ssh.py @@ -119,9 +119,9 @@ def _get_config_file(user, config): if not uinfo: raise CommandExecutionError('User \'{0}\' does not exist'.format(user)) home = uinfo['home'] + config = _expand_authorized_keys_path(config, user, home) if not os.path.isabs(config): config = os.path.join(home, config) - config = _expand_authorized_keys_path(config, user, home) return config @@ -376,9 +376,9 @@ def check_key_file(user, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -465,9 +465,9 @@ def rm_auth_key_from_file(user, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -589,9 +589,9 @@ def set_auth_key_from_file(user, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -807,7 +807,7 @@ def recv_known_host(hostname, time anything was read from that host, then the connection is closed and the host in question considered unavailable. Default is 5 seconds. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -980,7 +980,7 @@ def set_known_host(user=None, time anything was read from that host, then the connection is closed and the host in question considered unavailable. Default is 5 seconds. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/state.py b/salt/modules/state.py index d57496247218..c0db94342509 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -239,7 +239,8 @@ def high(data, test=False, queue=False, **kwargs): 'is specified.' ) try: - st_ = salt.state.State(__opts__, pillar, pillar_enc=pillar_enc, proxy=__proxy__) + st_ = salt.state.State(__opts__, pillar, pillar_enc=pillar_enc, proxy=__proxy__, + context=__context__) except NameError: st_ = salt.state.State(__opts__, pillar, pillar_enc=pillar_enc) @@ -263,9 +264,9 @@ def template(tem, queue=False, **kwargs): ''' if 'env' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) saltenv = kwargs['env'] elif 'saltenv' in kwargs: @@ -276,7 +277,7 @@ def template(tem, queue=False, **kwargs): conflict = _check_queue(queue, kwargs) if conflict is not None: return conflict - st_ = salt.state.HighState(__opts__) + st_ = salt.state.HighState(__opts__, context=__context__) if not tem.endswith('.sls'): tem = '{sls}.sls'.format(sls=tem) high_state, errors = st_.render_state(tem, saltenv, '', None, local=True) @@ -485,7 +486,7 @@ def highstate(test=None, Additional pillar data to use for this function. Any pillar keys specified here will overwrite matching keys in the Pillar data. - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 GPG-encrypted CLI Pillar data is now supported via the GPG renderer. See :ref:`here ` for details. @@ -493,7 +494,7 @@ def highstate(test=None, Specify which renderer to use to decrypt encrypted data located within the ``pillar`` value. Currently, only ``gpg`` is supported. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 queue : False Instead of failing immediately when another state run is in progress, @@ -553,9 +554,9 @@ def highstate(test=None, if 'env' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) opts['environment'] = kwargs['env'] elif 'saltenv' in kwargs: @@ -580,6 +581,7 @@ def highstate(test=None, kwargs.get('__pub_jid'), pillar_enc=pillar_enc, proxy=__proxy__, + context=__context__, mocked=kwargs.get('mock', False)) except NameError: st_ = salt.state.HighState(opts, @@ -634,7 +636,7 @@ def sls(mods, Additional pillar data to use for this function. Any pillar keys specified here will overwrite matching keys in the Pillar data. - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 GPG-encrypted CLI Pillar data is now supported via the GPG renderer. See :ref:`here ` for details. @@ -642,7 +644,7 @@ def sls(mods, Specify which renderer to use to decrypt encrypted data located within the ``pillar`` value. Currently, only ``gpg`` is supported. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 queue : ``False`` Instead of failing immediately when another state run is in progress, @@ -695,9 +697,9 @@ def sls(mods, concurrent = kwargs.get('concurrent', False) if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -771,6 +773,7 @@ def sls(mods, kwargs.get('__pub_jid'), pillar_enc=pillar_enc, proxy=__proxy__, + context=__context__, mocked=kwargs.get('mock', False)) except NameError: st_ = salt.state.HighState(opts, @@ -883,7 +886,7 @@ def top(topfn, 'is specified.' ) - st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc) + st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, context=__context__) st_.push_active() st_.opts['state_top'] = salt.utils.url.create(topfn) if saltenv: @@ -1037,9 +1040,9 @@ def show_low_sls(mods, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -1092,9 +1095,9 @@ def show_sls(mods, saltenv='base', test=None, queue=False, env=None, **kwargs): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -1153,9 +1156,9 @@ def show_top(queue=False, **kwargs): opts = copy.deepcopy(__opts__) if 'env' in kwargs: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) opts['environment'] = kwargs['env'] elif 'saltenv' in kwargs: @@ -1489,7 +1492,7 @@ def event(tagmatch='*', r''' Watch Salt's event bus and block until the given tag is matched - .. versionadded:: Boron + .. versionadded:: 2016.3.0 This is useful for utilizing Salt's event bus from shell scripts or for taking simple actions directly from the CLI. diff --git a/salt/modules/status.py b/salt/modules/status.py index 2f4405887bb0..67d773c8abdb 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -833,7 +833,7 @@ def master(master=None, connected=True): def time(format='%A, %d. %B %Y %I:%M%p'): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Return the current time on the minion, formated based on the format parameter. diff --git a/salt/modules/sysfs.py b/salt/modules/sysfs.py index 775959382dd5..4c1eb675d31d 100644 --- a/salt/modules/sysfs.py +++ b/salt/modules/sysfs.py @@ -3,7 +3,7 @@ Module for interfacing with SysFS .. seealso:: https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' # Import python libs from __future__ import absolute_import diff --git a/salt/modules/sysmod.py b/salt/modules/sysmod.py index 3abe7bc7bc18..53cb01bb3fe4 100644 --- a/salt/modules/sysmod.py +++ b/salt/modules/sysmod.py @@ -882,7 +882,7 @@ def state_schema(module=''): ''' Return a JSON Schema for the given state function(s) - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index bab87aaf7da3..ee19d17ce30c 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -541,7 +541,14 @@ def mask(name, runtime=False): redirect_stderr=True) if out['retcode'] != 0: +<<<<<<< HEAD raise CommandExecutionError('Failed to mask service \'%s\'' % name) +======= + raise CommandExecutionError( + 'Failed to mask service \'%s\'' % name, + info=out['stdout'] + ) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b return True @@ -755,7 +762,7 @@ def enabled(name, **kwargs): # pylint: disable=unused-argument def disabled(name): ''' - Return if the named service is disabled to start on boot + Return if the named service is disabled from starting on boot CLI Example: diff --git a/salt/modules/telemetry.py b/salt/modules/telemetry.py index 6ef5dacf52b4..5dcd80d31c48 100644 --- a/salt/modules/telemetry.py +++ b/salt/modules/telemetry.py @@ -2,7 +2,7 @@ ''' Connection module for Telemetry -.. versionadded:: Boron +.. versionadded:: 2016.3.0 https://github.com/mongolab/mongolab-telemetry-api-docs/blob/master/alerts.md diff --git a/salt/modules/timezone.py b/salt/modules/timezone.py index 6f636dd73d9f..9acc728431d1 100644 --- a/salt/modules/timezone.py +++ b/salt/modules/timezone.py @@ -240,7 +240,7 @@ def zone_compare(timezone): /etc/localtime. Returns True if names and hash sums match, and False if not. Mostly useful for running state checks. - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 .. note:: diff --git a/salt/modules/tomcat.py b/salt/modules/tomcat.py index 1e839f379e7b..fe279408e880 100644 --- a/salt/modules/tomcat.py +++ b/salt/modules/tomcat.py @@ -579,9 +579,9 @@ def deploy_war(war, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/modules/vboxmanage.py b/salt/modules/vboxmanage.py index 683fe670b535..0378216e7b2c 100644 --- a/salt/modules/vboxmanage.py +++ b/salt/modules/vboxmanage.py @@ -2,7 +2,7 @@ ''' Support for VirtualBox using the VBoxManage command -.. versionadded:: Boron +.. versionadded:: 2016.3.0 If the ``vboxdrv`` kernel module is not loaded, this module can automatically load it by configuring ``autoload_vboxdrv`` in ``/etc/salt/minion``: diff --git a/salt/modules/virt.py b/salt/modules/virt.py index 8a08c1b4a7ab..dfd517c46edd 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -1829,7 +1829,7 @@ def list_snapshots(domain=None): ''' List available snapshots for certain vm or for all. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -1857,7 +1857,7 @@ def snapshot(domain, name=None, suffix=None): * **suffix**: Add suffix for the new name. Useful in states, where such snapshots can be distinguished from manually created. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -1891,7 +1891,7 @@ def delete_snapshots(name, *names, **kwargs): * **all**: Remove all snapshots. Values: True or False (default False). - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -1918,7 +1918,7 @@ def revert_snapshot(name, snapshot=None, cleanup=False): * **cleanup**: Remove all newer than reverted snapshots. Values: True or False (default False). - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: @@ -1979,7 +1979,7 @@ def revert_snapshot(name, snapshot=None, cleanup=False): # Deprecated aliases def create(domain): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Use :py:func:`~salt.modules.virt.start` instead. Start a defined domain @@ -1996,7 +1996,7 @@ def create(domain): def destroy(domain): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Use :py:func:`~salt.modules.virt.stop` instead. Power off a defined domain @@ -2013,7 +2013,7 @@ def destroy(domain): def list_vms(): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Use :py:func:`~salt.modules.virt.list_domains` instead. List all virtual machines. @@ -2045,7 +2045,7 @@ def cpu_baseline(full=False, migratable=False, out='libvirt'): ''' Return the optimal 'custom' CPU baseline config for VM's on this minion - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param full: Return all CPU features rather than the ones on top of the closest CPU model :param migratable: Exclude CPU features that are unmigratable (libvirt 2.13+) diff --git a/salt/modules/virtualenv_mod.py b/salt/modules/virtualenv_mod.py index 2b266df06653..e95d2fecb370 100644 --- a/salt/modules/virtualenv_mod.py +++ b/salt/modules/virtualenv_mod.py @@ -332,7 +332,7 @@ def get_distribution_path(venv, distribution): ''' Return the path to a distribution installed inside a virtualenv - .. versionadded:: Boron + .. versionadded:: 2016.3.0 venv Path to the virtualenv. @@ -377,23 +377,23 @@ def get_resource_path(venv, package Name of the package in which the resource resides - .. versionadded:: Boron + .. versionadded:: 2016.3.0 package_or_requirement Name of the package in which the resource resides - .. deprecated:: Boron + .. deprecated:: Nitrogen Use ``package`` instead. resource Name of the resource of which the path is to be returned - .. versionadded:: Boron + .. versionadded:: 2016.3.0 resource_name Name of the resource of which the path is to be returned - .. deprecated:: Boron + .. deprecated:: Nitrogen .. versionadded:: 2015.5.0 @@ -468,23 +468,23 @@ def get_resource_content(venv, package Name of the package in which the resource resides - .. versionadded:: Boron + .. versionadded:: 2016.3.0 package_or_requirement Name of the package in which the resource resides - .. deprecated:: Boron + .. deprecated:: Nitrogen Use ``package`` instead. resource Name of the resource of which the content is to be returned - .. versionadded:: Boron + .. versionadded:: 2016.3.0 resource_name Name of the resource of which the content is to be returned - .. deprecated:: Boron + .. deprecated:: Nitrogen .. versionadded:: 2015.5.0 diff --git a/salt/modules/win_iis.py b/salt/modules/win_iis.py index 3f163d1dd70e..57b7f167ffb0 100644 --- a/salt/modules/win_iis.py +++ b/salt/modules/win_iis.py @@ -4,7 +4,7 @@ :platform: Windows -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' diff --git a/salt/modules/win_network.py b/salt/modules/win_network.py index 5d8f035c4fb3..7f75c5df4eb4 100644 --- a/salt/modules/win_network.py +++ b/salt/modules/win_network.py @@ -301,7 +301,7 @@ def connect(host, port=None, **kwargs): Test connectivity to a host using a particular port from the minion. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Example: diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index a758a958b12a..4c23194c2f89 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -583,8 +583,15 @@ def install(name=None, refresh=False, pkgs=None, saltenv='base', **kwargs): if 'latest' in pkginfo: latest.append(pkg_name) +<<<<<<< HEAD # Get the installer installer = pkginfo[version_num].get('installer') +======= + # Get the installer settings from winrepo.p + installer = pkginfo[version_num].get('installer', False) + cache_dir = pkginfo[version_num].get('cache_dir', False) + cache_file = pkginfo[version_num].get('cache_file', False) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b # Is there an installer configured? if not installer: diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 9d488709677a..6f7fbf1add89 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -469,7 +469,7 @@ def config(name, r''' Modify the named service. - .. versionadded:: 2015.8.5 + .. versionadded:: 2015.8.6 Required parameters: diff --git a/salt/modules/win_system.py b/salt/modules/win_system.py index 15f4296aa862..7903d19a1e08 100644 --- a/salt/modules/win_system.py +++ b/salt/modules/win_system.py @@ -435,7 +435,7 @@ def get_computer_desc(): def get_hostname(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Get the hostname of the windows minion @@ -456,7 +456,7 @@ def get_hostname(): def set_hostname(hostname): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Set the hostname of the windows minion, requires a restart before this will be updated. diff --git a/salt/modules/win_task.py b/salt/modules/win_task.py index 3373bc593316..902f9b20a0d7 100644 --- a/salt/modules/win_task.py +++ b/salt/modules/win_task.py @@ -2,7 +2,7 @@ # https://msdn.microsoft.com/en-us/library/windows/desktop/aa383608(v=vs.85).aspx ''' Windows Task Scheduler Module -.. versionadded:: Boron +.. versionadded:: 2016.3.0 A module for working with the Windows Task Scheduler. You can add and edit existing tasks. diff --git a/salt/modules/xapi.py b/salt/modules/xapi.py index dfb3eaa370ab..89ae03009aa8 100644 --- a/salt/modules/xapi.py +++ b/salt/modules/xapi.py @@ -930,7 +930,7 @@ def _info(vm_): # Deprecated aliases def create(domain): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.start` instead. Start a defined domain @@ -947,7 +947,7 @@ def create(domain): def destroy(domain): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.stop` instead. Power off a defined domain @@ -964,7 +964,7 @@ def destroy(domain): def list_vms(): ''' - .. deprecated:: Boron + .. deprecated:: Nitrogen Use :py:func:`~salt.modules.virt.list_domains` instead. List all virtual machines. diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 67b705c3b7db..42d508b60a0c 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -59,6 +59,8 @@ log = logging.getLogger(__name__) +__HOLD_PATTERN = r'\w+(?:[.-][^-]+)*' + # Define the module's virtual name __virtualname__ = 'pkg' @@ -97,6 +99,36 @@ def _strip_headers(output, *args): return ret +def _get_hold(line, pattern=__HOLD_PATTERN, full=True): + ''' + Resolve a package name from a line containing the hold expression. If the + regex is not matched, None is returned. + + yum ==> 2:vim-enhanced-7.4.629-5.el6.* + dnf ==> vim-enhanced-2:7.4.827-1.fc22.* + ''' + if full: + if _yum() == 'dnf': + lock_re = r'({0}-\S+)'.format(pattern) + else: + lock_re = r'(\d+:{0}-\S+)'.format(pattern) + else: + if _yum() == 'dnf': + lock_re = r'({0}-\S+)'.format(pattern) + else: + lock_re = r'\d+:({0}-\S+)'.format(pattern) + + match = re.search(lock_re, line) + if match: + if not full: + woarch = match.group(1).rsplit('.', 1)[0] + worel = woarch.rsplit('-', 1)[0] + return worel.rsplit('-', 1)[0] + else: + return match.group(1) + return None + + def _yum(): ''' return yum or dnf depending on version @@ -115,6 +147,7 @@ def _repoquery_pkginfo(repoquery_args): ''' Wrapper to call repoquery and parse out all the tuples ''' +<<<<<<< HEAD ret = [] for line in _repoquery(repoquery_args, ignore_stderr=True): pkginfo = salt.utils.pkg.rpm.parse_pkginfo( @@ -184,6 +217,8 @@ def _yum_pkginfo(output): names are long) retrieving the name, version, etc., and return a list of pkginfo namedtuples. ''' +======= +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cur = {} keys = itertools.cycle(('name', 'version', 'repoid')) values = salt.utils.itertools.split(_strip_headers(output)) @@ -230,6 +265,7 @@ def _check_versionlock(): ) +<<<<<<< HEAD def _repoquery(repoquery_args, query_format=salt.utils.pkg.rpm.QUERYFORMAT, ignore_stderr=False): @@ -264,6 +300,8 @@ def _repoquery(repoquery_args, return call['stdout'].splitlines() +======= +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def _get_repo_options(**kwargs): ''' Returns a string of '--enablerepo' and '--disablerepo' options to be used @@ -279,6 +317,7 @@ def _get_repo_options(**kwargs): if repo and not fromrepo: fromrepo = repo +<<<<<<< HEAD use_dnf_repoquery = kwargs.get('repoquery', False) and _yum() == 'dnf' ret = [] if fromrepo: @@ -311,6 +350,27 @@ def _get_repo_options(**kwargs): else: log.info('Enabling repo \'{0}\''.format(enablerepo)) ret.append('--enablerepo=\'{0}\''.format(enablerepo)) +======= + ret = [] + if fromrepo: + log.info('Restricting to repo \'{0}\''.format(fromrepo)) + ret.extend(['--disablerepo=*', '--enablerepo=' + fromrepo]) + else: + if disablerepo: + targets = [disablerepo] \ + if not isinstance(disablerepo, list) \ + else disablerepo + log.info('Disabling repo(s): {0}'.format(', '.join(disablerepo))) + ret.extend( + ['--disablerepo={0}'.format(x) for x in disablerepo] + ) + if enablerepo: + targets = [enablerepo] \ + if not isinstance(enablerepo, list) \ + else enablerepo + log.info('Enabling repo(s): {0}'.format(', '.join(enablerepo))) + ret.extend(['--enablerepo={0}'.format(x) for x in enablerepo]) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b return ret @@ -320,6 +380,7 @@ def _get_excludes_option(**kwargs): based on the kwargs. ''' disable_excludes = kwargs.get('disableexcludes', '') +<<<<<<< HEAD if disable_excludes: if kwargs.get('repoquery', False) and _yum() == 'dnf': @@ -331,6 +392,13 @@ def _get_excludes_option(**kwargs): log.info('Disabling excludes for \'{0}\''.format(disable_excludes)) return ['--disableexcludes=\'{0}\''.format(disable_excludes)] return [] +======= + ret = [] + if disable_excludes: + log.info('Disabling excludes for \'{0}\''.format(disable_excludes)) + ret.append(['--disableexcludes={0}'.format(disable_excludes)]) + return ret +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def _get_branch_option(**kwargs): @@ -340,12 +408,20 @@ def _get_branch_option(**kwargs): ''' # Get branch option from the kwargs branch = kwargs.get('branch', '') +<<<<<<< HEAD branch_arg = '' if branch: log.info('Adding branch \'{0}\''.format(branch)) branch_arg = '--branch=\'{0}\''.format(branch) return branch_arg +======= + ret = [] + if branch: + log.info('Adding branch \'{0}\''.format(branch)) + ret.append('--branch=\'{0}\''.format(branch)) + return ret +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def _get_yum_config(): @@ -866,7 +942,11 @@ def list_upgrades(refresh=True, **kwargs): exclude_arg = _get_excludes_option(**kwargs) if salt.utils.is_true(refresh): +<<<<<<< HEAD refresh_db(**kwargs) +======= + refresh_db(check_update=False, **kwargs) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cmd = [_yum(), '--quiet'] cmd.extend(repo_arg) @@ -880,6 +960,12 @@ def list_upgrades(refresh=True, **kwargs): return {} return dict([(x.name, x.version) for x in _yum_pkginfo(out['stdout'])]) +<<<<<<< HEAD +======= + +# Preserve expected CLI usage (yum list updates) +list_updates = salt.utils.alias_function(list_upgrades, 'list_updates') +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def info_installed(*names): @@ -908,6 +994,7 @@ def info_installed(*names): return ret +<<<<<<< HEAD def check_db(*names, **kwargs): ''' .. versionadded:: 0.17.0 @@ -982,6 +1069,8 @@ def check_db(*names, **kwargs): return ret +======= +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def refresh_db(**kwargs): ''' Check the yum repos for updated packages @@ -1036,10 +1125,19 @@ def refresh_db(**kwargs): update_cmd.extend(args) __salt__['cmd.run'](clean_cmd, python_shell=False) +<<<<<<< HEAD result = __salt__['cmd.retcode'](update_cmd, ignore_retcode=True, python_shell=False) return retcodes.get(result, False) +======= + if check_update_: + result = __salt__['cmd.retcode'](update_cmd, + ignore_retcode=True, + python_shell=False) + return retcodes.get(result, False) + return True +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def clean_metadata(**kwargs): @@ -1293,6 +1391,11 @@ def _add_common_args(cmd): if skip_verify: cmd.append('--nogpgcheck') +<<<<<<< HEAD +======= + errors = [] + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b if targets: cmd = [_yum(), '-y'] if _yum() == 'dnf': @@ -1300,36 +1403,63 @@ def _add_common_args(cmd): _add_common_args(cmd) cmd.append('install') cmd.extend(targets) +<<<<<<< HEAD __salt__['cmd.run_all']( +======= + out = __salt__['cmd.run_all']( +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cmd, output_loglevel='trace', python_shell=False, redirect_stderr=True ) +<<<<<<< HEAD +======= + if out['retcode'] != 0: + errors.append(out['stdout']) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b if downgrade: cmd = [_yum(), '-y'] _add_common_args(cmd) cmd.append('downgrade') cmd.extend(downgrade) +<<<<<<< HEAD __salt__['cmd.run_all']( +======= + out = __salt__['cmd.run_all']( +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cmd, output_loglevel='trace', python_shell=False, redirect_stderr=True ) +<<<<<<< HEAD +======= + if out['retcode'] != 0: + errors.append(out['stdout']) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b if to_reinstall: cmd = [_yum(), '-y'] _add_common_args(cmd) cmd.append('reinstall') cmd.extend(six.itervalues(to_reinstall)) +<<<<<<< HEAD __salt__['cmd.run_all']( +======= + out = __salt__['cmd.run_all']( +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cmd, output_loglevel='trace', python_shell=False, redirect_stderr=True ) +<<<<<<< HEAD +======= + if out['retcode'] != 0: + errors.append(out['stdout']) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __context__.pop('pkg.list_pkgs', None) new = list_pkgs() @@ -1345,9 +1475,22 @@ def _add_common_args(cmd): return ret +<<<<<<< HEAD def upgrade(refresh=True, skip_verify=False, **kwargs): ''' Run a full system upgrade, a yum upgrade +======= +def upgrade(refresh=True, + skip_verify=False, + name=None, + pkgs=None, + normalize=True, + **kwargs): + ''' + Run a full system upgrade (a ``yum upgrade`` or ``dnf upgrade``), or + upgrade specified packages. If the packages aren't installed, they will + not be installed. +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b .. versionchanged:: 2014.7.0 @@ -1380,7 +1523,57 @@ def upgrade(refresh=True, skip_verify=False, **kwargs): Disable exclude from main, for a repo or for everything. (e.g., ``yum --disableexcludes='main'``) +<<<<<<< HEAD .. versionadded:: 2014.7.0 +======= + .. versionadded:: 2014.7 + name + The name of the package to be upgraded. Note that this parameter is + ignored if "pkgs" is passed. + + 32-bit packages can be upgraded on 64-bit systems by appending the + architecture designation (``.i686``, ``.i586``, etc.) to the end of the + package name. + + Warning: if you forget 'name=' and run pkg.upgrade openssl, ALL packages + are upgraded. This will be addressed in next releases. + + CLI Example: + + .. code-block:: bash + + salt '*' pkg.upgrade name=openssl + + .. versionadded:: 2016.3.0 + pkgs + A list of packages to upgrade from a software repository. Must be + passed as a python list. A specific version number can be specified + by using a single-element dict representing the package and its + version. If the package was not already installed on the system, + it will not be installed. + + CLI Examples: + + .. code-block:: bash + + salt '*' pkg.upgrade pkgs='["foo", "bar"]' + salt '*' pkg.upgrade pkgs='["foo", {"bar": "1.2.3-4.el5"}]' + + .. versionadded:: 2016.3.0 + + normalize : True + Normalize the package name by removing the architecture. This is useful + for poorly created packages which might include the architecture as an + actual part of the name such as kernel modules which match a specific + kernel version. + + .. code-block:: bash + + salt -G role:nsd pkg.install gpfs.gplbin-2.6.32-279.31.1.el6.x86_64 normalize=False + + .. versionadded:: 2016.3.0 + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b ''' repo_arg = _get_repo_options(**kwargs) exclude_arg = _get_excludes_option(**kwargs) @@ -1390,6 +1583,21 @@ def upgrade(refresh=True, skip_verify=False, **kwargs): refresh_db(**kwargs) old = list_pkgs() +<<<<<<< HEAD +======= + try: + pkg_params = __salt__['pkg_resource.parse_targets']( + name=name, + pkgs=pkgs, + sources=None, + normalize=normalize, + **kwargs)[0] + except MinionError as exc: + raise CommandExecutionError(exc) + + targets = [x for x in pkg_params] + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b cmd = [_yum(), '--quiet', '-y'] for args in (repo_arg, exclude_arg, branch_arg): if args: @@ -1397,6 +1605,10 @@ def upgrade(refresh=True, skip_verify=False, **kwargs): if skip_verify: cmd.append('--nogpgcheck') cmd.append('upgrade') +<<<<<<< HEAD +======= + cmd.extend(targets) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __salt__['cmd.run'](cmd, output_loglevel='trace', python_shell=False) __context__.pop('pkg.list_pkgs', None) @@ -1443,8 +1655,23 @@ def remove(name=None, pkgs=None, **kwargs): # pylint: disable=W0613 targets = [x for x in pkg_params if x in old] if not targets: return {} +<<<<<<< HEAD cmd = [_yum(), '-y', 'remove'] + targets __salt__['cmd.run'](cmd, output_loglevel='trace') +======= + + out = __salt__['cmd.run_all']( + [_yum(), '-y', 'remove'] + targets, + output_loglevel='trace', + python_shell=False + ) + + if out['retcode'] != 0 and out['stderr']: + errors = [out['stderr']] + else: + errors = [] + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b __context__.pop('pkg.list_pkgs', None) new = list_pkgs() ret = salt.utils.compare_dicts(old, new) @@ -1564,8 +1791,15 @@ def hold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W0613 ret[target]['comment'] = ('Package {0} is set to be held.' .format(target)) else: +<<<<<<< HEAD cmd = [_yum(), 'versionlock', target] out = __salt__['cmd.run_all'](cmd, python_shell=False) +======= + out = __salt__['cmd.run_all']( + [_yum(), 'versionlock', target], + python_shell=False + ) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b if out['retcode'] == 0: ret[target].update(result=True) @@ -1636,7 +1870,11 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 else: targets.append(name) - current_locks = list_holds(full=False) + # Yum's versionlock plugin doesn't support passing just the package name + # when removing a lock, so we need to get the full list and then use + # fnmatch below to find the match. + current_locks = list_holds(full=_yum() == 'yum') + ret = {} for target in targets: if isinstance(target, dict): @@ -1647,15 +1885,35 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 'result': False, 'comment': ''} - search_locks = [x for x in current_locks if target in x] + if _yum() == 'dnf': + search_locks = [x for x in current_locks if x == target] + else: + # To accommodate yum versionlock's lack of support for removing + # locks using just the package name, we have to use fnmatch to do + # glob matching on the target name, and then for each matching + # expression double-check that the package name (obtained via + # _get_hold()) matches the targeted package. + search_locks = [ + x for x in current_locks + if fnmatch.fnmatch(x, '*{0}*'.format(target)) + and target == _get_hold(x, full=False) + ] + if search_locks: - if 'test' in __opts__ and __opts__['test']: + if __opts__['test']: ret[target].update(result=None) ret[target]['comment'] = ('Package {0} is set to be unheld.' .format(target)) else: +<<<<<<< HEAD cmd = [_yum(), 'versionlock', 'delete'] + search_locks out = __salt__['cmd.run_all'](cmd, python_shell=False) +======= + out = __salt__['cmd.run_all']( + [_yum(), 'versionlock', 'delete'] + search_locks, + python_shell=False + ) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b if out['retcode'] == 0: ret[target].update(result=True) @@ -1673,9 +1931,9 @@ def unhold(name=None, pkgs=None, sources=None, **kwargs): # pylint: disable=W06 return ret -def list_holds(pattern=r'\w+(?:[.-][^-]+)*', full=True): +def list_holds(pattern=__HOLD_PATTERN, full=True): r''' - .. versionchanged:: Boron,2015.8.4,2015.5.10 + .. versionchanged:: 2016.3.0,2015.8.4,2015.5.10 Function renamed from ``pkg.get_locked_pkgs`` to ``pkg.list_holds``. List information on locked packages @@ -1704,26 +1962,10 @@ def list_holds(pattern=r'\w+(?:[.-][^-]+)*', full=True): ''' _check_versionlock() - # yum ==> 2:vim-enhanced-7.4.629-5.el6.* - # dnf ==> vim-enhanced-2:7.4.827-1.fc22.* - - yum_cmd = _yum() - if full: - if yum_cmd == 'dnf': - lock_re = r'({0}-\S+)'.format(pattern) - else: - lock_re = r'(\d+:{0}-\S+)'.format(pattern) - else: - if yum_cmd == 'dnf': - lock_re = r'({0}-\S+)'.format(pattern) - else: - lock_re = r'\d+:({0}-\S+)'.format(pattern) - - pat = re.compile(lock_re) - - out = __salt__['cmd.run']([yum_cmd, 'versionlock', 'list'], + out = __salt__['cmd.run']([_yum(), 'versionlock', 'list'], python_shell=False) ret = [] +<<<<<<< HEAD for item in out.splitlines(): match = pat.search(item) if match: @@ -1735,6 +1977,12 @@ def list_holds(pattern=r'\w+(?:[.-][^-]+)*', full=True): else: target = match.group(1) ret.append(target) +======= + for line in salt.utils.itertools.split(out, '\n'): + match = _get_hold(line, pattern=pattern, full=full) + if match is not None: + ret.append(match) +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b return ret get_locked_packages = salt.utils.alias_function(list_holds, 'get_locked_packages') @@ -1821,7 +2069,7 @@ def group_list(): def group_info(name, expand=False): ''' .. versionadded:: 2014.1.0 - .. versionchanged:: Boron,2015.8.4,2015.5.10 + .. versionchanged:: 2016.3.0,2015.8.4,2015.5.10 The return data has changed. A new key ``type`` has been added to distinguish environment groups from package groups. Also, keys for the group name and group ID have been added. The ``mandatory packages``, @@ -1832,6 +2080,19 @@ def group_info(name, expand=False): Lists packages belonging to a certain group +<<<<<<< HEAD +======= + name + Name of the group to query + + expand : False + If the specified group is an environment group, then the group will be + expanded and the return data will include package names instead of + group names. + + .. versionadded:: 2016.3.0 + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b CLI Example: .. code-block:: bash @@ -1906,7 +2167,7 @@ def group_info(name, expand=False): def group_diff(name): ''' .. versionadded:: 2014.1.0 - .. versionchanged:: Boron,2015.8.4,2015.5.10 + .. versionchanged:: 2016.3.0,2015.8.4,2015.5.10 Environment groups are now supported. The key names have been renamed, similar to the changes made in :py:func:`pkg.group_info `. @@ -2412,7 +2673,11 @@ def owner(*paths): ret = {} for path in paths: ret[path] = __salt__['cmd.run_stdout']( +<<<<<<< HEAD ['rpm', '-qf', '--queryformat', '%{NAME}', path], +======= + cmd_prefix + [path], +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b output_loglevel='trace', python_shell=False ) diff --git a/salt/modules/zenoss.py b/salt/modules/zenoss.py index 7cbb223539ee..79229beaa4fb 100644 --- a/salt/modules/zenoss.py +++ b/salt/modules/zenoss.py @@ -2,7 +2,7 @@ ''' Module for working with the Zenoss API -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module requires a 'zenoss' entry in the master/minion config. @@ -179,8 +179,6 @@ def set_prod_state(prod_state, device=None): ''' A function to set the prod_state in zenoss. - versionadded:: Boron - Parameters: prod_state: (Required) Integer value of the state device: (Optional) Will use the grain 'fqdn' by default. diff --git a/salt/modules/zfs.py b/salt/modules/zfs.py index f25e9db675f4..3ecd53dc5f58 100644 --- a/salt/modules/zfs.py +++ b/salt/modules/zfs.py @@ -109,7 +109,7 @@ def exists(name, **kwargs): def create(name, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Create a ZFS File System. @@ -248,7 +248,7 @@ def destroy(name, **kwargs): def rename(name, new_name, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Rename or Relocate a ZFS File System. @@ -308,7 +308,7 @@ def rename(name, new_name, **kwargs): def list_(name=None, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return a list of all datasets or a specified dataset on the system and the values of their used, available, referenced, and mountpoint properties. @@ -395,7 +395,7 @@ def list_(name=None, **kwargs): def mount(name='-a', **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Mounts ZFS file systems @@ -439,7 +439,7 @@ def mount(name='-a', **kwargs): def unmount(name, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Unmounts ZFS file systems @@ -480,7 +480,7 @@ def unmount(name, **kwargs): def inherit(prop, name, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Clears the specified property @@ -528,7 +528,7 @@ def inherit(prop, name, **kwargs): def diff(name_a, name_b, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Display the difference between a snapshot of a given filesystem and another snapshot of that filesystem from a later time or the current @@ -578,7 +578,7 @@ def diff(name_a, name_b, **kwargs): def rollback(name, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Roll back the given dataset to a previous snapshot. @@ -643,7 +643,7 @@ def rollback(name, **kwargs): def clone(name_a, name_b, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Creates a clone of the given snapshot. @@ -708,7 +708,7 @@ def clone(name_a, name_b, **kwargs): def promote(name): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Promotes a clone file system to no longer be dependent on its "origin" snapshot. @@ -755,7 +755,7 @@ def promote(name): def bookmark(snapshot, bookmark): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Creates a bookmark of the given snapshot @@ -811,7 +811,7 @@ def bookmark(snapshot, bookmark): def holds(snapshot, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Lists all existing user references for the given snapshot or snapshots. @@ -863,7 +863,7 @@ def holds(snapshot, **kwargs): def hold(tag, *snapshot, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Adds a single reference, named with the tag argument, to the specified snapshot or snapshots. @@ -942,7 +942,7 @@ def hold(tag, *snapshot, **kwargs): def release(tag, *snapshot, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Removes a single reference, named with the tag argument, from the specified snapshot or snapshots. @@ -1019,7 +1019,7 @@ def release(tag, *snapshot, **kwargs): def snapshot(*snapshot, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Creates snapshots with the given names. @@ -1098,7 +1098,7 @@ def snapshot(*snapshot, **kwargs): def set(*dataset, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Sets the property or list of properties to the given value(s) for each dataset. @@ -1180,7 +1180,7 @@ def set(*dataset, **kwargs): def get(*dataset, **kwargs): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Displays properties for the given datasets. diff --git a/salt/modules/zpool.py b/salt/modules/zpool.py index 7ba651360282..6588d0717199 100644 --- a/salt/modules/zpool.py +++ b/salt/modules/zpool.py @@ -68,7 +68,7 @@ def __virtual__(): def healthy(): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Check if all zpools are healthy @@ -89,7 +89,7 @@ def healthy(): def status(zpool=None): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return the status of the named zpool @@ -198,7 +198,7 @@ def status(zpool=None): def iostat(zpool=None, sample_time=0): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Display I/O statistics for the given pools @@ -318,10 +318,10 @@ def zpool_list(): salt '*' zpool.zpool_list ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'zpool_list()\' module function is being deprecated and is ' 'being renamed to \'list()\'. This function \'zpool_list()\' will be removed in ' - 'Salt Boron.' + 'Salt Carbon.' ) return list_() @@ -329,7 +329,7 @@ def zpool_list(): def list_(properties='size,alloc,free,cap,frag,health', zpool=None): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Return information about (all) storage pools @@ -391,7 +391,7 @@ def list_(properties='size,alloc,free,cap,frag,health', zpool=None): def get(zpool, prop=None, show_source=False): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Retrieves the given list of properties @@ -445,7 +445,7 @@ def get(zpool, prop=None, show_source=False): def set(zpool, prop, value): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Sets the given property on the specified pool @@ -511,7 +511,7 @@ def exists(zpool): def destroy(zpool, force=False): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Destroys a storage pool @@ -550,7 +550,7 @@ def destroy(zpool, force=False): def scrub(zpool, stop=False): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Scrub a storage pool @@ -596,7 +596,7 @@ def scrub(zpool, stop=False): def create(zpool, *vdevs, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Create a simple zpool, a mirrored zpool, a zpool having nested VDEVs, a hybrid zpool with cache, spare and log drives or a zpool with RAIDZ-1, RAIDZ-2 or RAIDZ-3 @@ -725,7 +725,7 @@ def create(zpool, *vdevs, **kwargs): def add(zpool, *vdevs, **kwargs): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Add the specified vdev\'s to the given storage pool @@ -796,7 +796,7 @@ def add(zpool, *vdevs, **kwargs): def attach(zpool, device, new_device, force=False): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Attach specified device to zpool @@ -862,7 +862,7 @@ def attach(zpool, device, new_device, force=False): def detach(zpool, device): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Detach specified device to zpool @@ -904,7 +904,7 @@ def detach(zpool, device): def replace(zpool, old_device, new_device=None, force=False): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Replaces old_device with new_device. @@ -979,7 +979,7 @@ def replace(zpool, old_device, new_device=None, force=False): @salt.utils.decorators.which('mkfile') def create_file_vdev(size, *vdevs): ''' - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Creates file based ``virtual devices`` for a zpool @@ -1023,7 +1023,7 @@ def create_file_vdev(size, *vdevs): def export(*pools, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Export storage pools @@ -1070,7 +1070,7 @@ def export(*pools, **kwargs): def import_(zpool=None, new_name=None, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Import storage pools or list pools available for import @@ -1170,7 +1170,7 @@ def import_(zpool=None, new_name=None, **kwargs): def online(zpool, *vdevs, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Ensure that the specified devices are online @@ -1245,7 +1245,7 @@ def online(zpool, *vdevs, **kwargs): def offline(zpool, *vdevs, **kwargs): ''' .. versionadded:: 2015.5.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 Ensure that the specified devices are offline @@ -1303,7 +1303,7 @@ def offline(zpool, *vdevs, **kwargs): def reguid(zpool): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Generates a new unique identifier for the pool @@ -1338,7 +1338,7 @@ def reguid(zpool): def reopen(zpool): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Reopen all the vdevs associated with the pool @@ -1369,7 +1369,7 @@ def reopen(zpool): def upgrade(zpool=None, version=None): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Enables all supported features on the given pool @@ -1413,7 +1413,7 @@ def upgrade(zpool=None, version=None): def history(zpool=None, internal=False, verbose=False): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Displays the command history of the specified pools or all pools if no pool is specified diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index 3c6148011db0..41004b7c5e7c 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1325,14 +1325,18 @@ def list_products(all=False): doc = dom.parseString(__salt__['cmd.run'](("zypper -x products{0}".format(not all and ' -i' or '')), output_loglevel='trace')) for prd in doc.getElementsByTagName('product-list')[0].getElementsByTagName('product'): - p_data = dict() - p_nfo = dict(prd.attributes.items()) - p_name = p_nfo.pop('name') - p_data[p_name] = p_nfo - p_data[p_name]['eol'] = prd.getElementsByTagName('endoflife')[0].getAttribute('text') - descr = _get_first_aggregate_text(prd.getElementsByTagName('description')) - p_data[p_name]['description'] = " ".join([line.strip() for line in descr.split(os.linesep)]) - ret.append(p_data) + p_nfo = dict() + for k_p_nfo, v_p_nfo in prd.attributes.items(): + p_nfo[k_p_nfo] = k_p_nfo not in ['isbase', 'installed'] and v_p_nfo or v_p_nfo == 'true' + p_nfo['eol'] = prd.getElementsByTagName('endoflife')[0].getAttribute('text') + p_nfo['eol_t'] = int(prd.getElementsByTagName('endoflife')[0].getAttribute('time_t')) + p_nfo['description'] = " ".join( + [line.strip() for line in _get_first_aggregate_text( + prd.getElementsByTagName('description') + ).split(os.linesep)] + ) + + ret.append(p_nfo) return ret diff --git a/salt/netapi/__init__.py b/salt/netapi/__init__.py index 9aeaaa4d3276..c151914c086f 100644 --- a/salt/netapi/__init__.py +++ b/salt/netapi/__init__.py @@ -113,7 +113,7 @@ def local_subset(self, *args, **kwargs): ''' Run :ref:`execution modules ` against subsets of minions - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Wraps :py:meth:`salt.client.LocalClient.cmd_subset` ''' diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py index f654b55c6acb..a276f06657ad 100644 --- a/salt/netapi/rest_cherrypy/app.py +++ b/salt/netapi/rest_cherrypy/app.py @@ -345,7 +345,7 @@ def salt_token_tool(): def salt_api_acl_tool(username, request): ''' - ..versionadded:: Boron + ..versionadded:: 2016.3.0 Verifies user requests against the API whitelist. (User/IP pair) in order to provide whitelisting for the API similar to the diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py index fe3094215e8c..656cf173918d 100644 --- a/salt/pillar/__init__.py +++ b/salt/pillar/__init__.py @@ -38,9 +38,9 @@ def get_pillar(opts, grains, id_, saltenv=None, ext=None, env=None, funcs=None, ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -53,9 +53,13 @@ def get_pillar(opts, grains, id_, saltenv=None, ext=None, env=None, funcs=None, if opts['pillar_cache']: log.info('Compiling pillar from cache') log.debug('get_pillar using pillar cache with ext: {0}'.format(ext)) - return PillarCache(opts, grains, id_, saltenv, ext=ext, functions=funcs, + return PillarCache(opts, grains, minion_id, saltenv, ext=ext, functions=funcs, pillar=pillar, pillarenv=pillarenv) +<<<<<<< HEAD return ptype(opts, grains, id_, saltenv, ext, functions=funcs, +======= + return ptype(opts, grains, minion_id, saltenv, ext, functions=funcs, +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b pillar=pillar, pillarenv=pillarenv) @@ -67,9 +71,9 @@ def get_async_pillar(opts, grains, id_, saltenv=None, ext=None, env=None, funcs= ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -329,10 +333,10 @@ def __gen_opts(self, opts_in, grains, id_, saltenv=None, ext=None, env=None, pil ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env @@ -724,6 +728,8 @@ def ext_pillar(self, pillar, pillar_dirs): if not isinstance(run, dict): log.critical('The "ext_pillar" option is malformed') return {} + if run.keys()[0] in self.opts.get('exclude_ext_pillar', []): + continue for key, val in six.iteritems(run): if key not in self.ext_pillars: err = ('Specified ext_pillar interface {0} is ' diff --git a/salt/pillar/consul_pillar.py b/salt/pillar/consul_pillar.py index aeebd6798617..e8899a5d86de 100644 --- a/salt/pillar/consul_pillar.py +++ b/salt/pillar/consul_pillar.py @@ -160,6 +160,8 @@ def pillar_format(ret, keys, value): Perform data formatting to be used as pillar data and merge it with the current pillar data ''' + # drop leading/trailing whitespace, if any + value = value.strip(' \t\n\r') # skip it if value is None: return ret diff --git a/salt/pillar/mysql.py b/salt/pillar/mysql.py index 4b95f792b4c9..6b8d58f0d706 100644 --- a/salt/pillar/mysql.py +++ b/salt/pillar/mysql.py @@ -20,7 +20,7 @@ This legacy compatibility translates to depth 1. We do this so that it's backward compatible with older configs. -This is deprecated and slated to be removed in Boron. +This is deprecated and slated to be removed in Carbon. Configuring the mysql ext_pillar ===================================== @@ -59,7 +59,6 @@ import logging # Import Salt libs -import salt.utils from salt.pillar.sql_base import SqlBaseExtPillar # Set up logging @@ -129,16 +128,6 @@ def extract_queries(self, args, kwargs): This function normalizes the config block into a set of queries we can use. The return is a list of consistently laid out dicts. ''' - # Handle legacy query specification - if 'mysql_query' in kwargs: - salt.utils.warn_until( - 'Boron', - 'The legacy mysql_query configuration parameter is deprecated.' - 'See the docs for the new style of configuration.' - 'This functionality will be removed in Salt Boron.' - ) - args.insert(0, kwargs.pop('mysql_query')) - return super(MySQLExtPillar, self).extract_queries(args, kwargs) diff --git a/salt/pillar/sqlcipher.py b/salt/pillar/sqlcipher.py index 7f3fc7a7be1f..ac1d6cac0649 100644 --- a/salt/pillar/sqlcipher.py +++ b/salt/pillar/sqlcipher.py @@ -2,7 +2,7 @@ ''' Retrieve Pillar data by running a SQLCipher query -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Python SQLCipher support is provided by the pysqlcipher Python package. You need this module installed to query diff --git a/salt/pillar/stack.py b/salt/pillar/stack.py index 3e260651415a..bfd5fe5b8d44 100644 --- a/salt/pillar/stack.py +++ b/salt/pillar/stack.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- ''' -PillarStack -=========== +Simple and flexible YAML ext_pillar which can read pillar from within pillar. + +.. versionadded:: 2016.3.0 This custom saltstack ``ext_pillar`` is inspired by `varstack `_ but is heavily based on @@ -17,11 +18,27 @@ ``stack``, ``pillar``, ``__grains__``, ``__salt__``, ``__opts__`` objects - all these rendered files are then parsed as ``yaml`` - then all yaml dicts are merged in order with support for the following - merging strategies: ``merge-first``, ``merge-last``, and ``overwrite`` + merging strategies: ``merge-first``, ``merge-last``, ``remove``, and + ``overwrite`` - stack config files can be matched based on ``pillar``, ``grains``, or ``opts`` values, which make it possible to support kind of self-contained environments +Installation +------------ + +PillarStack is already bundled with Salt since 2016.3.0 version so there is +nothing to install from version 2016.3.0. + +If you use an older Salt version or you want to override PillarStack with a +more recent one, follow the installation procedure below. + +Installing the PillarStack ``ext_pillar`` is as simple as dropping the +``stack.py`` file in the ``/pillar`` directory (no external +python module required), given that ``extensions_modules`` is set in your +salt-master configuration, see: +http://docs.saltstack.com/en/latest/ref/configuration/master.html#extension-modules + Configuration in Salt --------------------- @@ -123,14 +140,14 @@ ├── config.cfg ├── core.yml ├── osarchs/ - │ ├── amd64.yml - │ └── armhf.yml + │   ├── amd64.yml + │   └── armhf.yml ├── oscodenames/ - │ ├── wheezy.yml - │ └── jessie.yml + │   ├── wheezy.yml + │   └── jessie.yml ├── roles/ - │ ├── web.yml - │ └── db.yml + │   ├── web.yml + │   └── db.yml └── minions/ ├── test-1-dev.yml └── test-2-dev.yml @@ -185,11 +202,11 @@ The way the data from a new ``yaml_data`` dict is merged with the existing ``stack`` data can be controlled by specifying a merging strategy. Right now -this strategy can either be ``merge-last`` (the default), ``merge-first``, or -``overwrite``. +this strategy can either be ``merge-last`` (the default), ``merge-first``, +``remove``, or ``overwrite``. Note that scalar values like strings, integers, booleans, etc. are always -evaluated using the ``overwrite`` strategy (other strategies don``t make sense +evaluated using the ``overwrite`` strategy (other strategies don't make sense in that case). The merging strategy can be set by including a dict in the form of: @@ -217,6 +234,14 @@ variables are swapped between the ``yaml_data`` and ``stack`` objects before being merged recursively with the ``merge-last`` previous strategy. +``remove`` strategy +~~~~~~~~~~~~~~~~~~~ + +If the ``remove`` strategy is selected, then content of dict or list variables +in ``stack`` are removed only if the correponding item is present in the +``yaml_data`` dict. +This allows for removing items from previously defined data. + ``overwrite`` strategy ~~~~~~~~~~~~~~~~~~~~~~ @@ -243,14 +268,14 @@ | uid: 500 | uid: 1000 | uid: 1000 | | roles: | roles: | roles: | | - sysadmin | - developer | - sysadmin | -| root: | mat: | - developer | -| uid: 0 | uid: 1001 | mat: | +| root: | mat: | - developer | +| uid: 0 | uid: 1001 | mat: | | | | uid: 1001 | | | | root: | | | | uid: 0 | +----------------------+-----------------------+-------------------------+ -Then you can specify the merging strategy to select using the ``__`` key: +Then you can select a custom merging strategy using the ``__`` key in a dict: +----------------------+-----------------------+-------------------------+ | ``stack`` | ``yaml_data`` | ``stack`` (after merge) | @@ -262,8 +287,8 @@ | uid: 500 | tom: | uid: 1000 | | roles: | uid: 1000 | roles: | | - sysadmin | roles: | - sysadmin | -| root: | - developer | - developer | -| uid: 0 | mat: | mat: | +| root: | - developer | - developer | +| uid: 0 | mat: | mat: | | | uid: 1001 | uid: 1001 | | | | root: | | | | uid: 0 | @@ -275,8 +300,8 @@ | uid: 500 | tom: | uid: 500 | | roles: | uid: 1000 | roles: | | - sysadmin | roles: | - developer | -| root: | - developer | - sysadmin | -| uid: 0 | mat: | mat: | +| root: | - developer | - sysadmin | +| uid: 0 | mat: | mat: | | | uid: 1001 | uid: 1001 | | | | root: | | | | uid: 0 | @@ -284,14 +309,57 @@ | .. code:: yaml | .. code:: yaml | .. code:: yaml | | | | | | users: | users: | users: | +| tom: | __: remove | root: | +| uid: 500 | tom: | uid: 0 | +| roles: | mat: | | +| - sysadmin | | | +| root: | | | +| uid: 0 | | | ++----------------------+-----------------------+-------------------------+ +| .. code:: yaml | .. code:: yaml | .. code:: yaml | +| | | | +| users: | users: | users: | | tom: | __: overwrite | tom: | | uid: 500 | tom: | uid: 1000 | | roles: | uid: 1000 | roles: | | - sysadmin | roles: | - developer | -| root: | - developer | mat: | -| uid: 0 | mat: | uid: 1001 | +| root: | - developer | mat: | +| uid: 0 | mat: | uid: 1001 | | | uid: 1001 | | +----------------------+-----------------------+-------------------------+ + +You can also select a custom merging strategy using a ``__`` object in a list: + ++----------------+-------------------------+-------------------------+ +| ``stack`` | ``yaml_data`` | ``stack`` (after merge) | ++================+=========================+=========================+ +| .. code:: yaml | .. code:: yaml | .. code:: yaml | +| | | | +| users: | users: | users: | +| - tom | - __: merge-last | - tom | +| - root | - mat | - root | +| | | - mat | ++----------------+-------------------------+-------------------------+ +| .. code:: yaml | .. code:: yaml | .. code:: yaml | +| | | | +| users: | users: | users: | +| - tom | - __: merge-first | - mat | +| - root | - mat | - tom | +| | | - root | ++----------------+-------------------------+-------------------------+ +| .. code:: yaml | .. code:: yaml | .. code:: yaml | +| | | | +| users: | users: | users: | +| - tom | - __: remove | - root | +| - root | - mat | | +| | - tom | | ++----------------+-------------------------+-------------------------+ +| .. code:: yaml | .. code:: yaml | .. code:: yaml | +| | | | +| users: | users: | users: | +| - tom | - __: overwrite | - mat | +| - root | - mat | | ++----------------+-------------------------+-------------------------+ ''' from __future__ import absolute_import @@ -301,14 +369,14 @@ import yaml from jinja2 import FileSystemLoader, Environment, TemplateNotFound -import salt.utils log = logging.getLogger(__name__) -strategies = ('overwrite', 'merge-first', 'merge-last') +strategies = ('overwrite', 'merge-first', 'merge-last', 'remove') def ext_pillar(minion_id, pillar, *args, **kwargs): + import salt.utils stack = {} stack_config_files = list(args) traverse = { @@ -380,6 +448,9 @@ def _merge_dict(stack, obj): return _cleanup(obj) else: for k, v in obj.iteritems(): + if strategy == 'remove': + stack.pop(k, None) + continue if k in stack: if strategy == 'merge-first': # merge-first is same as merge-last but the other way round @@ -412,6 +483,8 @@ def _merge_list(stack, obj): strategy, strategies)) if strategy == 'overwrite': return obj + elif strategy == 'remove': + return [item for item in stack if item not in obj] elif strategy == 'merge-first': return obj + stack else: diff --git a/salt/queues/pgjsonb_queue.py b/salt/queues/pgjsonb_queue.py index 66f73c055b3e..2c626194683f 100644 --- a/salt/queues/pgjsonb_queue.py +++ b/salt/queues/pgjsonb_queue.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ''' -.. versionadded:: Boron +.. versionadded:: 2016.3.0 This is a queue with postgres as the backend. It uses the jsonb store to store information for queues. diff --git a/salt/renderers/gpg.py b/salt/renderers/gpg.py index 6ead5d2026b9..8ed28910d684 100644 --- a/salt/renderers/gpg.py +++ b/salt/renderers/gpg.py @@ -95,7 +95,7 @@ Encrypted CLI Pillar Data ------------------------- -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Functions like :py:func:`state.highstate ` and :py:func:`state.sls ` allow for pillar data to be @@ -105,7 +105,7 @@ salt myminion state.highstate pillar="{'mypillar': 'foo'}" -Starting with the Boron release of Salt, it is now possible for this pillar +Starting with the 2016.3.0 release of Salt, it is now possible for this pillar data to be GPG-encrypted, and to use the GPG renderer to decrypt it. diff --git a/salt/returners/carbon_return.py b/salt/returners/carbon_return.py index 2d2fb4ecc892..d72cc7001f42 100644 --- a/salt/returners/carbon_return.py +++ b/salt/returners/carbon_return.py @@ -73,7 +73,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/couchdb_return.py b/salt/returners/couchdb_return.py index cd1c0e7156a2..b06cdda2ce74 100644 --- a/salt/returners/couchdb_return.py +++ b/salt/returners/couchdb_return.py @@ -33,7 +33,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/hipchat_return.py b/salt/returners/hipchat_return.py index 86a78b17a099..4d64f9c4093e 100644 --- a/salt/returners/hipchat_return.py +++ b/salt/returners/hipchat_return.py @@ -76,7 +76,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/influxdb_return.py b/salt/returners/influxdb_return.py index 825da1f2238e..b62f1ab2f893 100644 --- a/salt/returners/influxdb_return.py +++ b/salt/returners/influxdb_return.py @@ -43,7 +43,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/memcache_return.py b/salt/returners/memcache_return.py index 8411188aa8d1..db1a0a9a4e9b 100644 --- a/salt/returners/memcache_return.py +++ b/salt/returners/memcache_return.py @@ -38,7 +38,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/mongo_future_return.py b/salt/returners/mongo_future_return.py index 6f8c82266ac5..2d9a02160b54 100644 --- a/salt/returners/mongo_future_return.py +++ b/salt/returners/mongo_future_return.py @@ -56,7 +56,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/mongo_return.py b/salt/returners/mongo_return.py index ac73533484cd..279c0ea0bae5 100644 --- a/salt/returners/mongo_return.py +++ b/salt/returners/mongo_return.py @@ -45,7 +45,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash @@ -53,7 +53,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py index 2b0b4dae8769..b693ee346329 100644 --- a/salt/returners/mysql.py +++ b/salt/returners/mysql.py @@ -117,7 +117,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/nagios_return.py b/salt/returners/nagios_return.py index 3a5032521969..c51ba4b1f55e 100644 --- a/salt/returners/nagios_return.py +++ b/salt/returners/nagios_return.py @@ -41,7 +41,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/odbc.py b/salt/returners/odbc.py index 042ea3408cf0..7a19cba8e2f4 100644 --- a/salt/returners/odbc.py +++ b/salt/returners/odbc.py @@ -116,7 +116,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/pgjsonb.py b/salt/returners/pgjsonb.py index a8b48b7596fb..6f4963aa79d0 100644 --- a/salt/returners/pgjsonb.py +++ b/salt/returners/pgjsonb.py @@ -122,7 +122,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/postgres.py b/salt/returners/postgres.py index d53d92f6b423..5d0511d4df98 100644 --- a/salt/returners/postgres.py +++ b/salt/returners/postgres.py @@ -88,7 +88,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/pushover_returner.py b/salt/returners/pushover_returner.py index 8f6d68d62c86..ece9d631590c 100644 --- a/salt/returners/pushover_returner.py +++ b/salt/returners/pushover_returner.py @@ -2,7 +2,7 @@ ''' Return salt data via pushover (http://www.pushover.net) -.. versionadded:: Boron +.. versionadded:: 2016.3.0 The following fields can be set in the minion conf file:: @@ -70,8 +70,6 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron - .. code-block:: bash salt '*' test.ping --return pushover --return_kwargs '{"title": "Salt is awesome!"}' diff --git a/salt/returners/redis_return.py b/salt/returners/redis_return.py index d654ccb593ee..5278e3c98680 100644 --- a/salt/returners/redis_return.py +++ b/salt/returners/redis_return.py @@ -38,7 +38,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/slack_returner.py b/salt/returners/slack_returner.py index 605d52814df1..28cc5005def9 100644 --- a/salt/returners/slack_returner.py +++ b/salt/returners/slack_returner.py @@ -69,7 +69,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/smtp_return.py b/salt/returners/smtp_return.py index 95109b9f30e7..2be633bbae78 100644 --- a/salt/returners/smtp_return.py +++ b/salt/returners/smtp_return.py @@ -71,7 +71,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/sqlite3_return.py b/salt/returners/sqlite3_return.py index 41100eee9d58..4fc63f9a5668 100644 --- a/salt/returners/sqlite3_return.py +++ b/salt/returners/sqlite3_return.py @@ -73,7 +73,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/returners/xmpp_return.py b/salt/returners/xmpp_return.py index 32f340a1c826..353c1895c07b 100644 --- a/salt/returners/xmpp_return.py +++ b/salt/returners/xmpp_return.py @@ -58,7 +58,7 @@ To override individual configuration items, append --return_kwargs '{"key:": "value"}' to the salt command. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: bash diff --git a/salt/runners/cache.py b/salt/runners/cache.py index 674a85e9e75f..e8b55e1c6da6 100644 --- a/salt/runners/cache.py +++ b/salt/runners/cache.py @@ -11,7 +11,6 @@ import salt.utils import salt.utils.master import salt.payload -from salt.ext.six import string_types from salt.exceptions import SaltInvocationError from salt.fileserver import clear_lock as _clear_lock from salt.fileserver.gitfs import PER_REMOTE_OVERRIDES as __GITFS_OVERRIDES @@ -22,7 +21,7 @@ log = logging.getLogger(__name__) -def grains(tgt=None, expr_form='glob', outputter=None, **kwargs): +def grains(tgt=None, expr_form='glob', **kwargs): ''' Return cached grains of the targeted minions @@ -32,37 +31,15 @@ def grains(tgt=None, expr_form='glob', outputter=None, **kwargs): salt-run cache.grains ''' - deprecated_minion = kwargs.get('minion', None) - if tgt is None and deprecated_minion is None: - tgt = '*' # targat all minions for backward compatibility - elif tgt is None and isinstance(deprecated_minion, string_types): - salt.utils.warn_until( - 'Boron', - 'The \'minion\' argument to the cache.grains runner is ' - 'deprecated. Please specify the minion using the \'tgt\' ' - 'argument.' - ) - tgt = deprecated_minion - elif tgt is None: - return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=True, grains_fallback=False, opts=__opts__) cached_grains = pillar_util.get_minion_grains() - if outputter: - salt.utils.warn_until( - 'Boron', - 'The \'outputter\' argument to the cache.grains runner has ' - 'been deprecated. Please specify an outputter using --out. ' - 'See the output of \'salt-run -h\' for more information.' - ) - return {'outputter': outputter, 'data': cached_grains} - else: - return cached_grains + return cached_grains -def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs): +def pillar(tgt=None, expr_form='glob', **kwargs): ''' Return cached pillars of the targeted minions @@ -72,19 +49,6 @@ def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs): salt-run cache.pillar ''' - deprecated_minion = kwargs.get('minion', None) - if tgt is None and deprecated_minion is None: - tgt = '*' # targat all minions for backward compatibility - elif tgt is None and isinstance(deprecated_minion, string_types): - salt.utils.warn_until( - 'Boron', - 'The \'minion\' argument to the cache.pillar runner is ' - 'deprecated. Please specify the minion using the \'tgt\' ' - 'argument.' - ) - tgt = deprecated_minion - elif tgt is None: - return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=True, grains_fallback=False, @@ -92,19 +56,10 @@ def pillar(tgt=None, expr_form='glob', outputter=None, **kwargs): pillar_fallback=False, opts=__opts__) cached_pillar = pillar_util.get_minion_pillar() - if outputter: - salt.utils.warn_until( - 'Boron', - 'The \'outputter\' argument to the cache.pillar runner has ' - 'been deprecated. Please specify an outputter using --out. ' - 'See the output of \'salt-run -h\' for more information.' - ) - return {'outputter': outputter, 'data': cached_pillar} - else: - return cached_pillar + return cached_pillar -def mine(tgt=None, expr_form='glob', outputter=None, **kwargs): +def mine(tgt=None, expr_form='glob', **kwargs): ''' Return cached mine data of the targeted minions @@ -114,19 +69,6 @@ def mine(tgt=None, expr_form='glob', outputter=None, **kwargs): salt-run cache.mine ''' - deprecated_minion = kwargs.get('minion', None) - if tgt is None and deprecated_minion is None: - tgt = '*' # targat all minions for backward compatibility - elif tgt is None and isinstance(deprecated_minion, string_types): - salt.utils.warn_until( - 'Boron', - 'The \'minion\' argument to the cache.mine runner is ' - 'deprecated. Please specify the minion using the \'tgt\' ' - 'argument.' - ) - tgt = deprecated_minion - elif tgt is None: - return {} pillar_util = salt.utils.master.MasterPillarUtil(tgt, expr_form, use_cached_grains=False, grains_fallback=False, @@ -134,16 +76,7 @@ def mine(tgt=None, expr_form='glob', outputter=None, **kwargs): pillar_fallback=False, opts=__opts__) cached_mine = pillar_util.get_cached_mine_data() - if outputter: - salt.utils.warn_until( - 'Boron', - 'The \'outputter\' argument to the cache.mine runner has ' - 'been deprecated. Please specify an outputter using --out. ' - 'See the output of \'salt-run -h\' for more information.' - ) - return {'outputter': outputter, 'data': cached_mine} - else: - return cached_mine + return cached_mine def _clear_cache(tgt=None, diff --git a/salt/runners/cloud.py b/salt/runners/cloud.py index 22b3d429383f..c54acc4066ff 100644 --- a/salt/runners/cloud.py +++ b/salt/runners/cloud.py @@ -6,15 +6,14 @@ This runner wraps the functionality of salt cloud making salt cloud routines available to all internal apis via the runner system ''' +from __future__ import absolute_import # Import python libs -from __future__ import absolute_import import logging import os # Import Salt libs import salt.cloud -from salt.exceptions import SaltCloudConfigError # Get logging started log = logging.getLogger(__name__) @@ -130,12 +129,14 @@ def destroy(instances): return info -def action(*args, **kwargs): +def action(func=None, + cloudmap=None, + instances=None, + provider=None, + instance=None, + **kwargs): ''' - Execute a single action on the given map/provider/instance. - - Returns a dictionary of action info. If something goes wrong, - an empty dictionary will be returned. + Execute a single action on the given map/provider/instance CLI Example: @@ -144,17 +145,7 @@ def action(*args, **kwargs): salt-run cloud.actions start my-salt-vm ''' client = _get_client() - try: - info = client.action(args[0], - kwargs.get('cloudmap', None), - args[1:], - kwargs.get('provider', None), - kwargs.get('instance', None), - kwargs) - except SaltCloudConfigError as err: - log.error(err) - return {} - + info = client.action(func, cloudmap, instances, provider, instance, kwargs) return info diff --git a/salt/runners/fileserver.py b/salt/runners/fileserver.py index c6efe0221a3c..712200eabb43 100644 --- a/salt/runners/fileserver.py +++ b/salt/runners/fileserver.py @@ -41,7 +41,7 @@ def envs(backend=None, sources=False, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the fileserver.envs runner has ' 'been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -84,7 +84,7 @@ def file_list(saltenv='base', backend=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the fileserver.file_list runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -127,7 +127,7 @@ def symlink_list(saltenv='base', backend=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the fileserver.symlink_list ' 'runner has been deprecated. Please specify an outputter using ' '--out. See the output of \'salt-run -h\' for more information.' @@ -170,7 +170,7 @@ def dir_list(saltenv='base', backend=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the fileserver.dir_list runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -218,7 +218,7 @@ def empty_dir_list(saltenv='base', backend=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the fileserver.empty_dir_list ' 'runner has been deprecated. Please specify an outputter using ' '--out. See the output of \'salt-run -h\' for more information.' diff --git a/salt/runners/jobs.py b/salt/runners/jobs.py index c9c7084fc0c9..98025d64bdf7 100644 --- a/salt/runners/jobs.py +++ b/salt/runners/jobs.py @@ -75,7 +75,7 @@ def active(outputter=None, display_progress=False): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the jobs.active runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -162,7 +162,7 @@ def lookup_jid(jid, outputter = None else: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the jobs.lookup_jid runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -201,7 +201,7 @@ def list_job(jid, ext_source=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the jobs.list_job runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' @@ -398,7 +398,7 @@ def print_job(jid, ext_source=None, outputter=None): if outputter: salt.utils.warn_until( - 'Boron', + 'Carbon', 'The \'outputter\' argument to the jobs.print_job runner ' 'has been deprecated. Please specify an outputter using --out. ' 'See the output of \'salt-run -h\' for more information.' diff --git a/salt/runners/saltutil.py b/salt/runners/saltutil.py index 2b8dbccdbc0a..0fba15b95d09 100644 --- a/salt/runners/saltutil.py +++ b/salt/runners/saltutil.py @@ -2,7 +2,7 @@ ''' Sync custom types to the Master -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import @@ -17,8 +17,6 @@ def sync_all(saltenv='base'): ''' - .. versionadded:: Boron - Sync all custom types saltenv : base @@ -49,8 +47,6 @@ def sync_all(saltenv='base'): def sync_modules(saltenv='base'): ''' - .. versionadded:: Boron - Sync execution modules from ``salt://_modules`` to the master saltenv : base @@ -68,8 +64,6 @@ def sync_modules(saltenv='base'): def sync_states(saltenv='base'): ''' - .. versionadded:: Boron - Sync state modules from ``salt://_states`` to the master saltenv : base @@ -87,8 +81,6 @@ def sync_states(saltenv='base'): def sync_grains(saltenv='base'): ''' - .. versionadded:: Boron - Sync grains modules from ``salt://_grains`` to the master saltenv : base @@ -106,8 +98,6 @@ def sync_grains(saltenv='base'): def sync_renderers(saltenv='base'): ''' - .. versionadded:: Boron - Sync renderer modules from from ``salt://_renderers`` to the master saltenv : base @@ -125,8 +115,6 @@ def sync_renderers(saltenv='base'): def sync_returners(saltenv='base'): ''' - .. versionadded:: Boron - Sync returner modules from ``salt://_returners`` to the master saltenv : base @@ -144,8 +132,6 @@ def sync_returners(saltenv='base'): def sync_output(saltenv='base'): ''' - .. versionadded:: Boron - Sync output modules from ``salt://_output`` to the master saltenv : base @@ -163,8 +149,6 @@ def sync_output(saltenv='base'): def sync_proxymodules(saltenv='base'): ''' - .. versionadded:: Boron - Sync proxy modules from ``salt://_proxy`` to the master saltenv : base @@ -182,8 +166,6 @@ def sync_proxymodules(saltenv='base'): def sync_runners(saltenv='base'): ''' - .. versionadded:: Boron - Sync runners from ``salt://_runners`` to the master saltenv : base @@ -201,8 +183,6 @@ def sync_runners(saltenv='base'): def sync_wheel(saltenv='base'): ''' - .. versionadded:: Boron - Sync wheel modules from ``salt://_wheel`` to the master saltenv : base @@ -220,8 +200,6 @@ def sync_wheel(saltenv='base'): def sync_engines(saltenv='base'): ''' - .. versionadded:: Boron - Sync engines from ``salt://_engines`` to the master saltenv : base @@ -239,8 +217,6 @@ def sync_engines(saltenv='base'): def sync_queues(saltenv='base'): ''' - .. versionadded:: Boron - Sync queue modules from ``salt://_queues`` to the master saltenv : base diff --git a/salt/runners/spacewalk.py b/salt/runners/spacewalk.py index a1a0bce19e3a..1095e1f73564 100644 --- a/salt/runners/spacewalk.py +++ b/salt/runners/spacewalk.py @@ -3,7 +3,7 @@ Spacewalk Runner ================ -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Runner to interact with Spacewalk using Spacewalk API diff --git a/salt/runners/state.py b/salt/runners/state.py index 637cfbced7de..3f93044fb4c7 100644 --- a/salt/runners/state.py +++ b/salt/runners/state.py @@ -158,7 +158,7 @@ def event(tagmatch='*', :param pretty: Output the JSON all on a single line if ``False`` (useful for shell tools); pretty-print the JSON output if ``True``. :param node: Watch the minion-side or master-side event bus. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 CLI Examples: diff --git a/salt/sdb/consul.py b/salt/sdb/consul.py new file mode 100644 index 000000000000..4750164a7c69 --- /dev/null +++ b/salt/sdb/consul.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +''' +Consul sdb Module + +:maintainer: SaltStack +:maturity: New +:platform: all + +This module allows access to Consul using an ``sdb://`` URI + +Like all sdb modules, the Consul module requires a configuration profile to +be configured in either the minion or master configuration file. This profile +requires very little. For example: + +.. code-block:: yaml + myconsul: + driver: consul + host: 127.0.0.1 + port: 8500 + token: b6376760-a8bb-edd5-fcda-33bc13bfc556 + scheme: http + consistency: default + dc: dev + verify: True + +The ``driver`` refers to the Consul module, all other options are optional. +For option details see: http://python-consul.readthedocs.org/en/latest/#consul +''' +from __future__ import absolute_import + +from salt.exceptions import CommandExecutionError + +try: + import consul + HAS_CONSUL = True +except ImportError: + HAS_CONSUL = False + + +__func_alias__ = { + 'set_': 'set' +} + + +def set_(key, value, profile=None): + if not profile: + return False + + conn = get_conn(profile) + + return conn.kv.put(key, value) + + +def get(key, profile=None): + if not profile: + return False + + conn = get_conn(profile) + + _, result = conn.kv.get(key) + + return result['Value'] if result else None + + +def get_conn(profile): + ''' + Return a client object for accessing consul + ''' + params = {} + for key in ('host', 'port', 'token', 'scheme', 'consistency', 'dc', 'verify'): + if key in profile: + params[key] = profile[key] + + if HAS_CONSUL: + return consul.Consul(**params) + else: + raise CommandExecutionError( + '(unable to import consul, ' + 'module most likely not installed. PLease install python-consul)' + ) diff --git a/salt/serializers/configparser.py b/salt/serializers/configparser.py index 4176e28cf6f0..0b0b41678140 100644 --- a/salt/serializers/configparser.py +++ b/salt/serializers/configparser.py @@ -3,7 +3,7 @@ salt.serializers.configparser ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Implements a configparser serializer. ''' diff --git a/salt/serializers/python.py b/salt/serializers/python.py index 3c6568aea937..ef1ff2aa335c 100644 --- a/salt/serializers/python.py +++ b/salt/serializers/python.py @@ -3,7 +3,7 @@ salt.serializers.python ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Implements a Python serializer (via pprint.format) ''' diff --git a/salt/spm/pkgfiles/local.py b/salt/spm/pkgfiles/local.py index 80573f6ea400..5f35d9687035 100644 --- a/salt/spm/pkgfiles/local.py +++ b/salt/spm/pkgfiles/local.py @@ -106,6 +106,12 @@ def install_file(package, formula_tar, member, formula_def, conn=None): # Reactor files go into /srv/reactor/ out_path = __opts__['reactor_path'] + # This ensures that double directories (i.e., apache/apache/) don't + # get created + comps = member.path.split('/') + if len(comps) > 1 and comps[0] == comps[1]: + member.path = '/'.join(comps[1:]) + log.debug('Installing package file {0} to {1}'.format(member.name, out_path)) formula_tar.extract(member, out_path) diff --git a/salt/state.py b/salt/state.py index 13092b399149..682f1e1cdd0f 100644 --- a/salt/state.py +++ b/salt/state.py @@ -630,6 +630,7 @@ def __init__( jid=None, pillar_enc=None, proxy=None, + context=None, mocked=False, loader='states'): self.states_loader = loader @@ -650,7 +651,7 @@ def __init__( ) self._pillar_enc = pillar_enc self.opts['pillar'] = self._gather_pillar() - self.state_con = {} + self.state_con = context or {} self.load_modules(proxy=proxy) self.active = set() self.mod_init = set() @@ -3284,6 +3285,7 @@ def __init__( jid=None, pillar_enc=None, proxy=None, + context=None, mocked=False, loader='states'): self.opts = opts @@ -3295,6 +3297,7 @@ def __init__( jid, pillar_enc, proxy=proxy, + context=context, mocked=mocked, loader=loader) self.matcher = salt.minion.Matcher(self.opts) @@ -3365,10 +3368,10 @@ def __init__(self, master_opts, minion_opts, grains, id_, env=None): if isinstance(env, six.string_types): salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/states/alternatives.py b/salt/states/alternatives.py index ab40da45236b..44b99fdd5156 100644 --- a/salt/states/alternatives.py +++ b/salt/states/alternatives.py @@ -62,7 +62,7 @@ def install(name, link, path, priority): 'changes': {}, 'comment': ''} - isinstalled = __salt__['alternatives.check_exists'](name, path) + isinstalled = __salt__['alternatives.check_installed'](name, path) if not isinstalled: if __opts__['test']: ret['comment'] = ( diff --git a/salt/states/apache_conf.py b/salt/states/apache_conf.py index 4823b25958ea..de558f922861 100644 --- a/salt/states/apache_conf.py +++ b/salt/states/apache_conf.py @@ -2,7 +2,7 @@ ''' Manage Apache Confs -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Enable and disable apache confs. diff --git a/salt/states/apache_site.py b/salt/states/apache_site.py index 642454e0c34f..40abcf6ad5e2 100644 --- a/salt/states/apache_site.py +++ b/salt/states/apache_site.py @@ -2,7 +2,7 @@ ''' Manage Apache Sites -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Enable and disable apache sites. diff --git a/salt/states/archive.py b/salt/states/archive.py index 8298b791e8dd..97304629ba9e 100644 --- a/salt/states/archive.py +++ b/salt/states/archive.py @@ -7,6 +7,7 @@ # Import Python libs from __future__ import absolute_import +import re import os import logging import tarfile @@ -236,7 +237,7 @@ def extracted(name, filename = os.path.join(__opts__['cachedir'], 'files', __env__, - '{0}.{1}'.format(if_missing.replace('/', '_'), + '{0}.{1}'.format(re.sub('[:/\\\\]', '_', if_missing), archive_format)) if not os.path.exists(filename): if __opts__['test']: diff --git a/salt/states/augeas.py b/salt/states/augeas.py index 88038a8c06b1..c9374bf60fab 100644 --- a/salt/states/augeas.py +++ b/salt/states/augeas.py @@ -150,7 +150,7 @@ def change(name, context=None, changes=None, lens=None, See the `list of stock lenses `_ shipped with Augeas. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 load_path A list of directories that modules should be searched in. This is in diff --git a/salt/states/boto_cloudtrail.py b/salt/states/boto_cloudtrail.py index 1627d842cb3e..08f08986951a 100644 --- a/salt/states/boto_cloudtrail.py +++ b/salt/states/boto_cloudtrail.py @@ -3,7 +3,7 @@ Manage CloudTrail Objects ================= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Create and destroy CloudTrail objects. Be aware that this interacts with Amazon's services, and so may incur charges. @@ -212,7 +212,7 @@ def present(name, Name, region=region, key=key, keyid=keyid, profile=profile) if 'error' in _describe: ret['result'] = False - ret['comment'] = 'Failed to update trail: {0}.'.format(r['error']['message']) + ret['comment'] = 'Failed to update trail: {0}.'.format(_describe['error']['message']) ret['changes'] = {} return ret _describe = _describe.get('trail') diff --git a/salt/states/boto_ec2.py b/salt/states/boto_ec2.py index fee2587fd1b0..e03acfcae313 100644 --- a/salt/states/boto_ec2.py +++ b/salt/states/boto_ec2.py @@ -180,7 +180,7 @@ def eni_present( ''' Ensure the EC2 ENI exists. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name Name tag associated with the ENI. @@ -210,7 +210,7 @@ def eni_present( allocate_eip True/False - allocate and associate an EIP to the ENI - .. versionadded:: Boron + .. versionadded:: 2016.3.0 arecords A list of arecord dicts with attributes needed for the DNS add_record state. @@ -219,7 +219,7 @@ def eni_present( Other DNS modules can be called by specifying the provider keyword. By default, the private ENI IP address will be used, set 'public: True' in the arecord dict to use the ENI's public IP address - .. versionadded:: Boron + .. versionadded:: 2016.3.0 region Region to connect to. @@ -459,7 +459,7 @@ def eni_absent( ''' Ensure the EC2 ENI is absent. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name Name tag associated with the ENI. @@ -547,7 +547,7 @@ def snapshot_created(name, ami_name, instance_name, wait_until_available=True, w ''' Create a snapshot from the given instance - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, @@ -725,7 +725,7 @@ def instance_present(name, instance_name=None, instance_id=None, image_id=None, (variable) - A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, @@ -845,7 +845,7 @@ def instance_absent(name, instance_name=None, instance_id=None, (variable) - A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ### TODO - Implement 'force' option?? Would automagically turn off ### 'disableApiTermination', as needed before trying to delete. diff --git a/salt/states/boto_elb.py b/salt/states/boto_elb.py index 51f8a93bf74c..5fa10085ef0a 100644 --- a/salt/states/boto_elb.py +++ b/salt/states/boto_elb.py @@ -217,7 +217,7 @@ Tags can also be set: -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/boto_iam.py b/salt/states/boto_iam.py index 15c53461aac5..3f4b0495e1cf 100644 --- a/salt/states/boto_iam.py +++ b/salt/states/boto_iam.py @@ -167,12 +167,12 @@ def user_absent(name, delete_keys=True, delete_mfa_devices=True, delete_profile= delete_mfa_devices (bool) Delete all mfa devices from user. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 delete_profile (bool) Delete profile from user. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 region (string) Region to connect to. diff --git a/salt/states/boto_iot.py b/salt/states/boto_iot.py index 7792e0a4f798..480cee0fb519 100644 --- a/salt/states/boto_iot.py +++ b/salt/states/boto_iot.py @@ -3,7 +3,7 @@ Manage IoT Objects ================= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Create and destroy IoT objects. Be aware that this interacts with Amazon's services, and so may incur charges. diff --git a/salt/states/boto_lambda.py b/salt/states/boto_lambda.py index 46e8cf4c9952..0607ff8f7989 100644 --- a/salt/states/boto_lambda.py +++ b/salt/states/boto_lambda.py @@ -3,7 +3,7 @@ Manage Lambda Functions ================= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Create and destroy Lambda Functions. Be aware that this interacts with Amazon's services, and so may incur charges. diff --git a/salt/states/boto_s3_bucket.py b/salt/states/boto_s3_bucket.py index 3acc3d8da428..c7de21d0e4bc 100644 --- a/salt/states/boto_s3_bucket.py +++ b/salt/states/boto_s3_bucket.py @@ -3,7 +3,7 @@ Manage S3 Buckets ================= -.. versionadded:: Boron +.. versionadded:: 2016.3.0 Create and destroy S3 buckets. Be aware that this interacts with Amazon's services, and so may incur charges. diff --git a/salt/states/boto_secgroup.py b/salt/states/boto_secgroup.py index b5ef89d8a202..a0b3cee71759 100644 --- a/salt/states/boto_secgroup.py +++ b/salt/states/boto_secgroup.py @@ -138,7 +138,7 @@ def present( vpc_name The name of the VPC to create the security group in, if any. Exlusive with vpc_id. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. versionadded:: 2015.8.2 @@ -168,7 +168,7 @@ def present( tags List of key:value pairs of tags to set on the security group - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, 'comment': '', 'changes': {}} _ret = _security_group_present(name, description, vpc_id=vpc_id, @@ -560,7 +560,7 @@ def absent( vpc_name The name of the VPC to remove the security group from, if any. Exclusive with vpc_name. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 region Region to connect to. @@ -575,7 +575,7 @@ def absent( A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, 'comment': '', 'changes': {}} diff --git a/salt/states/boto_vpc.py b/salt/states/boto_vpc.py index 93590d5a9250..73ca50f66dac 100644 --- a/salt/states/boto_vpc.py +++ b/salt/states/boto_vpc.py @@ -306,7 +306,7 @@ def dhcp_options_present(name, dhcp_options_id=None, vpc_name=None, vpc_id=None, A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, @@ -392,7 +392,7 @@ def dhcp_options_absent(name=None, dhcp_options_id=None, region=None, key=None, A dict with region, key and keyid, or a pillar key (string) that contains a dict with region, key and keyid. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, diff --git a/salt/states/chocolatey.py b/salt/states/chocolatey.py index c0b309615387..7f47fa7474d8 100644 --- a/salt/states/chocolatey.py +++ b/salt/states/chocolatey.py @@ -2,7 +2,7 @@ ''' Manage Chocolatey package installs -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' # Import Python libs diff --git a/salt/states/cmd.py b/salt/states/cmd.py index 9d15bd3d0756..65d4528d43f9 100644 --- a/salt/states/cmd.py +++ b/salt/states/cmd.py @@ -991,12 +991,12 @@ def script(name, This is experimental. context - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Overrides default context variables passed to the template. defaults - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Default context passed to the template. diff --git a/salt/states/cron.py b/salt/states/cron.py index 3f5419cc55c0..59ca2ffc6428 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -282,7 +282,7 @@ def present(name, The cron job is set commented (prefixed with ``#DISABLED#``). Defaults to False. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 identifier Custom-defined identifier for tracking the cron line for future crontab diff --git a/salt/states/file.py b/salt/states/file.py index c9e7ce2e1129..b70328f67ee3 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -746,11 +746,17 @@ def _validate_str_list(arg): ensure ``arg`` is a list of strings ''' if isinstance(arg, six.string_types): - return [arg] + ret = [arg] elif isinstance(arg, Iterable) and not isinstance(arg, Mapping): - return [str(item) for item in arg] + ret = [] + for item in arg: + if isinstance(item, six.string_types): + ret.append(item) + else: + ret.append(str(item)) else: - return [str(arg)] + ret = [str(arg)] + return ret def symlink( @@ -764,7 +770,7 @@ def symlink( mode=None, **kwargs): ''' - Create a symlink + Create a symbolic link (symlink, soft link) If the file already exists and is a symlink pointing to any location other than the specified target, the symlink will be replaced. If the symlink is @@ -1437,67 +1443,59 @@ def managed(name, ) # Use this below to avoid multiple '\0' checks and save some CPU cycles - contents_are_binary = False - if contents_pillar: - contents = __salt__['pillar.get'](contents_pillar, __NOT_FOUND) - if contents is __NOT_FOUND: + if contents_pillar is not None: + use_contents = __salt__['pillar.get'](contents_pillar, __NOT_FOUND) + if use_contents is __NOT_FOUND: return _error( ret, 'Pillar {0} does not exist'.format(contents_pillar) ) - try: - if '\0' in contents: - contents_are_binary = True - except TypeError: - contents = str(contents) - if not allow_empty and not contents: - return _error( - ret, - 'contents_pillar {0} results in empty contents' - .format(contents_pillar) - ) - elif contents_grains: - contents = __salt__['grains.get'](contents_grains, __NOT_FOUND) - if contents is __NOT_FOUND: + elif contents_grains is not None: + use_contents = __salt__['grains.get'](contents_grains, __NOT_FOUND) + if use_contents is __NOT_FOUND: return _error( ret, 'Grain {0} does not exist'.format(contents_grains) ) - try: - if '\0' in contents: - contents_are_binary = True - except TypeError: - contents = str(contents) - if not allow_empty and not contents: + + elif contents is not None: + use_contents = contents + + else: + use_contents = None + + if use_contents is not None: + if not allow_empty and not use_contents: + if contents_pillar: + contents_id = 'contents_pillar {0}'.format(contents_pillar) + elif contents_grains: + contents_id = 'contents_grains {0}'.format(contents_grains) + else: + contents_id = '\'contents\'' return _error( ret, - 'contents_grains {0} results in empty contents' - .format(contents_grains) + '{0} value would result in empty contents. Set allow_empty ' + 'to True to allow the managed file to be empty.' + .format(contents_id) ) - elif contents: - try: - if '\0' in contents: - contents_are_binary = True - except TypeError: - pass - if not contents_are_binary: - validated_contents = _validate_str_list(contents) + contents_are_binary = \ + isinstance(use_contents, six.string_types) and '\0' in use_contents + if contents_are_binary: + contents = use_contents + else: + validated_contents = _validate_str_list(use_contents) if not validated_contents: return _error( ret, - '\'contents\' is not a string or list of strings' + 'Contents specified by contents/contents_pillar/' + 'contents_grains is not a string or list of strings, and ' + 'is not binary data. SLS is likely malformed.' ) contents = os.linesep.join(validated_contents) - - # If either contents_pillar or contents_grains were used, the contents - # variable now contains the value loaded from pillar/grains. - if contents \ - and not contents_are_binary \ - and contents_newline \ - and not contents.endswith(os.linesep): - contents += os.linesep + if contents_newline and not contents.endswith(os.linesep): + contents += os.linesep # Make sure that leading zeros stripped by YAML loader are added back mode = __salt__['config.manage_mode'](mode) @@ -2536,14 +2534,97 @@ def process_symlinks(filenames, symlinks): def line(name, content, match=None, mode=None, location=None, before=None, after=None, show_changes=True, backup=False, - quiet=False, indent=True): + quiet=False, indent=True, create=False, user=None, + group=None, file_mode=None): ''' Line-based editing of a file. .. versionadded:: 2015.8.0 - Params are identical to the remote execution function - :mod:`file.line `. + Edit a line in the configuration file. + + name: + Filesystem path to the file to be edited. + + content: + Content of the line. + + match: + Match the target line for an action by + a fragment of a string or regular expression. + + mode: + Ensure + If line does not exist, it will be added. + + Replace + If line already exist, it will be replaced. + + Delete + Delete the line, once found. + + Insert + Insert a line. + + location: + start + Place the content at the beginning of the file. + + end + Place the content at the end of the file. + + before: + Regular expression or an exact case-sensitive fragment of the string. + + after: + Regular expression or an exact case-sensitive fragment of the string. + + show_changes + Output a unified diff of the old file and the new file. + If ``False`` return a boolean if any changes were made. + Default is ``True`` + + .. note:: + + Using this option will store two copies of the file in-memory + (the original version and the edited version) in order to generate the diff. + + backup + Create a backup of the original file with the extension: + "Year-Month-Day-Hour-Minutes-Seconds". + + quiet + Do not raise any exceptions. E.g. ignore the fact that the file that is + tried to be edited does not exist and nothing really happened. + + indent + Keep indentation with the previous line. + + If an equal sign (``=``) appears in an argument to a Salt command, it is + interpreted as a keyword argument in the format of ``key=val``. That + processing can be bypassed in order to pass an equal sign through to the + remote shell command by manually specifying the kwarg: + + create + Create an empty file if doesn't exists. + + user + The user to own the file, this defaults to the user salt is running as + on the minion. + + .. versionadded:: Carbon + + group + The group ownership set for the file, this defaults to the group salt + is running as on the minion On Windows, this is ignored. + + .. versionadded:: Carbon + + file_mode + The permissions to set on this file, aka 644, 0775, 4664. Not supported + on Windows. + + .. versionadded:: Carbon .. code-block: yaml @@ -2562,6 +2643,9 @@ def line(name, content, match=None, mode=None, location=None, if not name: return _error(ret, 'Must provide name to file.line') + if create and not os.path.isfile(name): + managed(name, create=create, user=user, group=group, mode=file_mode) + check_res, check_msg = _check_file(name) if not check_res: return _error(ret, check_msg) @@ -4736,7 +4820,7 @@ def decode(name, ''' Decode an encoded file and write it to disk - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name Path of the file to be written. diff --git a/salt/states/firewall.py b/salt/states/firewall.py index b6da25b58912..83b01373178e 100644 --- a/salt/states/firewall.py +++ b/salt/states/firewall.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ''' State to check firewall configurations -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' diff --git a/salt/states/firewalld.py b/salt/states/firewalld.py index 4c64c401683b..937c0e8fa893 100644 --- a/salt/states/firewalld.py +++ b/salt/states/firewalld.py @@ -263,7 +263,7 @@ def bind(name, ''' Ensure a zone is bound to specific interfaces or sources. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. note:: diff --git a/salt/states/git.py b/salt/states/git.py index 52c4adb0a99c..257559fb8814 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -126,7 +126,7 @@ def _fail(ret, msg, comments=None): def _failed_fetch(ret, exc, comments=None): msg = ( 'Fetch failed. Set \'force_fetch\' to True to force the fetch if the ' - 'failure was due to it being non-fast-forward. Output of the fetch ' + 'failure was due to not being able to fast-forward. Output of the fetch ' 'command follows:\n\n{0}'.format(_strip_exc(exc)) ) return _fail(ret, msg, comments) @@ -325,6 +325,13 @@ def latest(name, invoked from the minion using ``salt-call``, to prevent blocking waiting for user input. +<<<<<<< HEAD +======= + Key can be specified as a SaltStack file server URL, eg. salt://location/identity_file + + .. versionadded:: 2016.3.0 + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b https_user HTTP Basic Auth username for HTTPS (only) clones @@ -370,6 +377,21 @@ def latest(name, - pkg: git - ssh_known_hosts: gitlab.example.com +<<<<<<< HEAD +======= + git-website-staging: + git.latest: + - name: ssh://git@gitlab.example.com:user/website.git + - rev: gh-pages + - target: /usr/share/nginx/staging + - identity: salt://website/id_rsa + - require: + - pkg: git + - ssh_known_hosts: gitlab.example.com + + .. versionadded:: 2016.3.0 + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b git-website-prod: git.latest: - name: git@gitlab.example.com:user/website.git @@ -1598,6 +1620,479 @@ def present(name, return ret +<<<<<<< HEAD +======= +def detached(name, + ref, + target=None, + remote='origin', + user=None, + force_clone=False, + force_checkout=False, + fetch_remote=True, + hard_reset=False, + submodules=False, + identity=None, + https_user=None, + https_pass=None, + onlyif=False, + unless=False, + **kwargs): + ''' + .. versionadded:: 2016.3.0 + + Make sure a repository is cloned to the given target directory and is + a detached HEAD checkout of the commit ID resolved from ``ref``. + + name + Address of the remote repository. + + ref + The branch, tag, or commit ID to checkout after clone. + If a branch or tag is specified it will be resolved to a commit ID + and checked out. + + target + Name of the target directory where repository is about to be cloned. + + remote : origin + Git remote to use. If this state needs to clone the repo, it will clone + it using this value as the initial remote name. If the repository + already exists, and a remote by this name is not present, one will be + added. + + user + User under which to run git commands. By default, commands are run by + the user under which the minion is running. + + force_clone : False + If the ``target`` directory exists and is not a git repository, then + this state will fail. Set this argument to ``True`` to remove the + contents of the target directory and clone the repo into it. + + force_checkout : False + When checking out the revision ID, the state will fail if there are + unwritten changes. Set this argument to ``True`` to discard unwritten + changes when checking out. + + fetch_remote : True + If ``False`` a fetch will not be performed and only local refs + will be reachable. + + hard_reset : False + If ``True`` a hard reset will be performed before the checkout and any + uncommitted modifications to the working directory will be discarded. + Untracked files will remain in place. + + .. note:: + Changes resulting from a hard reset will not trigger requisites. + + submodules : False + Update submodules + + identity + A path on the minion server to a private key to use over SSH + Key can be specified as a SaltStack file server URL + eg. salt://location/identity_file + + https_user + HTTP Basic Auth username for HTTPS (only) clones + + https_pass + HTTP Basic Auth password for HTTPS (only) clones + + onlyif + A command to run as a check, run the named command only if the command + passed to the ``onlyif`` option returns true + + unless + A command to run as a check, only run the named command if the command + passed to the ``unless`` option returns false + + ''' + + ret = {'name': name, 'result': True, 'comment': '', 'changes': {}} + + kwargs = salt.utils.clean_kwargs(**kwargs) + if kwargs: + return _fail( + ret, + salt.utils.invalid_kwargs(kwargs, raise_exc=False) + ) + + if not ref: + return _fail( + ret, + '\'{0}\' is not a valid value for the \'ref\' argument'.format(ref) + ) + + if not target: + return _fail( + ret, + '\'{0}\' is not a valid value for the \'target\' argument'.format(ref) + ) + + # Ensure that certain arguments are strings to ensure that comparisons work + if not isinstance(ref, six.string_types): + ref = str(ref) + if target is not None: + if not isinstance(target, six.string_types): + target = str(target) + if not os.path.isabs(target): + return _fail( + ret, + 'Target \'{0}\' is not an absolute path'.format(target) + ) + if user is not None and not isinstance(user, six.string_types): + user = str(user) + if remote is not None and not isinstance(remote, six.string_types): + remote = str(remote) + if identity is not None: + if isinstance(identity, six.string_types): + identity = [identity] + elif not isinstance(identity, list): + return _fail(ret, 'Identity must be either a list or a string') + for ident_path in identity: + if 'salt://' in ident_path: + try: + ident_path = __salt__['cp.cache_file'](ident_path) + except IOError as exc: + log.error( + 'Failed to cache {0}: {1}'.format(ident_path, exc) + ) + return _fail( + ret, + 'Identity \'{0}\' does not exist.'.format( + ident_path + ) + ) + if not os.path.isabs(ident_path): + return _fail( + ret, + 'Identity \'{0}\' is not an absolute path'.format( + ident_path + ) + ) + if https_user is not None and not isinstance(https_user, six.string_types): + https_user = str(https_user) + if https_pass is not None and not isinstance(https_pass, six.string_types): + https_pass = str(https_pass) + + if os.path.isfile(target): + return _fail( + ret, + 'Target \'{0}\' exists and is a regular file, cannot proceed' + .format(target) + ) + + try: + desired_fetch_url = salt.utils.url.add_http_basic_auth( + name, + https_user, + https_pass, + https_only=True + ) + except ValueError as exc: + return _fail(ret, exc.__str__()) + + redacted_fetch_url = salt.utils.url.redact_http_basic_auth(desired_fetch_url) + + # Check if onlyif or unless conditions match + run_check_cmd_kwargs = {'runas': user} + if 'shell' in __grains__: + run_check_cmd_kwargs['shell'] = __grains__['shell'] + cret = mod_run_check( + run_check_cmd_kwargs, onlyif, unless + ) + if isinstance(cret, dict): + ret.update(cret) + return ret + + # Determine if supplied ref is a hash + remote_ref_type = 'ref' + if len(ref) <= 40 \ + and all(x in string.hexdigits for x in ref): + ref = ref.lower() + remote_ref_type = 'hash' + + comments = [] + hash_exists_locally = False + local_commit_id = None + + gitdir = os.path.join(target, '.git') + if os.path.isdir(gitdir) or __salt__['git.is_worktree'](target): + # Target directory is a git repository or git worktree + + local_commit_id = _get_local_rev_and_branch(target, user)[0] + + if remote_ref_type is 'hash' and __salt__['git.describe'](ref): + # The ref is a hash and it exists locally so skip to checkout + hash_exists_locally = True + else: + # Check that remote is present and set to correct url + remotes = __salt__['git.remotes'](target, + user=user, + redact_auth=False) + + if remote in remotes and name in remotes[remote]['fetch']: + pass + else: + # The fetch_url for the desired remote does not match the + # specified URL (or the remote does not exist), so set the + # remote URL. + current_fetch_url = None + if remote in remotes: + current_fetch_url = remotes[remote]['fetch'] + + if __opts__['test']: + return _neutral_test( + ret, + 'Remote {0} would be set to {1}'.format( + remote, name + ) + ) + + __salt__['git.remote_set'](target, + url=name, + remote=remote, + user=user, + https_user=https_user, + https_pass=https_pass) + comments.append( + 'Remote {0} updated from \'{1}\' to \'{2}\''.format( + remote, + str(current_fetch_url), + name + ) + ) + + else: + # Clone repository + if os.path.isdir(target): + if force_clone: + # Clone is required, and target directory exists, but the + # ``force`` option is enabled, so we need to clear out its + # contents to proceed. + if __opts__['test']: + return _neutral_test( + ret, + 'Target directory {0} exists. Since force_clone=True, ' + 'the contents of {0} would be deleted, and {1} would ' + 'be cloned into this directory.'.format(target, name) + ) + log.debug( + 'Removing contents of {0} to clone repository {1} in its ' + 'place (force_clone=True set in git.detached state)' + .format(target, name) + ) + try: + if os.path.islink(target): + os.unlink(target) + else: + salt.utils.rm_rf(target) + except OSError as exc: + return _fail( + ret, + 'Unable to remove {0}: {1}'.format(target, exc), + comments + ) + else: + ret['changes']['forced clone'] = True + elif os.listdir(target): + # Clone is required, but target dir exists and is non-empty. We + # can't proceed. + return _fail( + ret, + 'Target \'{0}\' exists, is non-empty and is not a git ' + 'repository. Set the \'force_clone\' option to True to ' + 'remove this directory\'s contents and proceed with ' + 'cloning the remote repository'.format(target) + ) + + log.debug( + 'Target {0} is not found, \'git clone\' is required'.format(target) + ) + if __opts__['test']: + return _neutral_test( + ret, + 'Repository {0} would be cloned to {1}'.format( + name, target + ) + ) + try: + clone_opts = ['--no-checkout'] + if remote != 'origin': + clone_opts.extend(['--origin', remote]) + + __salt__['git.clone'](target, + name, + user=user, + opts=clone_opts, + identity=identity, + https_user=https_user, + https_pass=https_pass) + comments.append( + '{0} cloned to {1}'.format( + name, + target + ) + ) + + except Exception as exc: + log.error( + 'Unexpected exception in git.detached state', + exc_info=True + ) + if isinstance(exc, CommandExecutionError): + msg = _strip_exc(exc) + else: + msg = str(exc) + return _fail(ret, msg, comments) + + # Repository exists and is ready for fetch/checkout + refspecs = [ + 'refs/heads/*:refs/remotes/{0}/*'.format(remote), + '+refs/tags/*:refs/tags/*' + ] + if hash_exists_locally or fetch_remote is False: + pass + else: + # Fetch refs from remote + if __opts__['test']: + return _neutral_test( + ret, + 'Repository remote {0} would be fetched'.format( + remote + ) + ) + try: + fetch_changes = __salt__['git.fetch']( + target, + remote=remote, + force=True, + refspecs=refspecs, + user=user, + identity=identity) + except CommandExecutionError as exc: + msg = 'Fetch failed' + msg += ':\n\n' + str(exc) + return _fail(ret, msg, comments) + else: + if fetch_changes: + comments.append( + 'Remote {0} was fetched, resulting in updated ' + 'refs'.format(remote) + ) + + #get refs and checkout + checkout_commit_id = '' + if remote_ref_type is 'hash': + if __salt__['git.describe'](ref): + checkout_commit_id = ref + else: + return _fail( + ret, + 'Ref does not exist: {0}'.format(ref) + ) + else: + try: + all_remote_refs = __salt__['git.remote_refs']( + target, + user=user, + identity=identity, + https_user=https_user, + https_pass=https_pass, + ignore_retcode=False) + + if 'refs/remotes/'+remote+'/'+ref in all_remote_refs: + checkout_commit_id = all_remote_refs['refs/remotes/'+remote+'/'+ref] + elif 'refs/tags/'+ref in all_remote_refs: + checkout_commit_id = all_remote_refs['refs/tags/'+ref] + else: + return _fail( + ret, + 'Ref {0} does not exist'.format(ref) + ) + + except CommandExecutionError as exc: + return _fail( + ret, + 'Failed to list refs for {0}: {1}'.format(remote, _strip_exc(exc)) + ) + + if hard_reset: + if __opts__['test']: + return _neutral_test( + ret, + 'Hard reset to HEAD would be performed on {0}'.format( + target + ) + ) + __salt__['git.reset']( + target, + opts=['--hard', 'HEAD'], + user=user + ) + comments.append( + 'Repository was reset to HEAD before checking out ref' + ) + + # TODO: implement clean function for git module and add clean flag + + if checkout_commit_id == local_commit_id: + new_rev = None + else: + if __opts__['test']: + ret['changes']['HEAD'] = {'old': local_commit_id, 'new': checkout_commit_id} + return _neutral_test( + ret, + 'Commit ID {0} would be checked out at {1}'.format( + checkout_commit_id, + target + ) + ) + __salt__['git.checkout'](target, + checkout_commit_id, + force=force_checkout, + user=user) + comments.append( + 'Commit ID {0} was checked out at {1}'.format( + checkout_commit_id, + target + ) + ) + + try: + new_rev = __salt__['git.revision']( + cwd=target, + user=user, + ignore_retcode=True) + except CommandExecutionError: + new_rev = None + + if submodules: + __salt__['git.submodule'](target, + 'update', + opts=['--init', '--recursive'], + user=user, + identity=identity) + comments.append( + 'Submodules were updated' + ) + + if new_rev is not None: + ret['changes']['HEAD'] = {'old': local_commit_id, 'new': new_rev} + else: + comments.append("Already checked out at correct revision") + + msg = _format_comments(comments) + log.info(msg) + ret['comment'] = msg + + return ret + + +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b def config_unset(name, value_regex=None, repo=None, diff --git a/salt/states/github.py b/salt/states/github.py index a7d4e1aacec5..acc7b47d1a84 100644 --- a/salt/states/github.py +++ b/salt/states/github.py @@ -2,7 +2,7 @@ ''' Github User State Module -.. versionadded:: Boron. +.. versionadded:: 2016.3.0. This state is used to ensure presence of users in the Organization. diff --git a/salt/states/glance.py b/salt/states/glance.py index 8bb14ea4c8af..8176c03240ef 100644 --- a/salt/states/glance.py +++ b/salt/states/glance.py @@ -9,7 +9,6 @@ import time # Import salt libs -from salt.utils import warn_until # Import OpenStack libs try: @@ -46,12 +45,6 @@ def _find_image(name): return False, 'glanceclient: Unauthorized' log.debug('Got images_dict: {0}'.format(images_dict)) - warn_until('Boron', 'Starting with Boron ' - '\'glance.image_list\' is not supposed to return ' - 'the images wrapped in a separate dict anymore.') - if len(images_dict) == 1 and 'images' in images_dict: - images_dict = images_dict['images'] - # I /think/ this will still work when glance.image_list # starts returning a list instead of a dictionary... if len(images_dict) == 0: @@ -123,12 +116,6 @@ def image_present(name, visibility='public', protected=None, image = __salt__['glance.image_create'](name=name, protected=protected, visibility=visibility, location=location) - # See Salt issue #24568 - warn_until('Boron', 'Starting with Boron ' - '\'glance.image_create\' is not supposed to return ' - 'the image wrapped in a dict anymore.') - if len(image.keys()) == 1: - image = image.values()[0] log.debug('Created new image:\n{0}'.format(image)) ret['changes'] = { name: @@ -158,26 +145,12 @@ def image_present(name, visibility='public', protected=None, ret['comment'] += 'Created image {0} '.format( name) + ' vanished:\n' + msg return ret - elif len(image.keys()) == 1: - # See Salt issue #24568 - warn_until('Boron', 'Starting with Boron ' - '\'_find_image()\' is not supposed to return ' - 'the image wrapped in a dict anymore.') - image = image.values()[0] if timer <= 0 and image['status'] not in acceptable: ret['result'] = False ret['comment'] += 'Image didn\'t reach an acceptable '+\ 'state ({0}) before timeout:\n'.format(acceptable)+\ '\tLast status was "{0}".\n'.format(image['status']) - # See Salt issue #24568 - warn_until('Boron', 'Starting with Boron ' - '\'_find_image()\' is not supposed to return ' - 'the image wrapped in a dict anymore.') - if len(image.keys()) == 1: - image = image.values()[0] - # ret[comment] += - # There's no image but where would I get one?? elif location is None: if __opts__['test']: @@ -200,12 +173,6 @@ def image_present(name, visibility='public', protected=None, if not __opts__['test']: image = __salt__['glance.image_update']( id=image['id'], visibility=visibility) - # See Salt issue #24568 - warn_until('Boron', 'Starting with Boron ' - '\'glance.image_update\' is not supposed to return ' - 'the image wrapped in a dict anymore.') - if len(image.keys()) == 1: - image = image.values()[0] # Check if image_update() worked: if image['visibility'] != visibility: if not __opts__['test']: @@ -243,11 +210,6 @@ def image_present(name, visibility='public', protected=None, if 'checksum' not in image: # Refresh our info about the image image = __salt__['glance.image_show'](image['id']) - warn_until('Boron', 'Starting with Boron ' - '\'glance.image_show\' is not supposed to return ' - 'the image wrapped in a dict anymore.') - if len(image.keys()) == 1: - image = image.values()[0] if 'checksum' not in image: if not __opts__['test']: ret['result'] = False diff --git a/salt/states/glusterfs.py b/salt/states/glusterfs.py index fadbce823f0f..bb9887253726 100644 --- a/salt/states/glusterfs.py +++ b/salt/states/glusterfs.py @@ -65,7 +65,10 @@ def peered(name): ret['result'] = False return ret - ret['comment'] = __salt__['glusterfs.peer'](name) + if 'output' in __salt__['glusterfs.peer'](name): + ret['comment'] = __salt__['glusterfs.peer'](name)['output'] + else: + ret['comment'] = '' newpeers = __salt__['glusterfs.list_peers']() #if newpeers was null, we know something didn't work. diff --git a/salt/states/gpg.py b/salt/states/gpg.py index d83e172e83ce..6cf89bcfee57 100644 --- a/salt/states/gpg.py +++ b/salt/states/gpg.py @@ -3,7 +3,7 @@ Management of the GPG keychains ============================== -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' diff --git a/salt/states/grafana_dashboard.py b/salt/states/grafana_dashboard.py index 027790827497..779b257f37b5 100644 --- a/salt/states/grafana_dashboard.py +++ b/salt/states/grafana_dashboard.py @@ -2,7 +2,7 @@ ''' Manage Grafana v2.0 Dashboards -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/grafana_datasource.py b/salt/states/grafana_datasource.py index 3cbd55bc2d84..9d0b4ebdddbe 100644 --- a/salt/states/grafana_datasource.py +++ b/salt/states/grafana_datasource.py @@ -2,7 +2,7 @@ ''' Manage Grafana v2.0 data sources -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/grains.py b/salt/states/grains.py index 95d01af7578a..9e5a83f15e31 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -19,7 +19,7 @@ def present(name, value, delimiter=DEFAULT_TARGET_DELIM, force=False): ''' Ensure that a grain is set - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 name The grain name @@ -30,11 +30,11 @@ def present(name, value, delimiter=DEFAULT_TARGET_DELIM, force=False): :param force: If force is True, the existing grain will be overwritten regardless of its existing or provided value type. Defaults to False - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param delimiter: A delimiter different from the default can be provided. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 It is now capable to set a grain to a complex value (ie. lists and dicts) and supports nested grains as well. @@ -108,7 +108,7 @@ def list_present(name, value, delimiter=DEFAULT_TARGET_DELIM): :param delimiter: A delimiter different from the default ``:`` can be provided. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 The grain should be `list type `_ @@ -191,7 +191,7 @@ def list_absent(name, value, delimiter=DEFAULT_TARGET_DELIM): :param delimiter: A delimiter different from the default ``:`` can be provided. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 The grain should be `list type `_ @@ -261,13 +261,13 @@ def absent(name, :param force: If force is True, the existing grain will be overwritten regardless of its existing or provided value type. Defaults to False - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param delimiter: A delimiter different from the default can be provided. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 This state now support nested grains and complex values. It is also more conservative: if a grain has a value that is a list or a dict, it will not be removed unless the `force` parameter is True. @@ -355,7 +355,7 @@ def append(name, value, convert=False, :param delimiter: A delimiter different from the default can be provided. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/host.py b/salt/states/host.py index 09a0dff6a4e3..1c038d36fff8 100644 --- a/salt/states/host.py +++ b/salt/states/host.py @@ -149,7 +149,7 @@ def only(name, hostnames): Ensure that only the given hostnames are associated with the given IP address. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 name The IP address to associate with the given hostnames. diff --git a/salt/states/infoblox.py b/salt/states/infoblox.py index f7842b9b7390..38e9e59f21ca 100644 --- a/salt/states/infoblox.py +++ b/salt/states/infoblox.py @@ -4,7 +4,7 @@ ensures a record is either present or absent in an Infoblox DNS system -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import diff --git a/salt/states/jenkins.py b/salt/states/jenkins.py index a3356ffb96ed..b45e65e19be2 100644 --- a/salt/states/jenkins.py +++ b/salt/states/jenkins.py @@ -3,7 +3,7 @@ Management of Jenkins ============================== -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' diff --git a/salt/states/k8s.py b/salt/states/k8s.py index 744954b23349..879843be174c 100644 --- a/salt/states/k8s.py +++ b/salt/states/k8s.py @@ -2,7 +2,7 @@ ''' Manage Kubernetes -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/kmod.py b/salt/states/kmod.py index 7b06b2472f53..79306e1b5092 100644 --- a/salt/states/kmod.py +++ b/salt/states/kmod.py @@ -66,7 +66,7 @@ def present(name, persist=False, mods=None): ``name`` argument, although still required, is not used, and becomes a placeholder - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if not isinstance(mods, (list, tuple)): mods = [name] @@ -170,7 +170,7 @@ def absent(name, persist=False, comment=True, mods=None): the ``name`` argument, although still required, is not used, and becomes a placeholder - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' if not isinstance(mods, (list, tuple)): mods = [name] diff --git a/salt/states/ldap.py b/salt/states/ldap.py index 90a06f273afe..39edc779a8cf 100644 --- a/salt/states/ldap.py +++ b/salt/states/ldap.py @@ -3,7 +3,7 @@ Manage entries in an LDAP database ================================== -.. versionadded:: Boron +.. versionadded:: 2016.3.0 The ``states.ldap`` state module allows you to manage LDAP entries and their attributes. diff --git a/salt/states/lxc.py b/salt/states/lxc.py index 3b4c7d8c8120..341805111605 100644 --- a/salt/states/lxc.py +++ b/salt/states/lxc.py @@ -641,7 +641,7 @@ def created(name, **kwargs): Use :mod:`lxc.present ` ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'The lxc.created state has been renamed to lxc.present, please use ' 'lxc.present' ) @@ -654,7 +654,7 @@ def started(name, path=None, restart=False): Use :mod:`lxc.running ` ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'The lxc.started state has been renamed to lxc.running, please use ' 'lxc.running' ) @@ -673,7 +673,7 @@ def cloned(name, Use :mod:`lxc.present ` ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'The lxc.cloned state has been merged into the lxc.present state. ' 'Please update your states to use lxc.present, with the ' '\'clone_from\' argument set to the name of the clone source.' @@ -744,7 +744,7 @@ def edited_conf(name, lxc_conf=None, lxc_conf_unset=None): - lxc.utsname ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'This state is unsuitable for setting parameters that appear more ' 'than once in an LXC config file, or parameters which must appear in ' 'a certain order (such as when configuring more than one network ' diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 9beaa4ec00f2..80033d6890d9 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -883,7 +883,7 @@ def installed( reinstalled. This is supported in both :mod:`apt ` and :mod:`yumpkg `. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Example: @@ -1951,7 +1951,7 @@ def group_installed(name, skip=None, include=None, **kwargs): - include: - haproxy - .. versionchanged:: Boron + .. versionchanged:: 2016.3.0 This option can no longer be passed as a comma-separated list, it must now be passed as a list (as shown in the above example). diff --git a/salt/states/pkgrepo.py b/salt/states/pkgrepo.py index 7ac1b3df5980..71740bd4f591 100644 --- a/salt/states/pkgrepo.py +++ b/salt/states/pkgrepo.py @@ -268,7 +268,7 @@ def managed(name, **kwargs): if kwargs.pop('enabled', None): kwargs['disabled'] = False salt.utils.warn_until( - 'Boron', + 'Carbon', 'The `enabled` argument has been deprecated in favor of ' '`disabled`.' ) diff --git a/salt/states/postgres_initdb.py b/salt/states/postgres_initdb.py index 95f90e0b9d4e..fdd015e0b037 100644 --- a/salt/states/postgres_initdb.py +++ b/salt/states/postgres_initdb.py @@ -6,7 +6,7 @@ The postgres_initdb module is used to initialize the postgresql data directory. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/postgres_language.py b/salt/states/postgres_language.py index d1bf65438d2d..813189879fff 100644 --- a/salt/states/postgres_language.py +++ b/salt/states/postgres_language.py @@ -6,7 +6,7 @@ The postgres_language module is used to create and manage Postgres languages. Languages can be set as either absent or present -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/postgres_privileges.py b/salt/states/postgres_privileges.py index 8ebbffcdf539..3f12e860e797 100644 --- a/salt/states/postgres_privileges.py +++ b/salt/states/postgres_privileges.py @@ -18,7 +18,7 @@ Setting the grant option is supported as well. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/postgres_user.py b/salt/states/postgres_user.py index d00b2f83dd48..101c96da6304 100644 --- a/salt/states/postgres_user.py +++ b/salt/states/postgres_user.py @@ -96,7 +96,7 @@ def present(name, default_passwoord The password used only when creating the user, unless password is set. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 refresh_password Password refresh flag diff --git a/salt/states/redismod.py b/salt/states/redismod.py index df27e9119f51..ae012983ccfe 100644 --- a/salt/states/redismod.py +++ b/salt/states/redismod.py @@ -121,7 +121,7 @@ def slaveof(name, sentinel_host=None, sentinel_port=None, sentinel_password=None ''' Set this redis instance as a slave. - .. versionadded: Boron + .. versionadded: 2016.3.0 name Master to make this a slave of diff --git a/salt/states/reg.py b/salt/states/reg.py index fd77fd5d3b46..b752c8bac24b 100644 --- a/salt/states/reg.py +++ b/salt/states/reg.py @@ -60,9 +60,6 @@ # Import python libs import logging -# Import salt libs -import salt.utils - log = logging.getLogger(__name__) @@ -70,18 +67,23 @@ def __virtual__(): ''' Load this state if the reg module exists ''' - return 'reg' if 'reg.read_key' in __salt__ else False + if 'reg.read_value' not in __salt__: + return (False, 'reg state module failed to load: ' + 'missing module function: reg.read_value') + if 'reg.set_value' not in __salt__: + return (False, 'reg state module failed to load: ' + 'missing module function: reg.set_value') -def _parse_key_value(key): - ''' - split the full path in the registry to the key and the rest - ''' - splt = key.split("\\") - hive = splt.pop(0) - vname = splt.pop(-1) - key = '\\'.join(splt) - return hive, key, vname + if 'reg.delete_value' not in __salt__: + return (False, 'reg state module failed to load: ' + 'missing module function: reg.delete_value') + + if 'reg.delete_key_recursive' not in __salt__: + return (False, 'reg state module failed to load: ' + 'missing module function: reg.delete_key_recursive') + + return 'reg' def _parse_key(key): @@ -95,11 +97,9 @@ def _parse_key(key): def present(name, - value=None, vname=None, vdata=None, vtype='REG_SZ', - reflection=True, use_32bit_registry=False): ''' Ensure a registry key or value is present. @@ -114,16 +114,13 @@ def present(name, - HKEY_LOCAL_MACHINE or HKLM - HKEY_USERS or HKU - :param str value: Deprecated. Use vname and vdata instead. Included here for - backwards compatibility. - :param str vname: The name of the value you'd like to create beneath the Key. If this parameter is not passed it will assume you want to set the (Default) value - :param str vdata: The value you'd like to set for the Key. If a value name - (vname) is passed, this will be the data for that value name. If not, this - will be the (Default) value for the key. + :param str vdata: The value you'd like to set. If a value name (vname) is + passed, this will be the data for that value name. If not, this will be the + (Default) value for the key. The type for the (Default) value is always REG_SZ and cannot be changed. This parameter is optional. If not passed, the Key will be created with no @@ -138,26 +135,15 @@ def present(name, - REG_MULTI_SZ - REG_SZ (Default) - :param bool reflection: On 64 bit machines a duplicate value will be created - in the ``Wow6432Node`` for 32bit programs. This only applies to the SOFTWARE - key. This option is ignored on 32bit operating systems. This value defaults - to True. Set it to False to disable reflection. - - .. deprecated:: 2015.8.2 - Use `use_32bit_registry` instead. - The parameter seems to have no effect since Windows 7 / Windows 2008R2 - removed support for reflection. The parameter will be removed in Boron. - :param bool use_32bit_registry: Use the 32bit portion of the registry. Applies only to 64bit windows. 32bit Windows will ignore this parameter. - Default if False. + Default is False. :return: Returns a dictionary showing the results of the registry operation. :rtype: dict The following example will set the ``(Default)`` value for the - ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The - value will not be reflected in ``Wow6432Node``: + ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``2016.3.1``: Example: @@ -165,11 +151,10 @@ def present(name, HKEY_CURRENT_USER\\SOFTWARE\\Salt: reg.present: - - vdata: 0.15.3 - - reflection: False + - vdata: 2016.3.1 The following example will set the value for the ``version`` entry under the - ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The + ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``2016.3.1``. The value will be reflected in ``Wow6432Node``: Example: @@ -179,7 +164,7 @@ def present(name, HKEY_CURRENT_USER\\SOFTWARE\\Salt: reg.present: - vname: version - - vdata: 0.15.3 + - vdata: 2016.3.1 In the above example the path is interpreted as follows: - ``HKEY_CURRENT_USER`` is the hive @@ -192,20 +177,7 @@ def present(name, 'changes': {}, 'comment': ''} - # This is for backwards compatibility - # If 'value' is passed a value, vdata becomes value and the vname is - # obtained from the key path - if value or value in [0, '']: - hive, key, vname = _parse_key_value(name) - vdata = value - ret['comment'] = 'State file is using deprecated syntax. Please update.' - salt.utils.warn_until( - 'Boron', - 'The \'value\' argument has been deprecated. ' - 'Please use vdata instead.' - ) - else: - hive, key = _parse_key(name) + hive, key = _parse_key(name) # Determine what to do reg_current = __salt__['reg.read_value'](hive=hive, @@ -267,7 +239,7 @@ def absent(name, vname=None, use_32bit_registry=False): :param bool use_32bit_registry: Use the 32bit portion of the registry. Applies only to 64bit windows. 32bit Windows will ignore this parameter. - Default if False. + Default is False. :return: Returns a dictionary showing the results of the registry operation. :rtype: dict @@ -276,17 +248,13 @@ def absent(name, vname=None, use_32bit_registry=False): .. code-block:: yaml - 'HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version': + 'HKEY_CURRENT_USER\\SOFTWARE\\Salt': reg.absent + - vname: version - In the above example the path is interpreted as follows: - - - ``HKEY_CURRENT_USER`` is the hive - - ``SOFTWARE\\Salt`` is the key - - ``version`` is the value name - - So the value ``version`` will be deleted from the ``SOFTWARE\\Salt`` key in - the ``HKEY_CURRENT_USER`` hive. + In the above example the value named ``version`` will be removed from + the SOFTWARE\\Salt key in the HKEY_CURRENT_USER hive. If ``vname`` was not + passed, the (Default) value would be deleted. ''' ret = {'name': name, 'result': True, @@ -301,18 +269,8 @@ def absent(name, vname=None, use_32bit_registry=False): vname=vname, use_32bit_registry=use_32bit_registry) if not reg_check['success'] or reg_check['vdata'] == '(value not set)': - if not vname: - hive, key, vname = _parse_key_value(name) - reg_check = __salt__['reg.read_value'](hive=hive, - key=key, - vname=vname, - use_32bit_registry=use_32bit_registry) - if not reg_check['success'] or reg_check['vdata'] == '(value not set)': - ret['comment'] = '{0} is already absent'.format(name) - return ret - else: - ret['comment'] = '{0} is already absent'.format(name) - return ret + ret['comment'] = '{0} is already absent'.format(name) + return ret remove_change = {'Key': r'{0}\{1}'.format(hive, key), 'Entry': '{0}'.format(vname if vname else '(Default)')} @@ -338,7 +296,7 @@ def absent(name, vname=None, use_32bit_registry=False): return ret -def key_absent(name, force=False, use_32bit_registry=False): +def key_absent(name, use_32bit_registry=False): r''' .. versionadded:: 2015.5.4 @@ -346,15 +304,16 @@ def key_absent(name, force=False, use_32bit_registry=False): entries it contains. It will fail if the key contains subkeys. :param str name: A string representing the full path to the key to be - removed to include the hive and the keypath. The hive can be any of the following: + removed to include the hive and the keypath. The hive can be any of the + following: - HKEY_LOCAL_MACHINE or HKLM - HKEY_CURRENT_USER or HKCU - HKEY_USER or HKU - :param bool force: A boolean value indicating that all subkeys should be - deleted with the key. If force=False and subkeys exists beneath the key you - want to delete, key_absent will fail. Use with caution. The default is False. + :param bool use_32bit_registry: Use the 32bit portion of the registry. + Applies only to 64bit windows. 32bit Windows will ignore this parameter. + Default is False. :return: Returns a dictionary showing the results of the registry operation. :rtype: dict @@ -400,10 +359,9 @@ def key_absent(name, force=False, use_32bit_registry=False): return ret # Delete the value - __salt__['reg.delete_key'](hive=hive, - key=key, - force=force, - use_32bit_registry=use_32bit_registry) + __salt__['reg.delete_key_recursive'](hive=hive, + key=key, + use_32bit_registry=use_32bit_registry) if __salt__['reg.read_value'](hive=hive, key=key, use_32bit_registry=use_32bit_registry)['success']: diff --git a/salt/states/rsync.py b/salt/states/rsync.py index 0b542c13e164..bda65aa2eb5c 100644 --- a/salt/states/rsync.py +++ b/salt/states/rsync.py @@ -16,7 +16,7 @@ ''' Rsync state. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' from __future__ import absolute_import diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index 79be79f12546..0ce9c59e1fab 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -161,11 +161,11 @@ def state( if env is not None: msg = ( 'Passing a salt environment should be done using \'saltenv\' not ' - '\'env\'. This warning will go away in Salt Boron and this ' + '\'env\'. This warning will go away in Salt Carbon and this ' 'will be the default and expected behavior. Please update your ' 'state files.' ) - salt.utils.warn_until('Boron', msg) + salt.utils.warn_until('Carbon', msg) state_ret.setdefault('warnings', []).append(msg) # No need to set __env__ = env since that's done in the state machinery diff --git a/salt/states/selinux.py b/salt/states/selinux.py index 3ae1650396e9..3931d84b071d 100644 --- a/salt/states/selinux.py +++ b/salt/states/selinux.py @@ -64,7 +64,7 @@ def _refine_value(value): def _refine_module_state(module_state): ''' Return a predictable value, or allow us to error out - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' module_state = str(module_state).lower() if module_state in ('1', 'on', 'yes', 'true', 'enabled'): @@ -177,7 +177,7 @@ def module(name, module_state='Enabled', version='any'): Defaults to no preference, set to a specified value if required. Currently can only alert if the version is incorrect. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'result': True, diff --git a/salt/states/smartos.py b/salt/states/smartos.py index 76aa16300878..9815a232c297 100644 --- a/salt/states/smartos.py +++ b/salt/states/smartos.py @@ -7,7 +7,7 @@ :depends: vmadm, imgadm :platform: smartos -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/splunk.py b/salt/states/splunk.py index 8834c2cee5f6..e03d140f697a 100644 --- a/salt/states/splunk.py +++ b/salt/states/splunk.py @@ -2,7 +2,7 @@ ''' Splunk User State Module -.. versionadded:: Boron. +.. versionadded:: 2016.3.0. This state is used to ensure presence of users in splunk. diff --git a/salt/states/ssh_known_hosts.py b/salt/states/ssh_known_hosts.py index 62f08b5c6a63..1a8b9f406955 100644 --- a/salt/states/ssh_known_hosts.py +++ b/salt/states/ssh_known_hosts.py @@ -91,7 +91,7 @@ def present( time anything was read from that host, then the connection is closed and the host in question considered unavailable. Default is 5 seconds. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ret = {'name': name, 'changes': {}, diff --git a/salt/states/telemetry_alert.py b/salt/states/telemetry_alert.py index ccb3bfd7a651..272816621d97 100644 --- a/salt/states/telemetry_alert.py +++ b/salt/states/telemetry_alert.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ''' -.. versionadded:: Boron. +.. versionadded:: 2016.3.0. Manage Telemetry alert configurations ===================================== diff --git a/salt/states/virt.py b/salt/states/virt.py index af86febaebfe..f7cb41f916cf 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -136,7 +136,7 @@ def stopped(name): ''' Stops a VM by shutting it down nicely. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -151,7 +151,7 @@ def powered_off(name): ''' Stops a VM by power off. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -166,7 +166,7 @@ def running(name, **kwargs): ''' Starts an existing guest, or defines and starts a new VM with specified arguments. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -216,7 +216,7 @@ def snapshot(name, suffix=None): ''' Takes a snapshot of a particular VM or by a UNIX-style wildcard. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -237,7 +237,7 @@ def rebooted(name): ''' Reboots VMs - .. versionadded:: Boron + .. versionadded:: 2016.3.0 :param name: :return: @@ -248,12 +248,12 @@ def rebooted(name): def unpowered(name): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Use :py:func:`~salt.modules.virt.powered_off` instead. Stops a VM by power off. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -266,12 +266,12 @@ def unpowered(name): def saved(name, suffix=None): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Use :py:func:`~salt.modules.virt.snapshot` instead. Takes a snapshot of a particular VM or by a UNIX-style wildcard. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml @@ -289,11 +289,11 @@ def saved(name, suffix=None): def reverted(name, snapshot=None, cleanup=False): ''' - .. deprecated:: Boron + .. deprecated:: 2016.3.0 Reverts to the particular snapshot. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/win_iis.py b/salt/states/win_iis.py index c0af870283dd..99b6059997be 100644 --- a/salt/states/win_iis.py +++ b/salt/states/win_iis.py @@ -5,7 +5,7 @@ This module provides the ability to add/remove websites and application pools from Microsoft IIS. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 ''' diff --git a/salt/states/win_system.py b/salt/states/win_system.py index 33a9608d9031..cfa9a60558bb 100644 --- a/salt/states/win_system.py +++ b/salt/states/win_system.py @@ -129,7 +129,7 @@ def computer_name(name): def hostname(name): ''' - .. versionadded:: Boron + .. versionadded:: 2016.3.0 Manage the hostname of the computer diff --git a/salt/states/x509.py b/salt/states/x509.py index 0c8a442e5e2d..2a9c7e43cbe0 100644 --- a/salt/states/x509.py +++ b/salt/states/x509.py @@ -16,7 +16,7 @@ :mod:`sign_remote_certificate ` function. -/etc/salt/master.d/peer.sls +/etc/salt/master.d/peer.conf .. code-block:: yaml diff --git a/salt/states/zcbuildout.py b/salt/states/zcbuildout.py index eacb59c52678..a2fec8e2becd 100644 --- a/salt/states/zcbuildout.py +++ b/salt/states/zcbuildout.py @@ -6,7 +6,7 @@ This module is inspired from minitage's buildout maker (https://github.com/minitage/minitage/blob/master/src/minitage/core/makers/buildout.py) -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. note:: diff --git a/salt/states/zenoss.py b/salt/states/zenoss.py index 18bf430b19d8..269599cbe0c0 100644 --- a/salt/states/zenoss.py +++ b/salt/states/zenoss.py @@ -2,7 +2,7 @@ ''' State to manage monitoring in Zenoss. -.. versionadded:: Boron +.. versionadded:: 2016.3.0 This state module depends on the 'zenoss' Salt execution module. diff --git a/salt/states/zfs.py b/salt/states/zfs.py index 9f42b2a3a90f..b9da2478ee32 100644 --- a/salt/states/zfs.py +++ b/salt/states/zfs.py @@ -7,7 +7,7 @@ :depends: zfs :platform: smartos, illumos, solaris, freebsd, linux -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/states/zpool.py b/salt/states/zpool.py index f79a4ad3e638..690720839ff8 100644 --- a/salt/states/zpool.py +++ b/salt/states/zpool.py @@ -7,7 +7,7 @@ :depends: zpool :platform: smartos, illumos, solaris, freebsd, linux -.. versionadded:: Boron +.. versionadded:: 2016.3.0 .. code-block:: yaml diff --git a/salt/template.py b/salt/template.py index 8ff6b7638856..cf04ce3612af 100644 --- a/salt/template.py +++ b/salt/template.py @@ -43,11 +43,11 @@ def compile_template(template, ret = {} log.debug('compile template: {0}'.format(template)) - # We "map" env to the same as saltenv until Boron is out in order to follow the same deprecation path + # We "map" env to the same as saltenv until Carbon is out in order to follow the same deprecation path kwargs.setdefault('env', saltenv) salt.utils.warn_until( - 'Boron', - 'We are only supporting \'env\' in the templating context until Boron comes out. ' + 'Carbon', + 'We are only supporting \'env\' in the templating context until Carbon comes out. ' 'Once this warning is shown, please remove the above mapping', _dont_call_warnings=True ) diff --git a/salt/thorium/__init__.py b/salt/thorium/__init__.py index 3e1b07c9c20c..5e89107408e5 100644 --- a/salt/thorium/__init__.py +++ b/salt/thorium/__init__.py @@ -11,12 +11,14 @@ # Import python libs from __future__ import absolute_import +import os import time import logging import traceback # Import Salt libs import salt.state +import salt.payload from salt.exceptions import SaltRenderError log = logging.getLogger(__name__) @@ -26,8 +28,19 @@ class ThorState(salt.state.HighState): ''' Compile the thorium state and manage it in the thorium runtime ''' - def __init__(self, opts): + def __init__( + self, + opts, + grains=False, + grain_keys=None, + pillar=False, + pillar_keys=None): + self.grains = grains + self.grain_keys = grain_keys + self.pillar = pillar + self.pillar_keys = pillar_keys opts['file_roots'] = opts['thorium_roots'] + opts['file_client'] = 'local' self.opts = opts salt.state.HighState.__init__(self, self.opts, loader='thorium') self.state.inject_globals = {'__reg__': {}} @@ -35,15 +48,57 @@ def __init__(self, opts): self.opts, self.opts['sock_dir']) + def gather_cache(self): + ''' + Gather the specified data from the minion data cache + ''' + cache = {'grains': {}, 'pillar': {}} + if self.grains or self.pillar: + if self.opts.get('minion_data_cache'): + serial = salt.payload.Serial(self.opts) + cdir = os.path.join(self.opts['cachedir'], 'minions') + if not os.path.isdir(cdir): + minions = [] + else: + minions = os.listdir(cdir) + if not minions: + return cache + for minion in minions: + cache['pillar'][minion] = {} + cache['grains'][minion] = {} + datap = os.path.join(cdir, minion, 'data.p') + try: + with salt.utils.fopen(datap, 'rb') as fp_: + total = serial.load(fp_) + if 'pillar' in total: + if self.pillar_keys: + for key in self.pillar_keys: + if key in total['pillar']: + cache['pillar'][minion][key] = total['pillar'][key] + else: + cache['pillar'][minion] = total['pillar'] + if 'grains' in total: + if self.grain_keys: + for key in self.grain_keys: + if key in total['grains']: + cache['grains'][minion][key] = total['grains'][key] + else: + cache['grains'][minion] = total['grains'] + else: + continue + except (IOError, OSError): + continue + return cache + def start_runtime(self): ''' Start the system! ''' - chunks = self.get_chunks() while True: try: - self.call_runtime(chunks) + self.call_runtime() except Exception: + log.error('Exception in Thorium: ', exc_info=True) time.sleep(self.opts['thorium_interval']) def get_chunks(self, exclude=None, whitelist=None): @@ -94,20 +149,29 @@ def get_events(self): return ret ret.append(event) - def call_runtime(self, chunks): + def call_runtime(self): ''' Execute the runtime ''' + cache = self.gather_cache() + chunks = self.get_chunks() interval = self.opts['thorium_interval'] + recompile = self.opts.get('thorium_recompile', 300) + r_start = time.time() while True: events = self.get_events() if not events: time.sleep(interval) - self.state.inject_globals['__events__'] = events + continue start = time.time() + self.state.inject_globals['__events__'] = events self.state.call_chunks(chunks) elapsed = time.time() - start left = interval - elapsed if left > 0: time.sleep(left) self.state.reset_run_num() + if (start - r_start) > recompile: + cache = self.gather_cache() + chunks = self.get_chunks() + r_start = time.time() diff --git a/salt/thorium/check.py b/salt/thorium/check.py index eee82199f592..e25750e879c0 100644 --- a/salt/thorium/check.py +++ b/salt/thorium/check.py @@ -59,7 +59,7 @@ def contains(name, value): ret['comment'] = 'Value {0} not in register'.format(name) return ret try: - if __reg__[name]['val'] in value: + if value in __reg__[name]['val']: ret['result'] = True except TypeError: pass diff --git a/salt/thorium/file.py b/salt/thorium/file.py index 881c2ecbfef8..633fea85ff50 100644 --- a/salt/thorium/file.py +++ b/salt/thorium/file.py @@ -22,7 +22,7 @@ def save(name): 'result': True} tgt_dir = os.path.join(__opts__['cachedir'], 'thorium', 'saves') fn_ = os.path.join(tgt_dir, name) - if not os.isdir(tgt_dir): + if not os.path.isdir(tgt_dir): os.makedirs(tgt_dir) with salt.utils.fopen(fn_, 'w+') as fp_: fp_.write(json.dumps(__reg__)) diff --git a/salt/thorium/reg.py b/salt/thorium/reg.py index 0726e538f2a5..733d4727e343 100644 --- a/salt/thorium/reg.py +++ b/salt/thorium/reg.py @@ -10,6 +10,7 @@ __func_alias__ = { 'set_': 'set', + 'list_': 'list', } diff --git a/salt/thorium/timer.py b/salt/thorium/timer.py new file mode 100644 index 000000000000..cbbab1d8e9b7 --- /dev/null +++ b/salt/thorium/timer.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +''' +Allow for flow based timers. These timers allow for a sleep to exist across +multiple runs of the flow +''' + +from __future__ import absolute_import +import time + + +def hold(name, seconds): + ''' + Wait for a given period of time, then fire a result of True, requireing + this state allows for an action to be blocked for evaluation based on + time + ''' + ret = {'name': name, + 'result': False, + 'comment': '', + 'changes': {}} + start = time.time() + if 'timer' not in __context__: + __context__['timer'] = {} + if name not in __context__['timer']: + __context__['timer'][name] = start + if (start - __context__['timer'][name]) > seconds: + ret['result'] = True + __context__['timer'][name] = start + return ret diff --git a/salt/transport/zeromq.py b/salt/transport/zeromq.py index e1e5cbd98468..27fa2acc811a 100644 --- a/salt/transport/zeromq.py +++ b/salt/transport/zeromq.py @@ -803,6 +803,7 @@ def destroy(self): self.stream.io_loop.remove_handler(self.stream.socket) # set this to None, more hacks for messed up pyzmq self.stream.socket = None + self.stream = None self.socket.close() if self.context.closed is False: self.context.term() diff --git a/salt/utils/cloud.py b/salt/utils/cloud.py index 8bd3763cddfa..75877e178c07 100644 --- a/salt/utils/cloud.py +++ b/salt/utils/cloud.py @@ -3113,7 +3113,7 @@ def check_key_path_and_mode(provider, key_path): Returns True or False. - .. versionadded:: Boron + .. versionadded:: 2016.3.0 provider The provider name that the key_path to check belongs to. diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 6ff5a1135d5c..8638787b4fe9 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -111,7 +111,7 @@ def failhard(role): class GitProvider(object): ''' - Base class for gitfs/git_pillar provider classes Should never be used + Base class for gitfs/git_pillar provider classes. Should never be used directly. self.provider should be set in the sub-class' __init__ function before @@ -1971,6 +1971,13 @@ def get_provider(self): elif self.verify_dulwich(quiet=True): self.provider = 'dulwich' else: + # Ensure non-lowercase providers work + try: + desired_provider = desired_provider.lower() + except AttributeError: + # Should only happen if someone does something silly like + # set the provider to a numeric value. + desired_provider = str(desired_provider).lower() if desired_provider not in self.valid_providers: log.critical( 'Invalid {0}_provider \'{1}\'. Valid choices are: {2}' @@ -2298,9 +2305,9 @@ def serve_file(self, load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -2334,9 +2341,9 @@ def file_hash(self, load, fnd): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -2367,9 +2374,9 @@ def _file_lists(self, load, form): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') @@ -2439,9 +2446,9 @@ def symlink_list(self, load): ''' if 'env' in load: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) load['saltenv'] = load.pop('env') diff --git a/salt/utils/jid.py b/salt/utils/jid.py index 05b8c5878124..509a87a7adff 100644 --- a/salt/utils/jid.py +++ b/salt/utils/jid.py @@ -4,10 +4,7 @@ from calendar import month_abbr as months import datetime -import hashlib -import os -import salt.utils from salt.ext import six @@ -33,39 +30,6 @@ def is_jid(jid): return False -def jid_dir(jid, cachedir, sum_type): - ''' - Return the jid_dir for the given job id - ''' - salt.utils.warn_until( - 'Boron', - 'All job_cache management has been moved into the local_cache ' - 'returner, this util function will be removed-- please use ' - 'the returner' - ) - jid = salt.utils.to_bytes(str(jid)) if six.PY3 else str(jid) - jhash = getattr(hashlib, sum_type)(jid).hexdigest() - return os.path.join(cachedir, 'jobs', jhash[:2], jhash[2:]) - - -def jid_load(jid, cachedir, sum_type, serial='msgpack'): - ''' - Return the load data for a given job id - ''' - salt.utils.warn_until( - 'Boron', - 'Getting the load has been moved into the returner interface ' - 'please get the data from the master_job_cache ' - ) - _dir = jid_dir(jid, cachedir, sum_type) - load_fn = os.path.join(_dir, '.load.p') - if not os.path.isfile(load_fn): - return {} - serial = salt.payload.Serial(serial) - with salt.utils.fopen(load_fn, 'rb') as fp_: - return serial.load(fp_) - - def jid_to_time(jid): ''' Convert a salt job id into the time when the job was invoked diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py index 742f94c61af0..25df07d3ed17 100644 --- a/salt/utils/jinja.py +++ b/salt/utils/jinja.py @@ -58,10 +58,10 @@ def __init__(self, opts, saltenv='base', encoding='utf-8', env=None, pillar_rend=False): if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/utils/mac_utils.py b/salt/utils/mac_utils.py new file mode 100644 index 000000000000..24c98ef8a665 --- /dev/null +++ b/salt/utils/mac_utils.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +''' +Helper functions for use by mac modules +.. versionadded:: 2016.3.0 +''' +from __future__ import absolute_import + +# Import Python Libraries +import logging + +# Import Third Party Libs + +# Import Salt Libs +import salt.utils +from salt.exceptions import CommandExecutionError, SaltInvocationError + +# Set up logging +log = logging.getLogger(__name__) + +__virtualname__ = 'mac_utils' + + +def __virtual__(): + ''' + Load only on Mac OS + ''' + if not salt.utils.is_darwin(): + return (False, 'The mac_utils utility could not be loaded: ' + 'utility only works on MacOS systems.') + + return __virtualname__ + + +def execute_return_success(cmd): + ''' + Executes the passed command. Returns True if successful + + :param str cmd: The command to run + + :return: True if successful, otherwise False + :rtype: bool + ''' + ret = __salt__['cmd.run_all'](cmd) + + if 'not supported' in ret['stdout'].lower(): + return 'Not supported on this machine' + + if ret['retcode'] != 0: + msg = 'Command Failed: {0}\n'.format(cmd) + msg += 'Return Code: {0}\n'.format(ret['retcode']) + msg += 'Output: {0}\n'.format(ret['stdout']) + raise CommandExecutionError(msg) + + return True + + +def execute_return_result(cmd): + ''' + Executes the passed command. Returns the standard out if successful + + :param str cmd: The command to run + + :return: The standard out of the command if successful, otherwise returns + an error + :rtype: str + ''' + ret = __salt__['cmd.run_all'](cmd) + + if ret['retcode'] != 0: + msg = 'Command failed: {0}'.format(ret['stderr']) + raise CommandExecutionError(msg) + + return ret['stdout'] + + +def parse_return(data): + ''' + Returns the data portion of a string that is colon separated. + + :param str data: The string that contains the data to be parsed. Usually the + standard out from a command + + For example: + ``Time Zone: America/Denver`` + will return: + ``America/Denver`` + ''' + + if ': ' in data: + return data.split(': ')[1] + if ':\n' in data: + return data.split(':\n')[1] + else: + return data + + +def validate_enabled(enabled): + ''' + Helper function to validate the enabled parameter. Boolean values are + converted to "on" and "off". String values are checked to make sure they are + either "on" or "off". Integer ``0`` will return "off". All other integers + will return "on" + + :param enabled: Enabled can be boolean True or False, Integers, or string + values "on" and "off". + :type: str, int, bool + + :return: "on" or "off" or errors + :rtype: str + ''' + if isinstance(enabled, str): + if enabled.lower() not in ['on', 'off']: + msg = '\nMac Power: Invalid String Value for Enabled.\n' \ + 'String values must be \'on\' or \'off\'.\n' \ + 'Passed: {0}'.format(enabled) + raise SaltInvocationError(msg) + + return enabled.lower() + + return 'on' if bool(enabled) else 'off' diff --git a/salt/utils/mako.py b/salt/utils/mako.py index 80ad9d8df5f3..c4afac66b3ae 100644 --- a/salt/utils/mako.py +++ b/salt/utils/mako.py @@ -47,10 +47,10 @@ class SaltMakoTemplateLookup(TemplateCollection): def __init__(self, opts, saltenv='base', env=None, pillar_rend=False): if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/utils/master.py b/salt/utils/master.py index eee7f67b5b6a..63a2f424133a 100644 --- a/salt/utils/master.py +++ b/salt/utils/master.py @@ -76,10 +76,10 @@ def __init__(self, env=None): if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' 'not \'env\'. This functionality will be removed in Salt ' - 'Boron.' + 'Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/utils/network.py b/salt/utils/network.py index 847a4ab64ed8..fd36f91ca90e 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -414,7 +414,7 @@ def _number_of_set_bits(x): ''' Returns the number of bits that are set in a 32bit int ''' - #Taken from http://stackoverflow.com/a/4912729. Many thanks! + # Taken from http://stackoverflow.com/a/4912729. Many thanks! x -= (x >> 1) & 0x55555555 x = ((x >> 2) & 0x33333333) + (x & 0x33333333) x = ((x >> 4) + x) & 0x0f0f0f0f @@ -910,13 +910,13 @@ def ip_in_subnet(addr, cidr): ''' Returns True if given IP is within specified subnet, otherwise False - .. deprecated:: Boron + .. deprecated:: Carbon Use :py:func:`~salt.utils.network.in_subnet` instead ''' salt.utils.warn_until( - 'Boron', + 'Carbon', 'Support for \'ip_in_subnet\' has been deprecated and will be removed ' - 'in Salt Boron. Please use \'in_subnet\' instead.' + 'in Salt Carbon. Please use \'in_subnet\' instead.' ) return in_subnet(cidr, addr) @@ -974,6 +974,18 @@ def hex2ip(hex_ip, invert=False): Convert a hex string to an ip, if a failure occurs the original hex is returned ''' + if len(hex_ip) == 32: # ipv6 + ip = [] + for i in range(0, 32, 8): + ip_part = hex_ip[i:i + 8] + ip_part = [ip_part[x:x + 2] for x in range(0, 8, 2)] + ip.append("{0[3]}{0[2]}:{0[1]}{0[0]}".format(ip_part)) + try: + return ipaddress.IPv6Address(":".join(ip)).compressed + except ipaddress.AddressValueError as ex: + log.error('hex2ip - ipv6 address error: {0}'.format(ex)) + return hex_ip + try: hip = int(hex_ip, 16) except ValueError: @@ -1015,13 +1027,13 @@ def active_tcp(): Return a dict describing all active tcp connections as quickly as possible ''' ret = {} - if os.path.isfile('/proc/net/tcp'): - with salt.utils.fopen('/proc/net/tcp', 'rb') as fp_: - for line in fp_: - if line.strip().startswith('sl'): - continue - ret.update(_parse_tcp_line(line)) - return ret + for statf in ['/proc/net/tcp', '/proc/net/tcp6']: + if os.path.isfile(statf): + with salt.utils.fopen(statf, 'rb') as fp_: + for line in fp_: + if line.strip().startswith('sl'): + continue + ret.update(_parse_tcp_line(line)) return ret @@ -1029,19 +1041,7 @@ def local_port_tcp(port): ''' Return a set of remote ip addrs attached to the specified local port ''' - ret = set() - if os.path.isfile('/proc/net/tcp'): - with salt.utils.fopen('/proc/net/tcp', 'rb') as fp_: - for line in fp_: - if line.strip().startswith('sl'): - continue - iret = _parse_tcp_line(line) - sl = next(iter(iret)) - if iret[sl]['local_port'] == port: - ret.add(iret[sl]['remote_addr']) - return ret - else: # Fallback to use 'lsof' if /proc not available - ret = remotes_on_local_tcp_port(port) + ret = _remotes_on(port, 'local_port') return ret @@ -1049,25 +1049,46 @@ def remote_port_tcp(port): ''' Return a set of ip addrs the current host is connected to on given port ''' + ret = _remotes_on(port, 'remote_port') + return ret + + +def _remotes_on(port, which_end): + ''' + Return a set of ip addrs active tcp connections + ''' + port = int(port) ret = set() - if os.path.isfile('/proc/net/tcp'): - with salt.utils.fopen('/proc/net/tcp', 'rb') as fp_: - for line in fp_: - if line.strip().startswith('sl'): - continue - iret = _parse_tcp_line(line) - sl = next(iter(iret)) - if iret[sl]['remote_port'] == port: - ret.add(iret[sl]['remote_addr']) - return ret - else: # Fallback to use 'lsof' if /proc not available - ret = remotes_on_remote_tcp_port(port) + + for statf in ['/proc/net/tcp', '/proc/net/tcp6']: + if os.path.isfile(statf): + with salt.utils.fopen(statf, 'rb') as fp_: + for line in fp_: + if line.strip().startswith('sl'): + continue + iret = _parse_tcp_line(line) + sl = next(iter(iret)) + if iret[sl][which_end] == port: + ret.add(iret[sl]['remote_addr']) + + if not ret: # Fallback to use 'lsof' if /proc not available + if salt.utils.is_sunos(): + return _sunos_remotes_on(port, which_end) + if salt.utils.is_freebsd(): + return _freebsd_remotes_on(port, which_end) + if salt.utils.is_openbsd(): + return _openbsd_remotes_on(port, which_end) + if salt.utils.is_windows(): + return _windows_remotes_on(port, which_end) + + return _linux_remotes_on(port, which_end) + return ret def _parse_tcp_line(line): ''' - Parse a single line from the contents of /proc/net/tcp + Parse a single line from the contents of /proc/net/tcp or /proc/net/tcp6 ''' ret = {} comps = line.strip().split() @@ -1158,7 +1179,7 @@ def _freebsd_remotes_on(port, which_end): continue # ['root', 'python2.7', '1456', '37', 'tcp4', # '127.0.0.1:4505-', '127.0.0.1:55703'] - #print chunks + # print chunks if 'COMMAND' in chunks[1]: continue # ignore header if len(chunks) < 2: @@ -1252,35 +1273,29 @@ def _windows_remotes_on(port, which_end): return remotes -def remotes_on_local_tcp_port(port): +def _linux_remotes_on(port, which_end): ''' - Returns set of ipv4 host addresses of remote established connections + Linux specific helper function. + Returns set of ip host addresses of remote established connections on local tcp port port. Parses output of shell 'lsof' to get connections - $ sudo lsof -i4TCP:4505 -n + $ sudo lsof -iTCP:4505 -n COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Python 9971 root 35u IPv4 0x18a8464a29ca329d 0t0 TCP *:4505 (LISTEN) Python 9971 root 37u IPv4 0x18a8464a29b2b29d 0t0 TCP 127.0.0.1:4505->127.0.0.1:55703 (ESTABLISHED) Python 10152 root 22u IPv4 0x18a8464a29c8cab5 0t0 TCP 127.0.0.1:55703->127.0.0.1:4505 (ESTABLISHED) + Python 10153 root 22u IPv4 0x18a8464a29c8cab5 0t0 TCP [fe80::249a]:4505->[fe80::150]:59367 (ESTABLISHED) ''' - port = int(port) remotes = set() - if salt.utils.is_sunos(): - return _sunos_remotes_on(port, 'local_port') - if salt.utils.is_freebsd(): - return _freebsd_remotes_on(port, 'local_port') - if salt.utils.is_openbsd(): - return _openbsd_remotes_on(port, 'local_port') - if salt.utils.is_windows(): - return _windows_remotes_on(port, 'local_port') - try: - data = subprocess.check_output(['lsof', '-i4TCP:{0:d}'.format(port), '-n']) # pylint: disable=minimum-python-version + data = subprocess.check_output( + ['lsof', '-iTCP:{0:d}'.format(port), '-n', '-P'] # pylint: disable=minimum-python-version + ) except subprocess.CalledProcessError as ex: log.error('Failed "lsof" with returncode = {0}'.format(ex.returncode)) raise @@ -1292,72 +1307,19 @@ def remotes_on_local_tcp_port(port): continue # ['Python', '9971', 'root', '37u', 'IPv4', '0x18a8464a29b2b29d', '0t0', # 'TCP', '127.0.0.1:4505->127.0.0.1:55703', '(ESTABLISHED)'] - #print chunks + # print chunks if 'COMMAND' in chunks[0]: continue # ignore header if 'ESTABLISHED' not in chunks[-1]: continue # ignore if not ESTABLISHED # '127.0.0.1:4505->127.0.0.1:55703' local, remote = chunks[8].split('->') - lhost, lport = local.split(':') - if int(lport) != port: # ignore if local port not port + _, lport = local.rsplit(':', 1) + rhost, rport = remote.rsplit(':', 1) + if which_end == 'remote_port' and int(rport) != port: continue - rhost, rport = remote.split(':') - remotes.add(rhost) - - return remotes - - -def remotes_on_remote_tcp_port(port): - ''' - Returns set of ipv4 host addresses which the current host is connected - to on given port - - Parses output of shell 'lsof' to get connections - - $ sudo lsof -i4TCP:4505 -n - COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME - Python 9971 root 35u IPv4 0x18a8464a29ca329d 0t0 TCP *:4505 (LISTEN) - Python 9971 root 37u IPv4 0x18a8464a29b2b29d 0t0 TCP 127.0.0.1:4505->127.0.0.1:55703 (ESTABLISHED) - Python 10152 root 22u IPv4 0x18a8464a29c8cab5 0t0 TCP 127.0.0.1:55703->127.0.0.1:4505 (ESTABLISHED) - - ''' - port = int(port) - remotes = set() - - if salt.utils.is_sunos(): - return _sunos_remotes_on(port, 'remote_port') - if salt.utils.is_freebsd(): - return _freebsd_remotes_on(port, 'remote_port') - if salt.utils.is_openbsd(): - return _openbsd_remotes_on(port, 'remote_port') - if salt.utils.is_windows(): - return _windows_remotes_on(port, 'remote_port') - - try: - data = subprocess.check_output(['lsof', '-i4TCP:{0:d}'.format(port), '-n']) # pylint: disable=minimum-python-version - except subprocess.CalledProcessError as ex: - log.error('Failed "lsof" with returncode = {0}'.format(ex.returncode)) - raise - - lines = salt.utils.to_str(data).split('\n') - for line in lines: - chunks = line.split() - if not chunks: - continue - # ['Python', '9971', 'root', '37u', 'IPv4', '0x18a8464a29b2b29d', '0t0', - # 'TCP', '127.0.0.1:4505->127.0.0.1:55703', '(ESTABLISHED)'] - #print chunks - if 'COMMAND' in chunks[0]: - continue # ignore header - if 'ESTABLISHED' not in chunks[-1]: - continue # ignore if not ESTABLISHED - # '127.0.0.1:4505->127.0.0.1:55703' - local, remote = chunks[8].split('->') - rhost, rport = remote.split(':') - if int(rport) != port: # ignore if local port not port + if which_end == 'local_port' and int(lport) != port: continue - rhost, rport = remote.split(':') - remotes.add(rhost) + remotes.add(rhost.strip("[]")) return remotes diff --git a/salt/utils/openstack/nova.py b/salt/utils/openstack/nova.py index e0591c4a4de5..0101845ca851 100644 --- a/salt/utils/openstack/nova.py +++ b/salt/utils/openstack/nova.py @@ -139,22 +139,14 @@ def __init__(self, name, server, password=None): 'access_ip': server['accessIPv4'] } - if 'addresses' in server: - if 'public' in server['addresses']: - self.public_ips = [ - ip['addr'] for ip in server['addresses']['public'] - ] - else: - self.public_ips = [] - - if 'private' in server['addresses']: - self.private_ips = [ - ip['addr'] for ip in server['addresses']['private'] - ] - else: - self.private_ips = [] - - self.addresses = server['addresses'] + self.addresses = server.get('addresses', {}) + self.public_ips, self.private_ips = [], [] + for network in self.addresses.values(): + for addr in network: + if salt.utils.cloud.is_public_ip(addr['addr']): + self.public_ips.append(addr['addr']) + else: + self.private_ips.append(addr['addr']) if password: self.extra['password'] = password @@ -980,7 +972,7 @@ def floating_ip_pool_list(self): ''' List all floating IP pools - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn pools = nt_ks.floating_ip_pools.list() @@ -995,7 +987,7 @@ def floating_ip_list(self): ''' List floating IPs - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn floating_ips = nt_ks.floating_ips.list() @@ -1014,7 +1006,7 @@ def floating_ip_show(self, ip): ''' Show info on specific floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn floating_ips = nt_ks.floating_ips.list() @@ -1027,7 +1019,7 @@ def floating_ip_create(self, pool=None): ''' Allocate a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn floating_ip = nt_ks.floating_ips.create(pool) @@ -1044,7 +1036,7 @@ def floating_ip_delete(self, floating_ip): ''' De-allocate a floating IP - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' ip = self.floating_ip_show(floating_ip) nt_ks = self.compute_conn @@ -1054,7 +1046,7 @@ def floating_ip_associate(self, server_name, floating_ip): ''' Associate floating IP address to server - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn server_ = self.server_by_name(server_name) @@ -1066,7 +1058,7 @@ def floating_ip_disassociate(self, server_name, floating_ip): ''' Disassociate a floating IP from server - .. versionadded:: Boron + .. versionadded:: 2016.3.0 ''' nt_ks = self.compute_conn server_ = self.server_by_name(server_name) diff --git a/salt/utils/pkg/rpm.py b/salt/utils/pkg/rpm.py index f699df76e246..86bddf3efa24 100644 --- a/salt/utils/pkg/rpm.py +++ b/salt/utils/pkg/rpm.py @@ -31,7 +31,8 @@ ARCHES = ARCHES_64 + ARCHES_32 + ARCHES_PPC + ARCHES_S390 + \ ARCHES_ALPHA + ARCHES_ARM + ARCHES_SH -QUERYFORMAT = '%{NAME}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}_|-%{REPOID}' +# EPOCHNUM can't be used until RHEL5 is EOL as it is not present +QUERYFORMAT = '%{NAME}_|-%{EPOCH}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}_|-%{REPOID}' def get_osarch(): @@ -86,7 +87,7 @@ def parse_pkginfo(line, osarch=None): pkginfo namedtuple. ''' try: - name, version, release, arch, repoid = line.split('_|-') + name, epoch, version, release, arch, repoid = line.split('_|-') # Handle unpack errors (should never happen with the queryformat we are # using, but can't hurt to be careful). except ValueError: @@ -95,5 +96,7 @@ def parse_pkginfo(line, osarch=None): name = resolve_name(name, arch, osarch) if release: version += '-{0}'.format(release) + if epoch not in ('(none)', '0'): + version = ':'.join((epoch, version)) return pkginfo(name, version, arch, repoid) diff --git a/salt/utils/pushover.py b/salt/utils/pushover.py index d6a27ad0678b..b242e2aaf5dd 100644 --- a/salt/utils/pushover.py +++ b/salt/utils/pushover.py @@ -2,7 +2,7 @@ ''' Library for interacting with Slack API -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module can be used by specifying the name of a configuration profile in the minion config, minion pillar, or master diff --git a/salt/utils/pydsl.py b/salt/utils/pydsl.py index 388ebc6798b9..570e1ded1f82 100644 --- a/salt/utils/pydsl.py +++ b/salt/utils/pydsl.py @@ -141,9 +141,9 @@ def set(self, **options): def include(self, *sls_names, **kws): if kws.get('env', None) is not None: warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility kws['saltenv'] = kws.pop('env') diff --git a/salt/utils/sdb.py b/salt/utils/sdb.py index 622b018308b2..0eef8864aafb 100644 --- a/salt/utils/sdb.py +++ b/salt/utils/sdb.py @@ -21,7 +21,7 @@ def sdb_get(uri, opts): if not uri.startswith('sdb://'): return uri - comps = uri.replace('sdb://', '').split('/') + comps = uri.replace('sdb://', '').split('/', 1) if len(comps) < 2: return uri @@ -49,7 +49,7 @@ def sdb_set(uri, value, opts): if not uri.startswith('sdb://'): return False - comps = uri.replace('sdb://', '').split('/') + comps = uri.replace('sdb://', '').split('/', 1) if len(comps) < 2: return False diff --git a/salt/utils/slack.py b/salt/utils/slack.py index 53460258f928..63af9c182d0f 100644 --- a/salt/utils/slack.py +++ b/salt/utils/slack.py @@ -2,7 +2,7 @@ ''' Library for interacting with Slack API -.. versionadded:: Boron +.. versionadded:: 2016.3.0 :configuration: This module can be used by specifying the name of a configuration profile in the minion config, minion pillar, or master diff --git a/salt/utils/url.py b/salt/utils/url.py index f03fc8a1ba09..1ddf0762a16b 100644 --- a/salt/utils/url.py +++ b/salt/utils/url.py @@ -26,9 +26,9 @@ def parse(url): if '?env=' in resource: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) path, saltenv = resource.split('?env=', 1) elif '?saltenv=' in resource: diff --git a/salt/version.py b/salt/version.py index 98cda6e2e373..ecaa813351d0 100644 --- a/salt/version.py +++ b/salt/version.py @@ -84,7 +84,7 @@ class SaltStackVersion(object): 'Helium' : (2014, 7), 'Lithium' : (2015, 5), 'Beryllium' : (2015, 8), - 'Boron' : (MAX_SIZE - 104, 0), + 'Boron' : (2016, 3), 'Carbon' : (MAX_SIZE - 103, 0), 'Nitrogen' : (MAX_SIZE - 102, 0), # pylint: disable=E8265 diff --git a/salt/wheel/file_roots.py b/salt/wheel/file_roots.py index af252ecf2f48..aef90fbd1521 100644 --- a/salt/wheel/file_roots.py +++ b/salt/wheel/file_roots.py @@ -20,9 +20,9 @@ def find(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -49,9 +49,9 @@ def list_env(saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -99,9 +99,9 @@ def read(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -125,9 +125,9 @@ def write(data, path, saltenv='base', index=0, env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env diff --git a/salt/wheel/pillar_roots.py b/salt/wheel/pillar_roots.py index 5e8728bc19db..c336e035cdab 100644 --- a/salt/wheel/pillar_roots.py +++ b/salt/wheel/pillar_roots.py @@ -21,9 +21,9 @@ def find(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -50,9 +50,9 @@ def list_env(saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -100,9 +100,9 @@ def read(path, saltenv='base', env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env @@ -126,9 +126,9 @@ def write(data, path, saltenv='base', index=0, env=None): ''' if env is not None: salt.utils.warn_until( - 'Boron', + 'Carbon', 'Passing a salt environment should be done using \'saltenv\' ' - 'not \'env\'. This functionality will be removed in Salt Boron.' + 'not \'env\'. This functionality will be removed in Salt Carbon.' ) # Backwards compatibility saltenv = env diff --git a/tests/integration/files/file/base/pkg_latest_epoch.sls b/tests/integration/files/file/base/pkg_latest_epoch.sls new file mode 100644 index 000000000000..5bfe107bd9e1 --- /dev/null +++ b/tests/integration/files/file/base/pkg_latest_epoch.sls @@ -0,0 +1,3 @@ +nova_packages: + pkg.latest: + - name: libguestfs-tools diff --git a/tests/integration/modules/data.py b/tests/integration/modules/data.py index 7de33d311ef4..55d7836c7264 100644 --- a/tests/integration/modules/data.py +++ b/tests/integration/modules/data.py @@ -33,65 +33,27 @@ def test_load_dump(self): def test_get_update(self): ''' - data.getval + data.get data.update - data.getvals ''' self._clear_db() - self.assertTrue( - self.run_function( - 'data.update', - ['spam', 'eggs'] - ) - ) - self.assertEqual( - self.run_function( - 'data.getval', - ['spam'] - ), - 'eggs' - ) - self.assertTrue( - self.run_function( - 'data.update', - ['unladen', 'swallow'] - ) - ) - self.assertEqual( - self.run_function( - 'data.getvals', - ['spam', 'unladen'] - ), - ['eggs', 'swallow'] - ) + self.assertTrue(self.run_function('data.update', ['spam', 'eggs'])) + self.assertEqual(self.run_function('data.get', ['spam']), 'eggs') + + self.assertTrue(self.run_function('data.update', ['unladen', 'swallow'])) + self.assertEqual(self.run_function('data.get', ['["spam", "unladen"]']), ['eggs', 'swallow']) self._clear_db() def test_cas_update(self): ''' data.update data.cas - data.getval + data.get ''' self._clear_db() - self.assertTrue( - self.run_function( - 'data.update', - ['spam', 'eggs'] - ) - ) - self.assertTrue( - self.run_function( - 'data.cas', - ['spam', 'green', 'eggs'] - ) - ) - self.assertEqual( - self.run_function( - 'data.getval', - ['spam'] - ), - 'green' - ) + self.assertTrue(self.run_function('data.update', ['spam', 'eggs'])) + self.assertTrue(self.run_function('data.cas', ['spam', 'green', 'eggs'])) + self.assertEqual(self.run_function('data.get', ['spam']), 'green') if __name__ == '__main__': from integration import run_tests diff --git a/tests/integration/states/compiler.py b/tests/integration/states/compiler.py index 101b669bb9f9..8a6b24beb4f7 100644 --- a/tests/integration/states/compiler.py +++ b/tests/integration/states/compiler.py @@ -41,8 +41,8 @@ def test_jinja_deep_error(self): def test_env_in_jinja_context(self): salt.utils.warn_until( - 'Boron', - 'We are only supporting \'env\' in the templating context until Boron comes out. ' + 'Carbon', + 'We are only supporting \'env\' in the templating context until Carbon comes out. ' 'Once this warning is show, please remove the test case', _dont_call_warnings=True ) diff --git a/tests/integration/states/npm.py b/tests/integration/states/npm.py index 7f803c7c4315..8197d0724263 100644 --- a/tests/integration/states/npm.py +++ b/tests/integration/states/npm.py @@ -36,9 +36,9 @@ def test_npm_install_url_referenced_package(self): ''' Determine if URL-referenced NPM module can be successfully installed. ''' - ret = self.run_state('npm.installed', name='git://github.com/Unitech/pm2') + ret = self.run_state('npm.installed', name='git://github.com/request/request') self.assertSaltTrueReturn(ret) - ret = self.run_state('npm.removed', name='git://github.com/Unitech/pm2') + ret = self.run_state('npm.removed', name='git://github.com/request/request') self.assertSaltTrueReturn(ret) @destructiveTest diff --git a/tests/integration/states/pkg.py b/tests/integration/states/pkg.py index 480abb222be0..118f9ac2c7a8 100644 --- a/tests/integration/states/pkg.py +++ b/tests/integration/states/pkg.py @@ -284,6 +284,17 @@ def test_pkg_with_dot_in_pkgname(self, grains=None): ret = self.run_state('pkg.installed', name=target) self.assertSaltTrueReturn(ret) + @destructiveTest + @skipIf(salt.utils.is_windows(), 'minion is windows') + def test_pkg_latest_with_epoch(self): + ''' + This tests for the following issue: + https://github.com/saltstack/salt/issues/31014 + + This is a destructive test as it installs a package + ''' + ret = self.run_function('state.sls', mods='pkg_latest_epoch') + self.assertSaltTrueReturn(ret) if __name__ == '__main__': from integration import run_tests diff --git a/tests/unit/modules/boto_elb_test.py b/tests/unit/modules/boto_elb_test.py index f93bc09bc409..da13adbf98a3 100644 --- a/tests/unit/modules/boto_elb_test.py +++ b/tests/unit/modules/boto_elb_test.py @@ -68,6 +68,8 @@ def stub_function(self): opts = salt.config.DEFAULT_MASTER_OPTS utils = salt.loader.utils(opts, whitelist=['boto']) +funcs = salt.loader.minion_mods(opts, utils=utils) +boto_elb.__salt__ = funcs boto_elb.__utils__ = utils boto_elb.__virtual__() diff --git a/tests/unit/modules/boto_secgroup_test.py b/tests/unit/modules/boto_secgroup_test.py index a5e168b7b1ce..dd36328fbd50 100644 --- a/tests/unit/modules/boto_secgroup_test.py +++ b/tests/unit/modules/boto_secgroup_test.py @@ -60,6 +60,8 @@ def stub_function(self): opts = salt.config.DEFAULT_MASTER_OPTS utils = salt.loader.utils(opts, whitelist=['boto']) +funcs = salt.loader.minion_mods(opts, utils=utils) +boto_secgroup.__salt__ = funcs boto_secgroup.__utils__ = utils boto_secgroup.__virtual__() diff --git a/tests/unit/modules/boto_vpc_test.py b/tests/unit/modules/boto_vpc_test.py index ac968310a49c..a3e3c011c3e9 100644 --- a/tests/unit/modules/boto_vpc_test.py +++ b/tests/unit/modules/boto_vpc_test.py @@ -1025,17 +1025,16 @@ def test_that_when_associating_an_existing_dhcp_options_set_to_a_non_existent_vp self.assertTrue('error' in dhcp_options_association_result) @mock_ec2 - def test_that_when_creating_and_associating_dhcp_options_set_to_an_existing_vpc_succeeds_the_associate_new_dhcp_options_method_returns_true( + def test_that_when_creating_dhcp_options_set_to_an_existing_vpc_succeeds_the_associate_new_dhcp_options_method_returns_true( self): ''' Tests creation/association of dchp options to an existing vpc successfully ''' vpc = self._create_vpc() - dhcp_creation_and_association_result = boto_vpc.associate_new_dhcp_options_to_vpc(vpc.id, - **dhcp_options_parameters) + dhcp_creation_result = boto_vpc.create_dhcp_options(vpc_id=vpc.id, **dhcp_options_parameters) - self.assertTrue(dhcp_creation_and_association_result['created']) + self.assertTrue(dhcp_creation_result['created']) @mock_ec2 @skipIf(True, 'Disabled pending https://github.com/spulec/moto/issues/493') @@ -1065,13 +1064,13 @@ def test_that_when_creating_and_associating_dhcp_options_set_to_an_existing_vpc_ self.assertTrue('error' in r) @mock_ec2 - def test_that_when_creating_and_associating_dhcp_options_set_to_a_non_existent_vpc_the_dhcp_options_the_associate_new_dhcp_options_method_returns_false( + def test_that_when_creating_dhcp_options_set_to_a_non_existent_vpc_the_dhcp_options_the_associate_new_dhcp_options_method_returns_false( self): ''' Tests creation/association of dhcp options to non-existent vpc ''' - r = boto_vpc.associate_new_dhcp_options_to_vpc('fake', **dhcp_options_parameters) + r = boto_vpc.create_dhcp_options(vpc_name='fake', **dhcp_options_parameters) self.assertTrue('error' in r) @mock_ec2 @@ -1422,7 +1421,7 @@ def test_that_when_creating_and_associating_a_network_acl_to_a_non_existent_subn @mock_ec2 #@skipIf(True, 'Moto has not implemented this feature. Skipping for now.') - def test_that_when_creating_and_associating_a_network_acl_to_a_non_existent_vpc_the_associate_new_network_acl_to_subnet_method_returns_an_error( + def test_that_when_creating_a_network_acl_to_a_non_existent_vpc_the_associate_new_network_acl_to_subnet_method_returns_an_error( self): ''' Tests creation/association of network acl to a non-existent subnet @@ -1430,10 +1429,9 @@ def test_that_when_creating_and_associating_a_network_acl_to_a_non_existent_vpc_ vpc = self._create_vpc() subnet = self._create_subnet(vpc.id) - network_acl_creation_and_association_result = boto_vpc.associate_new_network_acl_to_subnet('fake', subnet.id, - **conn_parameters) + network_acl_creation_result = boto_vpc.create_network_acl(vpc_name='fake', subnet_id=subnet.id, **conn_parameters) - self.assertTrue('error' in network_acl_creation_and_association_result) + self.assertTrue('error' in network_acl_creation_result) @mock_ec2 @skipIf(True, 'Moto has not implemented this feature. Skipping for now.') diff --git a/tests/unit/modules/data_test.py b/tests/unit/modules/data_test.py index cffce6c153cd..c350ea030e43 100644 --- a/tests/unit/modules/data_test.py +++ b/tests/unit/modules/data_test.py @@ -90,24 +90,22 @@ def test_update(self): ''' self.assertTrue(data.update('foo', 'salt')) - # 'getval' function tests: 1 + # 'get' function tests: 2 @patch('salt.modules.data.load', MagicMock(return_value={'salt': 'SALT'})) - def test_getval(self): + def test_get(self): ''' - Test if it get a value from the minion datastore + Test if it gets a value from the minion datastore ''' - self.assertEqual(data.getval('salt'), 'SALT') - - # 'getvals' function tests: 1 + self.assertEqual(data.get('salt'), 'SALT') @patch('salt.modules.data.load', MagicMock(return_value={'salt': 'SALT', 'salt1': 'SALT1'})) - def test_getvals(self): + def test_get_vals(self): ''' - Test if it get a values from the minion datastore + Test if it gets values from the minion datastore ''' - self.assertEqual(data.getvals('salt', 'salt1'), ['SALT', 'SALT1']) + self.assertEqual(data.get(['salt', 'salt1']), ['SALT', 'SALT1']) # 'cas' function tests: 1 diff --git a/tests/unit/modules/glusterfs_test.py b/tests/unit/modules/glusterfs_test.py index 8ec4cd07f3bc..cabac4ad7578 100644 --- a/tests/unit/modules/glusterfs_test.py +++ b/tests/unit/modules/glusterfs_test.py @@ -147,6 +147,45 @@ """ +xml_peer_probe_success = """ + + + 0 + 0 + + + +""" + +xml_peer_probe_fail_already_member = """ + + + 0 + 2 + + Host salt port 24007 already in peer list + +""" + +xml_peer_probe_fail_localhost = """ + + + 0 + 1 + + Probe on localhost not needed + +""" + +xml_peer_probe_fail_cant_connect = """ + + + -1 + 107 + Probe returned with Transport endpoint is not connected + +""" + xml_command_success = """ @@ -190,9 +229,26 @@ def test_peer(self): ''' Test if it adds another node into the peer list. ''' - mock = MagicMock(return_value=xml_command_success) + + # Peers can be added successfully, already present, be the localhost, or not be connected. + mock = MagicMock(return_value=xml_peer_probe_success) + with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): + self.assertEqual(glusterfs.peer('salt'), + {'exitval': '0', 'output': None}) + + mock = MagicMock(return_value=xml_peer_probe_fail_already_member) + with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): + self.assertEqual(glusterfs.peer('salt'), + {'exitval': '0', 'output': 'Host salt port 24007 already in peer list'}) + + mock = MagicMock(return_value=xml_peer_probe_fail_localhost) + with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): + self.assertEqual(glusterfs.peer('salt'), + {'exitval': '0', 'output': 'Probe on localhost not needed'}) + + mock = MagicMock(return_value=xml_peer_probe_fail_cant_connect) with patch.dict(glusterfs.__salt__, {'cmd.run': mock}): - self.assertTrue(glusterfs.peer('salt')) + self.assertRaises(CommandExecutionError, glusterfs.peer, 'salt') mock = MagicMock(return_value=True) with patch.object(suc, 'check_name', mock): diff --git a/tests/unit/modules/s3_test.py b/tests/unit/modules/s3_test.py index 18b97ba0990d..cc5bb2790763 100644 --- a/tests/unit/modules/s3_test.py +++ b/tests/unit/modules/s3_test.py @@ -8,6 +8,7 @@ # Import Salt Testing Libs from salttesting import skipIf, TestCase from salttesting.mock import ( + MagicMock, NO_MOCK, NO_MOCK_REASON, patch @@ -21,12 +22,23 @@ import salt.utils.s3 from salt.modules import s3 +s3.__salt__ = {} + @skipIf(NO_MOCK, NO_MOCK_REASON) class S3TestCase(TestCase): - ''' - Test cases for salt.modules.s3 - ''' + def test__get_key_defaults(self): + mock = MagicMock(return_value='') + with patch.dict(s3.__salt__, {'config.option': mock}): + key, keyid, service_url, verify_ssl, kms_keyid, location, role_arn = ( + s3._get_key(None, None, None, None, None, None, None)) + self.assertEqual(None, role_arn) + self.assertEqual(None, key) + self.assertEqual(None, keyid) + self.assertEqual('s3.amazonaws.com', service_url) + self.assertEqual('', verify_ssl) + self.assertEqual('', location) + def test_delete(self): ''' Test for delete a bucket, or delete an object from a bucket. diff --git a/tests/unit/modules/ssh_test.py b/tests/unit/modules/ssh_test.py index c2f1e2e7a7fa..5c1ad66d9af2 100644 --- a/tests/unit/modules/ssh_test.py +++ b/tests/unit/modules/ssh_test.py @@ -34,6 +34,10 @@ def test_expand_user_token(self): '/home/user') self.assertEqual(output, '/home//home/user') + output = ssh._expand_authorized_keys_path('%h/foo', 'user', + '/home/user') + self.assertEqual(output, '/home/user/foo') + output = ssh._expand_authorized_keys_path('/srv/%h/aaa/%u%%', 'user', '/home/user') self.assertEqual(output, '/srv//home/user/aaa/user%') diff --git a/tests/unit/pillar/mysql_test.py b/tests/unit/pillar/mysql_test.py index f2f26c882151..e9ef6e17e3f5 100644 --- a/tests/unit/pillar/mysql_test.py +++ b/tests/unit/pillar/mysql_test.py @@ -20,7 +20,7 @@ class MysqlPillarTestCase(TestCase): def test_001_extract_queries_legacy(self): return_data = mysql.MySQLExtPillar() - args, kwargs = [], {'mysql_query': 'SELECT blah'} + args, kwargs = ['SELECT blah'], {} qbuffer = return_data.extract_queries(args, kwargs) self.assertEqual([ [None, {'query': 'SELECT blah', 'depth': 0, 'as_list': False, @@ -100,13 +100,10 @@ def test_004_extract_queries_mixed(self): ], { '1': 'SELECT blah1', '2': ('SELECT blah2', 2), - 'mysql_query': 'SELECT blahm', # In the middle for complexity '3': {'query': 'SELECT blah3', 'as_list': True}, } qbuffer = return_data.extract_queries(args, kwargs) self.assertEqual([ - [None, {'query': 'SELECT blahm', 'depth': 0, 'as_list': False, - 'with_lists': None, 'ignore_null': False}], [None, {'query': 'SELECT blah1', 'depth': 0, 'as_list': False, 'with_lists': None, 'ignore_null': False}], [None, {'query': 'SELECT blah2', 'depth': 2, 'as_list': False, diff --git a/tests/unit/runners/cache_test.py b/tests/unit/runners/cache_test.py index e63fa61b963c..2b1ef46bc82c 100644 --- a/tests/unit/runners/cache_test.py +++ b/tests/unit/runners/cache_test.py @@ -39,7 +39,6 @@ def test_grains(self): self.assertEqual(cache.grains(minion=mock_minion), mock_ret) mock_data = 'grain stuff' - mock_outputter = 'deprecated' class MockMaster(object): def __init__(self, *args, **kwargs): @@ -48,13 +47,8 @@ def __init__(self, *args, **kwargs): def get_minion_grains(self): return mock_data - mock_ret = {'outputter': mock_outputter, 'data': mock_data} with patch.object(salt.utils.master, 'MasterPillarUtil', MockMaster): - self.assertEqual(cache.grains(outputter=mock_outputter), mock_ret) - - mock_outputter = None - with patch.object(salt.utils.master, 'MasterPillarUtil', MockMaster): - self.assertEqual(cache.grains(outputter=mock_outputter), mock_data) + self.assertEqual(cache.grains(), mock_data) if __name__ == '__main__': diff --git a/tests/unit/states/alternatives_test.py b/tests/unit/states/alternatives_test.py index 9ce93e84e4ac..bb5dff40d011 100644 --- a/tests/unit/states/alternatives_test.py +++ b/tests/unit/states/alternatives_test.py @@ -52,7 +52,7 @@ def test_install(self): mock = MagicMock(side_effect=[True, False, False]) mock_bool = MagicMock(return_value=True) with patch.dict(alternatives.__salt__, - {'alternatives.check_exists': mock, + {'alternatives.check_installed': mock, 'alternatives.install': mock_bool}): comt = ('Alternatives for {0} is already set to {1}' ).format(name, path) diff --git a/tests/unit/states/glusterfs_test.py b/tests/unit/states/glusterfs_test.py index a7868385390b..9644664e7d27 100644 --- a/tests/unit/states/glusterfs_test.py +++ b/tests/unit/states/glusterfs_test.py @@ -67,15 +67,15 @@ def test_peered(self): with patch.object(socket, 'gethostname', MagicMock(side_effect=[name, 'salt.host', 'salt.host'])): - ret.update({'comment': [], 'result': True}) + ret.update({'comment': '', 'result': True}) self.assertDictEqual(glusterfs.peered(name), ret) comt = ('Host {0} already peered'.format(name)) - ret.update({'comment': [], 'result': True}) + ret.update({'comment': '', 'result': True}) self.assertDictEqual(glusterfs.peered(name), ret) comt = ('Host {0} already peered'.format(name)) - ret.update({'comment': [], 'result': True, + ret.update({'comment': '', 'result': True, 'changes': {'new': ['salt'], 'old': []}}) self.assertDictEqual(glusterfs.peered(name), ret) diff --git a/tests/unit/states/rabbitmq_vhost_test.py b/tests/unit/states/rabbitmq_vhost_test.py index 051998a90f8d..2953092eb4a5 100644 --- a/tests/unit/states/rabbitmq_vhost_test.py +++ b/tests/unit/states/rabbitmq_vhost_test.py @@ -39,11 +39,15 @@ def test_present(self): name = 'virtual_host' ret = {'name': name, +<<<<<<< HEAD <<<<<<< HEAD 'changes': {'new': 'virtual_host', 'old': ''}, ======= 'changes': {'old': '', 'new': name}, >>>>>>> de215bd0cdfdc4cee75939e821ff1492babd6ead +======= + 'changes': {'new': 'virtual_host', 'old': ''}, +>>>>>>> 15f5ae7454411c9a31799d256093b8ebe0f0b52b 'result': None, 'comment': 'Virtual Host \'virtual_host\' will be created.'} diff --git a/tests/unit/utils/gitfs_test.py b/tests/unit/utils/gitfs_test.py new file mode 100644 index 000000000000..165171b746c8 --- /dev/null +++ b/tests/unit/utils/gitfs_test.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +''' +These only test the provider selection and verification logic, they do not init +any remotes. +''' + +# Import python libs +from __future__ import absolute_import + +# Import Salt Testing libs +from salttesting import skipIf, TestCase +from salttesting.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON +from salttesting.helpers import ensure_in_syspath +ensure_in_syspath('../../') + +# Import salt libs +import salt.utils.gitfs +from salt.exceptions import FileserverConfigError + +# GLOBALS +OPTS = {'cachedir': '/tmp/gitfs-test-cache'} + + +@skipIf(NO_MOCK, NO_MOCK_REASON) +class TestGitFSProvider(TestCase): + + def test_provider_case_insensitive(self): + ''' + Ensure that both lowercase and non-lowercase values are supported + ''' + provider = 'GitPython' + for role_name, role_class in ( + ('gitfs', salt.utils.gitfs.GitFS), + ('git_pillar', salt.utils.gitfs.GitPillar), + ('winrepo', salt.utils.gitfs.WinRepo)): + + key = '{0}_provider'.format(role_name) + with patch.object(role_class, 'verify_gitpython', + MagicMock(return_value=True)): + with patch.object(role_class, 'verify_pygit2', + MagicMock(return_value=False)): + with patch.object(role_class, 'verify_dulwich', + MagicMock(return_value=False)): + args = [OPTS] + if role_name == 'winrepo': + args.append('/tmp/winrepo-dir') + with patch.dict(OPTS, {key: provider}): + # Try to create an instance with uppercase letters in + # provider name. If it fails then a + # FileserverConfigError will be raised, so no assert is + # necessary. + role_class(*args) + # Now try to instantiate an instance with all lowercase + # letters. Again, no need for an assert here. + role_class(*args) + + def test_valid_provider(self): + ''' + Ensure that an invalid provider is not accepted, raising a + FileserverConfigError. + ''' + def _get_mock(verify, provider): + ''' + Return a MagicMock with the desired return value + ''' + return MagicMock(return_value=verify.endswith(provider)) + + for role_name, role_class in ( + ('gitfs', salt.utils.gitfs.GitFS), + ('git_pillar', salt.utils.gitfs.GitPillar), + ('winrepo', salt.utils.gitfs.WinRepo)): + key = '{0}_provider'.format(role_name) + for provider in salt.utils.gitfs.VALID_PROVIDERS: + verify = 'verify_gitpython' + mock1 = _get_mock(verify, provider) + with patch.object(role_class, verify, mock1): + verify = 'verify_pygit2' + mock2 = _get_mock(verify, provider) + with patch.object(role_class, verify, mock2): + verify = 'verify_dulwich' + mock3 = _get_mock(verify, provider) + with patch.object(role_class, verify, mock3): + args = [OPTS] + if role_name == 'winrepo': + args.append('/tmp/winrepo-dir') + with patch.dict(OPTS, {key: provider}): + if role_name == 'gitfs' \ + or (role_name != 'gitfs' + and provider != 'dulwich'): + # This is a valid provider, so this should + # pass without raising an exception. + role_class(*args) + else: + # Dulwich is not supported for git_pillar nor + # winrepo, so trying to use it should raise an + # exception. + self.assertRaises( + FileserverConfigError, + role_class, + *args + ) + + with patch.dict(OPTS, {key: 'foo'}): + # Set the provider name to a known invalid provider + # and make sure it raises an exception. + self.assertRaises( + FileserverConfigError, + role_class, + *args + ) + + +if __name__ == '__main__': + from integration import run_tests + run_tests(TestGitFSProvider, needs_daemon=False) diff --git a/tests/unit/utils/utils_test.py b/tests/unit/utils/utils_test.py index 611bfce0ed4b..12f5ff0dd599 100644 --- a/tests/unit/utils/utils_test.py +++ b/tests/unit/utils/utils_test.py @@ -92,17 +92,6 @@ def test_ip_bracket(self): self.assertEqual(test_ipv4, utils.ip_bracket(test_ipv4)) self.assertEqual('[{0}]'.format(test_ipv6), utils.ip_bracket(test_ipv6)) - def test_jid_dir(self): - test_jid = 20131219110700123489 - test_cache_dir = '/tmp/cachdir' - test_hash_type = 'md5' - - expected_jid_dir = '/tmp/cachdir/jobs/69/fda308ccfa70d8296345e6509de136' - - ret = utils.jid.jid_dir(test_jid, test_cache_dir, test_hash_type) - - self.assertEqual(ret, expected_jid_dir) - def test_is_jid(self): self.assertTrue(utils.jid.is_jid('20131219110700123489')) # Valid JID self.assertFalse(utils.jid.is_jid(20131219110700123489)) # int