Merge pull request #26189 from basepi/merge-forward-develop

Merge forward from 2015.8 to develop
This commit is contained in:
Justin Findlay 2015-08-10 22:18:57 -06:00
commit fd70187176
81 changed files with 1864 additions and 647 deletions

View File

@ -3,13 +3,13 @@
# directory is identical.
#my-digitalocean-config:
# provider: digital_ocean
# driver: digital_ocean
# client_key: wFGEwgregeqw3435gDger
# api_key: GDE43t43REGTrkilg43934t34qT43t4dgegerGEgg
# location: New York 1
#my-aws-quick-start:
# provider: ec2
# driver: ec2
# id: HJGRYCILJLKJYG
# key: 'kdjgfsgm;woormgl/aserigjksjdhasdfgn'
# keyname: test
@ -17,7 +17,7 @@
# private_key: /root/test.pem
#my-aws-default:
# provider: ec2
# driver: ec2
# id: HJGRYCILJLKJYG
# key: 'kdjgfsgm;woormgl/aserigjksjdhasdfgn'
# keyname: test
@ -25,12 +25,12 @@
# private_key: /root/test.pem
#my-gogrid-config:
# provider: gogrid
# driver: gogrid
# apikey: asdff7896asdh789
# sharedsecret: saltybacon
#my-openstack-hp-config:
# provider: openstack
# driver: openstack
# identity_url: 'https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/'
# compute_name: Compute
# compute_region: 'az-1.region-a.geo-1'
@ -41,7 +41,7 @@
# password: mypass
#my-ibmsce-config:
# provider: ibmsce
# driver: ibmsce
# user: myuser@mycorp.com
# password: mypass
# ssh_key_name: mykey
@ -49,30 +49,30 @@
# location: Raleigh
#my-joyent-config:
# provider: joyent
# driver: joyent
# user: fred
# password: saltybacon
# private_key: /root/joyent.pem
#my-linode-config:
# provider: linode
# driver: linode
# apikey: asldkgfakl;sdfjsjaslfjaklsdjf;askldjfaaklsjdfhasldsadfghdkf
# password: F00barbaz
#my-parallels-config:
# provider: parallels
# driver: parallels
# user: myuser
# password: xyzzy
# url: https://api.cloud.xmission.com:4465/paci/v1.0/
#my-proxmox-config:
# provider: proxmox
# driver: proxmox
# user: saltcloud@pve
# password: xyzzy
# url: your.proxmox.host
#my-openstack-rackspace-config:
# provider: openstack
# driver: openstack
# identity_url: 'https://identity.api.rackspacecloud.com/v2.0/tokens'
# compute_name: cloudServersOpenStack
# protocol: ipv4
@ -83,4 +83,4 @@
# apikey: 901d3f579h23c8v73q9
#my-saltify-config:
# provider: saltify
# driver: saltify

View File

@ -1,5 +1,5 @@
#my-digitalocean-config:
# provider: digital_ocean
# driver: digital_ocean
# client_key: wFGEwgregeqw3435gDger
# api_key: GDE43t43REGTrkilg43934t34qT43t4dgegerGEgg
# location: New York 1

View File

@ -1,5 +1,5 @@
#my-aws-quick-start:
# provider: ec2
# driver: ec2
# id: HJGRYCILJLKJYG
# key: 'kdjgfsgm;woormgl/aserigjksjdhasdfgn'
# keyname: test
@ -7,7 +7,7 @@
# private_key: /root/test.pem
#my-aws-default:
# provider: ec2
# driver: ec2
# id: HJGRYCILJLKJYG
# key: 'kdjgfsgm;woormgl/aserigjksjdhasdfgn'
# keyname: test

View File

@ -1,4 +1,4 @@
#my-gogrid-config:
# provider: gogrid
# driver: gogrid
# apikey: asdff7896asdh789
# sharedsecret: saltybacon

View File

@ -1,5 +1,5 @@
#my-openstack-hp-config:
# provider: openstack
# driver: openstack
# identity_url: 'https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/'
# compute_name: Compute
# compute_region: 'az-1.region-a.geo-1'

View File

@ -1,5 +1,5 @@
#my-ibmsce-config:
# provider: ibmsce
# driver: ibmsce
# user: myuser@mycorp.com
# password: mypass
# ssh_key_name: mykey

View File

@ -1,5 +1,5 @@
#my-joyent-config:
# provider: joyent
# driver: joyent
# user: fred
# password: saltybacon
# private_key: /root/joyent.pem

View File

@ -1,4 +1,4 @@
#my-linode-config:
# provider: linode
# driver: linode
# apikey: asldkgfakl;sdfjsjaslfjaklsdjf;askldjfaaklsjdfhasldsadfghdkf
# password: F00barbaz

View File

@ -1,5 +1,5 @@
#my-parallels-config:
# provider: parallels
# driver: parallels
# user: myuser
# password: xyzzy
# url: https://api.cloud.xmission.com:4465/paci/v1.0/

View File

@ -1,6 +1,5 @@
#my-proxmox-config:
# provider: proxmox
# driver: proxmox
# user: saltcloud@pve
# password: xyzzy
# url: your.proxmox.host

View File

@ -1,5 +1,5 @@
#my-openstack-rackspace-config:
# provider: openstack
# driver: openstack
# identity_url: 'https://identity.api.rackspacecloud.com/v2.0/tokens'
# compute_name: cloudServersOpenStack
# protocol: ipv4

View File

@ -1,2 +1,2 @@
#my-saltify-config:
# provider: saltify
# driver: saltify

View File

@ -1,5 +1,5 @@
#my-vsphere-config:
# provider: vsphere
# driver: vsphere
# user: myuser
# password: verybadpass
# url: 'https://10.1.1.1:443'

View File

@ -1140,14 +1140,12 @@ Walkthrough <gitfs-per-remote-config>`.
.. versionadded:: 2014.7.0
Specify the provider to be used for gitfs. More information can be found in the
:ref:`GitFS Walkthrough <gitfs-dependencies>`.
Optional parameter used to specify the provider to be used for gitfs. More
information can be found in the :ref:`GitFS Walkthrough <gitfs-dependencies>`.
Specify one value among valid values: ``gitpython``, ``pygit2``, ``dulwich``
.. _pygit2: https://github.com/libgit2/pygit2
.. _GitPython: https://github.com/gitpython-developers/GitPython
.. _dulwich: https://www.samba.org/~jelmer/dulwich/
Must be one of the following: ``pygit2``, ``gitpython``, or ``dulwich``. If
unset, then each will be tried in that same order, and the first one with a
compatible version installed will be the provider that is used.
.. code-block:: yaml
@ -1160,11 +1158,11 @@ Specify one value among valid values: ``gitpython``, ``pygit2``, ``dulwich``
Default: ``True``
The ``gitfs_ssl_verify`` option specifies whether to ignore SSL certificate
errors when contacting the gitfs backend. You might want to set this to
``False`` if you're using a git backend that uses a self-signed certificate but
keep in mind that setting this flag to anything other than the default of
``True`` is a security concern, you may want to try using the ssh transport.
Specifies whether or not to ignore SSL certificate errors when contacting the
remote repository. You might want to set this to ``False`` if you're using a
git repo that uses a self-signed certificate. However, keep in mind that
setting this to anything other ``True`` is a considered insecure, and using an
SSH-based transport (if available) may be a better option.
.. code-block:: yaml
@ -1942,11 +1940,27 @@ ext_pillar.
ext_pillar_first: False
.. _git-pillar-config-opts:
.. _git_pillar-config-opts:
Git External Pillar (git_pillar) Configuration Options
------------------------------------------------------
.. conf_master:: git_pillar_provider
``git_pillar_provider``
***********************
.. versionadded:: 2015.8.0
Specify the provider to be used for git_pillar. Must be either ``pygit2`` or
``gitpython``. If unset, then both will be tried in that same order, and the
first one with a compatible version installed will be the provider that is
used.
.. code-block:: yaml
git_pillar_provider: gitpython
.. conf_master:: git_pillar_base
``git_pillar_base``
@ -2030,7 +2044,7 @@ environment irrespective of the branch/tag being used.
.. conf_master:: git_pillar_root
``git_pillar_root``
********************
*******************
.. versionadded:: 2015.8.0
@ -2077,23 +2091,23 @@ files would be looked for in a subdirectory called ``pillar``.
Default: ``True``
Specifies whether or not to ignore SSL certificate errors when contacting the
git_pillar remote repository. You might want to set this to ``False`` if you're
using a git backend that uses a self-signed certificate but keep in mind that
setting this flag to anything other than the default of ``True`` is a security
concern, you may want to try using the ssh transport.
remote repository. You might want to set this to ``False`` if you're using a
git repo that uses a self-signed certificate. However, keep in mind that
setting this to anything other ``True`` is a considered insecure, and using an
SSH-based transport (if available) may be a better option.
.. code-block:: yaml
git_pillar_ssl_verify: True
git_pillar Authentication Options
*********************************
Git External Pillar Authentication Options
******************************************
These parameters only currently apply to the pygit2 gitfs provider.
Authentication works the same as it does in gitfs, as outlined in the
:ref:`GitFS Walkthrough <gitfs-authentication>`, though the global
configuration options are named differently to reflect that they are for
git_pillar instead of gitfs.
These parameters only currently apply to the ``pygit2``
:conf_master:`git_pillar_provider`. Authentication works the same as it does
in gitfs, as outlined in the :ref:`GitFS Walkthrough <gitfs-authentication>`,
though the global configuration options are named differently to reflect that
they are for git_pillar instead of gitfs.
.. conf_master:: git_pillar_user
@ -2700,57 +2714,238 @@ option then the master will log a warning message.
- master.d/*
- /etc/roles/webserver
.. _winrepo-config-opts:
Windows Software Repo Settings
==============================
.. conf_master:: winrepo_provider
``winrepo_provider``
--------------------
.. versionadded:: 2015.8.0
Specify the provider to be used for winrepo. Must be either ``pygit2`` or
``gitpython``. If unset, then both will be tried in that same order, and the
first one with a compatible version installed will be the provider that is
used.
.. code-block:: yaml
winrepo_provider: gitpython
.. conf_master:: winrepo_dir
.. conf_master:: win_repo
``win_repo``
------------
``winrepo_dir``
---------------
.. versionchanged:: 2015.8.0
Renamed from ``win_repo`` to ``winrepo_dir``
Default: ``/srv/salt/win/repo``
Location of the repo on the master
Location on the master where the :conf_master:`winrepo_remotes` are checked
out.
.. code-block:: yaml
win_repo: '/srv/salt/win/repo'
winrepo_dir: /srv/salt/win/repo
.. conf_master:: winrepo_cachefile
.. conf_master:: win_repo_mastercachefile
``win_repo_mastercachefile``
----------------------------
``winrepo_cachefile``
---------------------
Default: ``/srv/salt/win/repo/winrepo.p``
.. versionchanged:: 2015.8.0
Renamed from ``win_repo_mastercachefile`` to ``winrepo_cachefile``
Default: ``winrepo.p``
Path relative to :conf_master:`winrepo_dir` where the winrepo cache should be
created.
.. code-block:: yaml
win_repo_mastercachefile: '/srv/salt/win/repo/winrepo.p'
winrepo_cachefile: winrepo.p
.. conf_master:: winrepo_remotes
.. conf_master:: win_gitrepos
``win_gitrepos``
----------------
``winrepo_remotes``
-------------------
.. versionchanged:: 2015.8.0
Renamed from ``win_gitrepos`` to ``winrepo_remotes``
Default: ``['https://github.com/saltstack/salt-winrepo.git']``
List of git repositories to checkout and include in the winrepo
.. code-block:: yaml
winrepo_remotes:
- https://github.com/saltstack/salt-winrepo.git
To specify a specific revision of the repository, prepend a commit ID to the
URL of the the repository:
.. code-block:: yaml
winrepo_remotes:
- '<commit_id> https://github.com/saltstack/salt-winrepo.git'
Replace ``<commit_id>`` with the SHA1 hash of a commit ID. Specifying a commit
ID is useful in that it allows one to revert back to a previous version in the
event that an error is introduced in the latest revision of the repo.
.. conf_master:: winrepo_branch
``winrepo_branch``
------------------
.. versionadded:: 2015.8.0
Default: ``master``
If the branch is omitted from a winrepo remote, then this branch will be
used instead. For example, in the configuration below, the first two remotes
would use the ``winrepo`` branch/tag, while the third would use the ``foo``
branch/tag.
.. code-block:: yaml
winrepo_branch: winrepo
ext_pillar:
- git:
- https://mygitserver/winrepo1.git
- https://mygitserver/winrepo2.git:
- foo https://mygitserver/winrepo3.git
.. conf_master:: winrepo_ssl_verify
``winrepo_ssl_verify``
----------------------
.. versionadded:: 2015.8.0
Default: ``True``
Specifies whether or not to ignore SSL certificate errors when contacting the
remote repository. You might want to set this to ``False`` if you're using a
git repo that uses a self-signed certificate. However, keep in mind that
setting this to anything other ``True`` is a considered insecure, and using an
SSH-based transport (if available) may be a better option.
.. code-block:: yaml
winrepo_ssl_verify: True
Winrepo Authentication Options
------------------------------
These parameters only currently apply to the ``pygit2``
:conf_master:`winrepo_provider`. Authentication works the same as it does in
gitfs, as outlined in the :ref:`GitFS Walkthrough <gitfs-authentication>`,
though the global configuration options are named differently to reflect that
they are for winrepo instead of gitfs.
.. conf_master:: winrepo_user
``winrepo_user``
****************
.. versionadded:: 2015.8.0
Default: ``''``
List of git repositories to include with the local repo.
Along with :conf_master:`winrepo_password`, is used to authenticate to HTTPS
remotes.
.. code-block:: yaml
win_gitrepos:
- 'https://github.com/saltstack/salt-winrepo.git'
winrepo_user: git
To specify a specific revision of the repository, preface the
repository location with a commit ID:
.. conf_master:: winrepo_password
``winrepo_password``
********************
.. versionadded:: 2015.8.0
Default: ``''``
Along with :conf_master:`winrepo_user`, is used to authenticate to HTTPS
remotes. This parameter is not required if the repository does not use
authentication.
.. code-block:: yaml
win_gitrepos:
- '<commit_id> https://github.com/saltstack/salt-winrepo.git'
winrepo_password: mypassword
Replacing ``<commit_id>`` with the ID from GitHub. Specifying a commit
ID is useful if you need to revert to a previous version if an error
is introduced in the latest version.
.. conf_master:: winrepo_insecure_auth
``winrepo_insecure_auth``
*************************
.. versionadded:: 2015.8.0
Default: ``False``
By default, Salt will not authenticate to an HTTP (non-HTTPS) remote. This
parameter enables authentication over HTTP. **Enable this at your own risk.**
.. code-block:: yaml
winrepo_insecure_auth: True
.. conf_master:: winrepo_pubkey
``winrepo_pubkey``
******************
.. versionadded:: 2015.8.0
Default: ``''``
Along with :conf_master:`winrepo_privkey` (and optionally
:conf_master:`winrepo_passphrase`), is used to authenticate to SSH remotes.
.. code-block:: yaml
winrepo_pubkey: /path/to/key.pub
.. conf_master:: winrepo_privkey
``winrepo_privkey``
*******************
.. versionadded:: 2015.8.0
Default: ``''``
Along with :conf_master:`winrepo_pubkey` (and optionally
:conf_master:`winrepo_passphrase`), is used to authenticate to SSH remotes.
.. code-block:: yaml
winrepo_privkey: /path/to/key
.. conf_master:: winrepo_passphrase
``winrepo_passphrase``
**********************
.. versionadded:: 2015.8.0
Default: ``''``
This parameter is optional, required only when the SSH key being used to
authenticate is protected by a passphrase.
.. code-block:: yaml
winrepo_passphrase: mypassphrase

View File

@ -1207,3 +1207,75 @@ have other services that need to go with it.
.. code-block:: yaml
update_restart_services: ['salt-minion']
Windows Software Repo Settings
==============================
.. important::
To use these config options, the minion must be running in masterless mode
(set :conf_minion:`file_client` to ``local``).
.. conf_minion:: winrepo_dir
.. conf_minion:: win_repo
``winrepo_dir``
---------------
.. versionchanged:: 2015.8.0
Renamed from ``win_repo`` to ``winrepo_dir``
Default: ``c:\\salt\\file_roots\\winrepo``
Location on the minion where the :conf_minion:`winrepo_remotes` are checked
out.
.. code-block:: yaml
winrepo_dir: /srv/salt/win/repo
.. conf_minion:: winrepo_cachefile
``winrepo_cachefile``
---------------------
.. versionchanged:: 2015.8.0
Renamed from ``win_repo_mastercachefile`` to ``winrepo_cachefile``
Default: ``winrepo.p``
Path relative to :conf_minion:`winrepo_dir` where the winrepo cache should be
created.
.. code-block:: yaml
winrepo_cachefile: winrepo.p
.. conf_minion:: winrepo_remotes
.. conf_minion:: win_gitrepos
``winrepo_remotes``
-------------------
.. versionadded:: 2015.8.0
Default: ``['https://github.com/saltstack/salt-winrepo.git']``
List of git repositories to checkout and include in the winrepo
.. code-block:: yaml
winrepo_remotes:
- https://github.com/saltstack/salt-winrepo.git
To specify a specific revision of the repository, prepend a commit ID to the
URL of the the repository:
.. code-block:: yaml
winrepo_remotes:
- '<commit_id> https://github.com/saltstack/salt-winrepo.git'
Replace ``<commit_id>`` with the SHA1 hash of a commit ID. Specifying a commit
ID is useful in that it allows one to revert back to a previous version in the
event that an error is introduced in the latest revision of the repo.

View File

@ -93,8 +93,25 @@ A State Module must return a dict containing the following keys/values:
containing the old/new values. For example, the pkg state's **changes** dict
has one key for each package changed, with the "old" and "new" keys in its
sub-dict containing the old and new versions of the package.
- **result:** A boolean value. *True* if the action was successful, otherwise
*False*.
- **result:** A tristate value. ``True`` if the action was successful,
``False`` if it was not, or ``None`` if the state was run in test mode,
``test=True``, and changes would have been made if the state was not run in
test mode.
+--------------------+-----------+-----------+
| | live mode | test mode |
+====================+===========+===========+
| no changes | ``True`` | ``True`` |
+--------------------+-----------+-----------+
| successful changes | ``True`` | ``None`` |
+--------------------+-----------+-----------+
| failed changes | ``False`` | ``None`` |
+--------------------+-----------+-----------+
.. note::
Test mode does not predict if the changes will be successful or not.
- **comment:** A string containing a summary of the result.
The return data can also, include the **pchanges** key, this statnds for

View File

@ -3,7 +3,7 @@ Getting Started With Aliyun ECS
===============================
The Aliyun ECS (Elastic Computer Service) is one of the most popular public
cloud providers in China. This cloud provider can be used to manage aliyun
cloud hosts in China. This cloud host can be used to manage aliyun
instance using salt-cloud.
http://www.aliyun.com/
@ -34,6 +34,14 @@ under "My Service" tab.
location: cn-qingdao
driver: aliyun
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========
@ -46,7 +54,7 @@ Set up an initial profile at ``/etc/salt/cloud.profiles`` or in the
.. code-block:: yaml
aliyun_centos:
driver: my-aliyun-config
provider: my-aliyun-config
size: ecs.t1.small
location: cn-qingdao
securitygroup: G1989096784427999
@ -161,4 +169,4 @@ for the ``salt-cloud`` command:
.. note::
Aliyun ECS REST API documentation is available from `Aliyun ECS API <http://help.aliyun.com/list/11113464.html?spm=5176.7224429.1997282881.55.J9XhVL>`_.
Aliyun ECS REST API documentation is available from `Aliyun ECS API <http://help.aliyun.com/list/11113464.html?spm=5176.7224429.1997282881.55.J9XhVL>`_.

View File

@ -5,9 +5,9 @@ Getting Started With AWS EC2
Amazon EC2 is a very widely used public cloud platform and one of the core
platforms Salt Cloud has been built to support.
Previously, the suggested provider for AWS EC2 was the ``aws`` provider. This
has been deprecated in favor of the ``ec2`` provider. Configuration using the
old ``aws`` provider will still function, but that driver is no longer in
Previously, the suggested driver for AWS EC2 was the ``aws`` driver. This
has been deprecated in favor of the ``ec2`` driver. Configuration using the
old ``aws`` driver will still function, but that driver is no longer in
active development.
@ -146,6 +146,14 @@ parameters are discussed in more detail below.
driver: ec2
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Access Credentials
==================

View File

@ -65,6 +65,14 @@ tab within the "Settings" section of the management portal.
Optionally, a ``management_host`` may be configured, if necessary for the region.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Cloud Profiles
==============

View File

@ -19,7 +19,7 @@ Assuming there is a profile configured as following:
.. code-block:: bash
fedora_rackspace:
provider: rackspace
provider: my-rackspace-config
image: Fedora 17
size: 256 server
script: bootstrap-salt
@ -43,4 +43,4 @@ For example, to delete the VM created on above example, use:
.. code-block:: bash
salt-cloud -d fedora_http_01
salt-cloud -d fedora_http_01

View File

@ -1,24 +1,24 @@
==============================
Writing Cloud Provider Modules
==============================
============================
Writing Cloud Driver Modules
============================
Salt Cloud runs on a module system similar to the main Salt project. The
modules inside saltcloud exist in the ``salt/cloud/clouds`` directory of the
salt source.
There are two basic types of cloud modules. If a cloud provider is supported by
There are two basic types of cloud modules. If a cloud host is supported by
libcloud, then using it is the fastest route to getting a module written. The
Apache Libcloud project is located at:
http://libcloud.apache.org/
Not every cloud provider is supported by libcloud. Additionally, not every
feature in a supported cloud provider is necessary supported by libcloud. In
Not every cloud host is supported by libcloud. Additionally, not every
feature in a supported cloud host is necessarily supported by libcloud. In
either of these cases, a module can be created which does not rely on libcloud.
All Modules
===========
The following functions are required by all modules, whether or not they are
All Driver Modules
==================
The following functions are required by all driver modules, whether or not they are
based on libcloud.
The __virtual__() Function
@ -51,17 +51,17 @@ The create() Function
---------------------
The most important function that does need to be manually written is the
``create()`` function. This is what is used to request a virtual machine to be
created by the cloud provider, wait for it to become available, and then
created by the cloud host, wait for it to become available, and then
(optionally) log in and install Salt on it.
A good example to follow for writing a cloud provider module based on libcloud
A good example to follow for writing a cloud driver module based on libcloud
is the module provided for Linode:
https://github.com/saltstack/salt/tree/develop/salt/cloud/clouds/linode.py
The basic flow of a ``create()`` function is as follows:
* Send a request to the cloud provider to create a virtual machine.
* Send a request to the cloud host to create a virtual machine.
* Wait for the virtual machine to become available.
* Generate kwargs to be used to deploy Salt.
* Log into the virtual machine and deploy Salt.
@ -80,20 +80,20 @@ configuration and environment variables.
The first thing the ``create()`` function must do is fire an event stating that
it has started the create process. This event is tagged
``salt/cloud/<vm name>/creating``. The payload contains the names of the VM,
profile and provider.
profile, and provider.
A set of kwargs is then usually created, to describe the parameters required
by the cloud provider to request the virtual machine.
by the cloud host to request the virtual machine.
An event is then fired to state that a virtual machine is about to be requested.
It is tagged as ``salt/cloud/<vm name>/requesting``. The payload contains most
or all of the parameters that will be sent to the cloud provider. Any private
or all of the parameters that will be sent to the cloud host. Any private
information (such as passwords) should not be sent in the event.
After a request is made, a set of deploy kwargs will be generated. These will
be used to install Salt on the target machine. Windows options are supported
at this point, and should be generated, even if the cloud provider does not
currently support Windows. This will save time in the future if the provider
at this point, and should be generated, even if the cloud host does not
currently support Windows. This will save time in the future if the host
does eventually decide to support Windows.
An event is then fired to state that the deploy process is about to begin. This
@ -118,12 +118,12 @@ manager. These do not need to be handled by the developer in the cloud module.
The ``salt.utils.cloud.validate_windows_cred()`` function has been extended to
take the number of retries and retry_delay parameters in case a specific cloud
provider has a delay between providing the Windows credentials and the
host has a delay between providing the Windows credentials and the
credentials being available for use. In their ``create()`` function, or as a
a sub-function called during the creation process, developers should use the
``win_deploy_auth_retries`` and ``win_deploy_auth_retry_delay`` parameters from
the provider configuration to allow the end-user the ability to customize the
number of tries and delay between tries for their particular provider.
number of tries and delay between tries for their particular host.
After the appropriate deploy function completes, a final event is fired
which describes the virtual machine that has just been created. This event is
@ -133,13 +133,13 @@ VM, profile, and provider.
Finally, a dict (queried from the provider) which describes the new virtual
machine is returned to the user. Because this data is not fired on the event
bus it can, and should, return any passwords that were returned by the cloud
provider. In some cases (for example, Rackspace), this is the only time that
host. In some cases (for example, Rackspace), this is the only time that
the password can be queried by the user; post-creation queries may not contain
password information (depending upon the provider).
password information (depending upon the host).
The libcloudfuncs Functions
---------------------------
A number of other functions are required for all cloud providers. However, with
A number of other functions are required for all cloud hosts. However, with
libcloud-based modules, these are all provided for free by the libcloudfuncs
library. The following two lines set up the imports:
@ -181,7 +181,7 @@ required by the developer. When this is the case, some or all of the functions
in ``libcloudfuncs`` may be replaced. If they are all replaced, the libcloud
imports should be absent from the Salt Cloud module.
A good example of a non-libcloud provider is the DigitalOcean module:
A good example of a non-libcloud driver is the DigitalOcean driver:
https://github.com/saltstack/salt/tree/develop/salt/cloud/clouds/digital_ocean.py
@ -202,8 +202,8 @@ to exist otherwise.
The avail_locations() Function
------------------------------
This function returns a list of locations available, if the cloud provider uses
multiple data centers. It is not necessary if the cloud provider only uses one
This function returns a list of locations available, if the cloud host uses
multiple data centers. It is not necessary if the cloud host uses only one
data center. It is normally called using the ``--list-locations`` option.
.. code-block:: bash

View File

@ -45,7 +45,7 @@ Cloud Configuration Syntax
The data specific to interacting with public clouds is set up here.
Cloud provider configuration syntax can live in several places. The first is in
Cloud provider configuration settings can live in several places. The first is in
``/etc/salt/cloud``:
.. code-block:: yaml
@ -171,13 +171,13 @@ minion. In your pillar file, you would use something like this:
profiles:
ubuntu-nova:
driver: my-nova
provider: my-nova
size: performance1-8
image: bb02b1a3-bc77-4d17-ab5b-421d89850fca
script_args: git develop
ubuntu-openstack:
driver: my-openstack
provider: my-openstack
size: performance1-8
image: bb02b1a3-bc77-4d17-ab5b-421d89850fca
script_args: git develop
@ -217,7 +217,7 @@ Rackspace cloud requires two configuration options; a ``user`` and an ``apikey``
my-rackspace-config:
user: example_user
apikey: 123984bjjas87034
driver: rackspace-config
driver: rackspace
.. note::
@ -444,7 +444,7 @@ Proxmox
-------
Using Salt with Proxmox requires a ``user``, ``password``, and ``URL``. These can be
obtained from your cloud provider. Both PAM and PVE users can be used.
obtained from your cloud host. Both PAM and PVE users can be used.
.. code-block:: yaml
@ -478,7 +478,7 @@ And in the map file:
.. code-block:: yaml
devhost10-lxc:
driver: devhost10-lxc
provider: devhost10-lxc
from_container: ubuntu
backing: lvm
sudo: True

View File

@ -75,7 +75,7 @@ test.ping. This is configured in the main cloud config file:
This is currently considered to be experimental functionality, and may not work
well with all providers. If you experience problems with Salt Cloud hanging
well with all cloud hosts. If you experience problems with Salt Cloud hanging
after Salt is deployed, consider using Startup States instead:
http://docs.saltstack.com/ref/states/startup.html
@ -114,7 +114,7 @@ Or even on the VM's profile settings:
.. code-block:: yaml
ubuntu_aws:
provider: ec2
provider: my-ec2-config
image: ami-7e2da54e
size: t1.micro
deploy: False
@ -174,7 +174,7 @@ to pass arguments to the deploy script:
.. code-block:: yaml
aws-amazon:
provider: ec2
provider: my-ec2-config
image: ami-1624987f
size: t1.micro
ssh_username: ec2-user
@ -186,4 +186,4 @@ This has also been tested to work with pipes, if needed:
.. code-block:: yaml
script_args: | head
script_args: | head

View File

@ -2,7 +2,7 @@
Getting Started With DigitalOcean
=================================
DigitalOcean is a public cloud provider that specializes in Linux instances.
DigitalOcean is a public cloud host that specializes in Linux instances.
Configuration
@ -25,6 +25,14 @@ under the "SSH Keys" section.
ssh_key_names: my-key-name,my-key-name-2
location: New York 1
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -4,23 +4,23 @@
Feature Matrix
==============
A number of features are available in most cloud providers, but not all are
A number of features are available in most cloud hosts, but not all are
available everywhere. This may be because the feature isn't supported by the
cloud provider itself, or it may only be that the feature has not yet been
cloud host itself, or it may only be that the feature has not yet been
added to Salt Cloud. In a handful of cases, it is because the feature does not
make sense for a particular cloud provider (Saltify, for instance).
This matrix shows which features are available in which cloud providers, as far
This matrix shows which features are available in which cloud hosts, as far
as Salt Cloud is concerned. This is not a comprehensive list of all features
available in all cloud providers, and should not be used to make business
decisions concerning choosing a cloud provider. In most cases, adding support
available in all cloud hosts, and should not be used to make business
decisions concerning choosing a cloud host. In most cases, adding support
for a feature to Salt Cloud requires only a little effort.
Legacy Drivers
==============
Both AWS and Rackspace are listed as "Legacy". This is because those drivers
have been replaced by other drivers, which are generally the preferred method
for working with those providers.
for working with those hosts.
The EC2 driver should be used instead of the AWS driver, when possible. The
OpenStack driver should be used instead of the Rackspace driver, unless the user
@ -28,13 +28,13 @@ is dealing with instances in "the old cloud" in Rackspace.
Note for Developers
===================
When adding new features to a particular cloud provider, please make sure to
When adding new features to a particular cloud host, please make sure to
add the feature to this table. Additionally, if you notice a feature that is not
properly listed here, pull requests to fix them is appreciated.
Standard Features
=================
These are features that are available for almost every provider.
These are features that are available for almost every cloud host.
.. container:: scrollable
@ -199,4 +199,4 @@ require the name of the provider to be passed in. For example:
|show_keypair | | |Yes |Yes| | | | | | | | | | |
+-----------------------+--------+----------+-------+---+------+------+------+---------+---------+---------+-------+---------+---------+------+
|show_volume | | | |Yes| | | | | | | | | |Yes |
+-----------------------+--------+----------+-------+---+------+------+------+---------+---------+---------+-------+---------+---------+------+
+-----------------------+--------+----------+-------+---+------+------+------+---------+---------+---------+-------+---------+---------+------+

View File

@ -113,6 +113,14 @@ Set up the cloud config at ``/etc/salt/cloud``:
The value provided for ``project`` must not contain underscores or spaces and
is labeled as "Project ID" on the Google Developers Console.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Cloud Profiles
==============

View File

@ -2,7 +2,7 @@
Getting Started With GoGrid
===========================
GoGrid is a public cloud provider supporting Linux and Windows.
GoGrid is a public cloud host that supports Linux and Windows.
Configuration
@ -32,6 +32,14 @@ in the configuration file to enable interfacing with GoGrid:
with the GoGrid driver. Map files will work with GoGrid, but the ``-P``
argument should not be used on maps referencing GoGrid instances.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -50,6 +50,14 @@ provider configuration file as in the example shown below:
The subsequent example that follows is using the openstack driver.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Compute Region
==============
@ -164,4 +172,4 @@ The example below is a modified version of the previous example. Note the use of
ssh_username: ubuntu
ssh_interface: private_ips
With this setup, salt-cloud will use the private IP address to ssh into the instance and set up the salt-minion
With this setup, salt-cloud will use the private IP address to ssh into the instance and set up the salt-minion

View File

@ -1,7 +1,7 @@
<row class="intro-row">
<div class="col-sm-4">
<div class="intro-text">Provision systems on cloud providers / hypervisors and immediately bring them under management.</div>
<div class="intro-text">Provision systems on cloud hosts / hypervisors and immediately bring them under management.</div>
</div>
<div class="col-sm-8">

View File

@ -15,9 +15,9 @@ Salt Cloud is built-in to Salt and is configured on and executed from your Salt
Define a Provider
-----------------
The first step is to add the credentials for your cloud provider. Credentials
and provider settings are stored in provider configuration files.
Provider configurations contain the details needed to connect to a cloud provider such as EC2, GCE, Rackspace, etc.,
The first step is to add the credentials for your cloud host. Credentials
and other settings provided by the cloud host are stored in provider configuration files.
Provider configurations contain the details needed to connect to a cloud host such as EC2, GCE, Rackspace, etc.,
and any global options that you want set on your cloud minions (such as the location of your Salt Master).
On your Salt Master, browse to ``/etc/salt/cloud.providers.d/`` and create a file called ``<provider>.provider.conf``,
@ -25,7 +25,7 @@ replacing ``<provider>`` with ``ec2``, ``softlayer``, and so on. The name helps
important as long as the file ends in ``.conf``.
Next, browse to the :ref:`Provider specifics <cloud-provider-specifics>` and add any required settings for your
provider to this file. Here is an example for Amazon EC2:
cloud host to this file. Here is an example for Amazon EC2:
.. code-block:: yaml
@ -45,7 +45,7 @@ provider to this file. Here is an example for Amazon EC2:
minion:
master: saltmaster.example.com
The required configuration varies between providers so make sure you read the provider specifics.
The required configuration varies between cloud hosts so make sure you read the provider specifics.
List Cloud Provider Options
---------------------------

View File

@ -2,7 +2,7 @@
Getting Started With Joyent
===========================
Joyent is a public cloud provider supporting SmartOS, Linux, FreeBSD, and
Joyent is a public cloud host that supports SmartOS, Linux, FreeBSD, and
Windows.
@ -30,6 +30,14 @@ send the provisioning commands up to the freshly created virtual machine.
private_key: /root/mykey.pem
keyname: mykey
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -2,7 +2,7 @@
Getting Started With Linode
===========================
Linode is a public cloud provider with a focus on Linux instances.
Linode is a public cloud host with a focus on Linux instances.
Starting with the 2015.8.0 release of Salt, the Linode driver uses Linode's
native REST API. There are no external dependencies required to use the
@ -28,6 +28,15 @@ instances also needs to be set:
The password needs to be 8 characters and contain lowercase, uppercase, and
numbers.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -23,10 +23,6 @@ Limitations
- Listing images must be targeted to a particular LXC provider (nothing will be
outputted with ``all``)
.. warning::
On pre **2015.5.2**, you need to specify explitly the network bridge
Operation
---------
@ -62,6 +58,15 @@ Here is a simple provider configuration:
target: devhost10
driver: lxc
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profile configuration
---------------------

View File

@ -14,7 +14,7 @@ to pass arguments to the deploy script:
.. code-block:: yaml
ec2-amazon:
provider: ec2
provider: my-ec2-config
image: ami-1624987f
size: t1.micro
ssh_username: ec2-user
@ -95,7 +95,7 @@ Delete SSH Keys
===============
When Salt Cloud deploys an instance, the SSH pub key for the instance is added
to the known_hosts file for the user that ran the salt-cloud command. When an
instance is deployed, a cloud provider generally recycles the IP address for
instance is deployed, a cloud host generally recycles the IP address for
the instance. When Salt Cloud attempts to deploy an instance using a recycled
IP address that has previously been accessed from the same machine, the old key
in the known_hosts file will cause a conflict.
@ -161,7 +161,7 @@ wait_for_ip_timeout
~~~~~~~~~~~~~~~~~~~
The amount of time Salt Cloud should wait for a VM to start and get an IP back
from the cloud provider.
from the cloud host.
Default: varies by cloud provider ( between 5 and 25 minutes)
@ -232,7 +232,7 @@ diff_cache_events
~~~~~~~~~~~~~~~~~
When the cloud cachedir is being managed, if differences are encountered
between the data that is returned live from the cloud provider and the data in
between the data that is returned live from the cloud host and the data in
the cache, fire events which describe the changes. This setting can be True or
False.
@ -251,20 +251,20 @@ The following are events that can be fired based on this data.
salt/cloud/minionid/cache_node_new
**********************************
A new node was found on the cloud provider which was not listed in the cloud
A new node was found on the cloud host which was not listed in the cloud
cachedir. A dict describing the new node will be contained in the event.
salt/cloud/minionid/cache_node_missing
**************************************
A node that was previously listed in the cloud cachedir is no longer available
on the cloud provider.
on the cloud host.
salt/cloud/minionid/cache_node_diff
***********************************
One or more pieces of data in the cloud cachedir has changed on the cloud
provider. A dict containing both the old and the new data will be contained in
host. A dict containing both the old and the new data will be contained in
the event.

View File

@ -46,6 +46,14 @@ Configuration
# skip SSL certificate validation (default false)
insecure: false
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Using nova client to get information from OpenStack
===================================================

View File

@ -4,7 +4,7 @@ Getting Started With Parallels
Parallels Cloud Server is a product by Parallels that delivers a cloud hosting
solution. The PARALLELS module for Salt Cloud enables you to manage instances
hosted by a provider using PCS. Further information can be found at:
hosted using PCS. Further information can be found at:
http://www.parallels.com/products/pcs/
@ -22,7 +22,7 @@ http://www.parallels.com/products/pcs/
PARALLELS.user: myuser
PARALLELS.password: badpass
# Set the access URL for your PARALLELS provider
# Set the access URL for your PARALLELS host
#
PARALLELS.url: https://api.cloud.xmission.com:4465/paci/v1.0/
@ -49,12 +49,19 @@ http://www.parallels.com/products/pcs/
url: https://api.cloud.xmission.com:4465/paci/v1.0/
driver: parallels
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Access Credentials
==================
The ``user``, ``password``, and ``url`` will be provided to you by your cloud
provider. These are all required in order for the PARALLELS driver to work.
host. These are all required in order for the PARALLELS driver to work.
Cloud Profiles
@ -62,34 +69,19 @@ Cloud Profiles
Set up an initial profile at ``/etc/salt/cloud.profiles`` or
``/etc/salt/cloud.profiles.d/parallels.conf``:
* Using the old cloud configuration format:
.. code-block:: yaml
parallels-ubuntu:
provider: parallels
image: ubuntu-12.04-x86_64
* Using the new cloud configuration format and the cloud configuration example
from above:
.. code-block:: yaml
parallels-ubuntu:
provider: my-parallels-config
image: ubuntu-12.04-x86_64
The profile can be realized now with a salt command:
.. code-block:: bash
# salt-cloud -p parallels-ubuntu myubuntu
This will create an instance named ``myubuntu`` on the cloud provider. The
This will create an instance named ``myubuntu`` on the cloud host. The
minion that is installed on this instance will have an ``id`` of ``myubuntu``.
If the command was executed on the salt-master, its Salt key will automatically
be signed on the master.
@ -131,8 +123,8 @@ Optional Settings
=================
Unlike other cloud providers in Salt Cloud, Parallels does not utilize a
``size`` setting. This is because Parallels allows the end-user to specify a
more detailed configuration for their instances, than is allowed by many other
cloud providers. The following options are available to be used in a profile,
more detailed configuration for their instances than is allowed by many other
cloud hosts. The following options are available to be used in a profile,
with their default settings listed.
.. code-block:: yaml

View File

@ -8,7 +8,7 @@ a yaml configuration. The syntax for declaring profiles is simple:
.. code-block:: yaml
fedora_rackspace:
provider: rackspace
provider: my-rackspace-config
image: Fedora 17
size: 256 server
script: bootstrap-salt
@ -18,12 +18,12 @@ and does not normally need to be specified. Further examples in this document
will not show the ``script`` option.
A few key pieces of information need to be declared and can change based on the
public cloud provider. A number of additional parameters can also be inserted:
cloud provider. A number of additional parameters can also be inserted:
.. code-block:: yaml
centos_rackspace:
driver: rackspace
provider: my-rackspace-config
image: CentOS 6.2
size: 1024 server
minion:
@ -66,44 +66,44 @@ Larger Example
.. code-block:: yaml
rhel_ec2:
provider: ec2
provider: my-ec2-config
image: ami-e565ba8c
size: t1.micro
minion:
cheese: edam
ubuntu_ec2:
provider: ec2
provider: my-ec2-config
image: ami-7e2da54e
size: t1.micro
minion:
cheese: edam
ubuntu_rackspace:
provider: rackspace
provider: my-rackspace-config
image: Ubuntu 12.04 LTS
size: 256 server
minion:
cheese: edam
fedora_rackspace:
provider: rackspace
provider: my-rackspace-config
image: Fedora 17
size: 256 server
minion:
cheese: edam
cent_linode:
provider: linode
provider: my-linode-config
image: CentOS 6.2 64bit
size: Linode 512
cent_gogrid:
provider: gogrid
provider: my-gogrid-config
image: 12834
size: 512MB
cent_joyent:
provider: joyent
provider: my-joyent-config
image: centos-6
size: Small 1GB
size: Small 1GB

View File

@ -34,17 +34,24 @@ done when the VM is an OpenVZ container rather than a KVM virtual machine.
user: myuser@pve
password: badpass
# Set the access URL for your PROXMOX provider
# Set the access URL for your PROXMOX host
#
url: your.proxmox.host
driver: proxmox
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Access Credentials
==================
The ``user``, ``password``, and ``url`` will be provided to you by your cloud
provider. These are all required in order for the PROXMOX driver to work.
host. These are all required in order for the PROXMOX driver to work.
Cloud Profiles
@ -57,7 +64,7 @@ Set up an initial profile at ``/etc/salt/cloud.profiles`` or
.. code-block:: yaml
proxmox-ubuntu:
provider: proxmox
provider: my-proxmox-config
image: local:vztmpl/ubuntu-12.04-standard_12.04-1_amd64.tar.gz
technology: openvz
host: myvmhost
@ -71,7 +78,7 @@ The profile can be realized now with a salt command:
# salt-cloud -p proxmox-ubuntu myubuntu
This will create an instance named ``myubuntu`` on the cloud provider. The
This will create an instance named ``myubuntu`` on the cloud host. The
minion that is installed on this instance will have a ``hostname`` of ``myubuntu``.
If the command was executed on the salt-master, its Salt key will automatically
be signed on the master.

View File

@ -5,7 +5,7 @@ Getting Started With Rackspace
Rackspace is a major public cloud platform which may be configured using either
the `rackspace` or the `openstack` driver, depending on your needs.
Please note that the `rackspace` driver is only intended for 1st gen instances,
Please note that the `rackspace` driver is intended only for 1st gen instances,
aka, "the old cloud" at Rackspace. It is required for 1st gen instances, but
will *not* work with OpenStack-based instances. Unless you explicitly have a
reason to use it, it is highly recommended that you use the `openstack` driver
@ -66,6 +66,14 @@ To use the `rackspace` driver, set up the cloud configuration at
The settings that follow are for using Rackspace with the `openstack` driver,
and will not work with the `rackspace` driver.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Compute Region
==============
@ -172,10 +180,10 @@ configuration please add:
force_first_gen: True
Private Subnets
--------------------------------
By default salt-cloud will not add Rackspace private networks to new servers. To enable
---------------
By default salt-cloud will not add Rackspace private networks to new servers. To enable
a private network to a server instantiated by salt cloud, add the following section
to the provider file (typically ``/etc/salt/cloud.providers.d/rackspace.conf``)
to the provider file (typically ``/etc/salt/cloud.providers.d/rackspace.conf``)
.. code-block:: yaml

View File

@ -34,8 +34,7 @@ using the ``ec2-config`` provider, the payload for this tag would look like:
{'name': 'web1',
'profile': 'ec2-centos',
'provider': 'ec2-config'}
'provider': 'ec2-config:ec2'}
Available Events
================
@ -206,11 +205,11 @@ options that can be specified is ``startup_states``, which is commonly set to
``highstate``. This will tell the minion to immediately apply a highstate, as
soon as it is able to do so.
This can present a problem with some system images on some cloud providers. For
This can present a problem with some system images on some cloud hosts. For
instance, Salt Cloud can be configured to log in as either the ``root`` user, or
a user with ``sudo`` access. While some providers commonly use images that
a user with ``sudo`` access. While some hosts commonly use images that
lock out remote ``root`` access and require a user with ``sudo`` privileges to
log in (notably EC2, with their ``ec2-user`` login), most cloud providers fall
log in (notably EC2, with their ``ec2-user`` login), most cloud hosts fall
back to ``root`` as the default login on all images, including for operating
systems (such as Ubuntu) which normally disallow remote ``root`` login.
@ -245,4 +244,4 @@ Because this event will not be fired until Salt Cloud has cleaned up after
itself, the highstate run will not step on Salt Cloud's toes. And because every
file on the minion is configurable, including ``/etc/salt/minion``, the
``startup_states`` can still be configured for future minion restarts, if
desired.
desired.

View File

@ -238,7 +238,7 @@ presence of the instance will be managed statefully.
my-instance-name:
cloud.present:
- driver: my-ec2-config
- provider: my-ec2-config
- image: ami-1624987f
- size: 't1.micro'
- ssh_username: ec2-user

View File

@ -2,7 +2,7 @@
Getting Started With Scaleway
=============================
Scaleway is the first IaaS provider worldwide to offer an ARM based cloud. Its the ideal platform for horizontal scaling with BareMetal SSD servers. The solution provides on demand resources: it comes with on-demand SSD storage, movable IPs , images, security group and an Object Storage solution. https://scaleway.com
Scaleway is the first IaaS host worldwide to offer an ARM based cloud. Its the ideal platform for horizontal scaling with BareMetal SSD servers. The solution provides on demand resources: it comes with on-demand SSD storage, movable IPs , images, security group and an Object Storage solution. https://scaleway.com
Configuration
=============
@ -21,6 +21,15 @@ If you do not have API token you can create one by clicking the "Create New Toke
token: a7347ec8-5de1-4024-a5e3-24b77d1ba91d
driver: scaleway
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -2,7 +2,7 @@
Getting Started With SoftLayer
==============================
SoftLayer is a public cloud provider, and baremetal hardware hosting provider.
SoftLayer is a public cloud host, and baremetal hardware hosting service.
Dependencies
============
@ -50,6 +50,14 @@ Set up the cloud config at ``/etc/salt/cloud.providers``:
driver: softlayer_hw
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Access Credentials
==================
@ -384,7 +392,7 @@ The `globalIdentifier` returned in this list is necessary for the
Optional Products for SoftLayer HW
==================================
The softlayer_hw provider supports the ability to add optional products, which
The softlayer_hw driver supports the ability to add optional products, which
are supported by SoftLayer's API. These products each have an ID associated with
them, that can be passed into Salt Cloud with the `optional_products` option:

View File

@ -83,7 +83,7 @@ By default, Salt Cloud will create a directory on the target instance called
``/tmp/.saltcloud/``. This directory should be owned by the user that is to
execute the deploy script, and should have permissions of ``0700``.
Most cloud providers are configured to use ``root`` as the default initial user
Most cloud hosts are configured to use ``root`` as the default initial user
for deployment, and as such, this directory and all files in it should be owned
by the ``root`` user.
@ -101,14 +101,14 @@ The ``/tmp/.saltcloud/`` directory should the following files:
Unprivileged Primary Users
--------------------------
Some providers, most notably EC2, are configured with a different primary user.
Some cloud hosts, most notably EC2, are configured with a different primary user.
Some common examples are ``ec2-user``, ``ubuntu``, ``fedora``, and ``bitnami``.
In these cases, the ``/tmp/.saltcloud/`` directory and all files in it should
be owned by this user.
Some providers, such as EC2, are configured to not require these users to
Some cloud hosts, such as EC2, are configured to not require these users to
provide a password when using the ``sudo`` command. Because it is more secure
to require ``sudo`` users to provide a password, other providers are configured
to require ``sudo`` users to provide a password, other hosts are configured
that way.
If this instance is required to provide a password, it needs to be configured
@ -123,7 +123,7 @@ configuration or the profile configuration:
``/tmp/`` is Mounted as ``noexec``
----------------------------------
It is more secure to mount the ``/tmp/`` directory with a ``noexec`` option.
This is uncommon on most cloud providers, but very common in private
This is uncommon on most cloud hosts, but very common in private
environments. To see if the ``/tmp/`` directory is mounted this way, run the
following command:

View File

@ -2,13 +2,13 @@
Getting Started with VEXXHOST
=============================
`VEXXHOST <http://vexxhost.com>`_ is an cloud computing provider which provides
`VEXXHOST <http://vexxhost.com>`_ is a cloud computing host which provides
`Canadian cloud computing <http://vexxhost.com/cloud-computing>`_ services
which are based in Monteral and uses the libcloud OpenStack driver. VEXXHOST
which are based in Monteral and use the libcloud OpenStack driver. VEXXHOST
currently runs the Havana release of OpenStack. When provisioning new
instances, they automatically get a public IP and private IP address.
Therefore, you do not need to assign a floating IP to access your instance
once it's booted.
after it's booted.
Cloud Provider Configuration
@ -24,7 +24,7 @@ driver.
.. code-block:: yaml
vexxhost:
my-vexxhost-config:
# Set the location of the salt-master
#
minion:
@ -52,6 +52,14 @@ driver.
driver: openstack
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Authentication
==============
@ -80,7 +88,7 @@ profile will build an Ubuntu 12.04 LTS `nb.2G` instance.
.. code-block:: yaml
vh_ubuntu1204_2G:
provider: vexxhost
provider: my-vexxhost-config
image: 4051139f-750d-4d72-8ef0-074f2ccc7e5a
size: nb.2G
@ -106,4 +114,4 @@ the following command:
# salt vh_instance1 test.ping
You can now continue to provision new instances and they will all automatically
be set up as minions of the master you've defined in the configuration file.
be set up as minions of the master you've defined in the configuration file.

View File

@ -60,6 +60,15 @@ set up in the cloud configuration at
server is not using the defaults. Default is ``protocol: https`` and
``port: 443``.
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
.. _vmware-cloud-profile:
Profiles

View File

@ -46,6 +46,14 @@ Set up the cloud config at ``/etc/salt/cloud.providers`` or in the
# Set the URL of your vSphere server
url: 'vsphere.example.com'
.. note::
.. versionchanged:: 2015.8.0
The ``provider`` parameter in cloud provider definitions was renamed to ``driver``. This
change was made to avoid confusion with the ``provider`` parameter that is used in cloud profile
definitions. Cloud provider definitions now use ``driver`` to refer to the Salt cloud module that
provides the underlying functionality to connect to a cloud host, while cloud profiles continue
to use ``provider`` to refer to provider configurations that you define.
Profiles
========

View File

@ -261,7 +261,7 @@ the tests pass and the pull request can be merged.
``Tests Passed``
The pull request has passed all tests even though some test results are negative. Sometimes the automated testing
infrastructure will encounter internal errors unrelated to the code change in the pull request that cause test runs
to fail. These errors can be caused by cloud provider and network issues and also Jenkins issues like erroneously
to fail. These errors can be caused by cloud host and network issues and also Jenkins issues like erroneously
accumulating workspace artifacts, resource exhaustion, and bugs that arise from long running Jenkins processes.
Other

View File

@ -108,7 +108,7 @@ the default cloud provider configuration file for DigitalOcean looks like this:
.. code-block:: yaml
digitalocean-config:
provider: digital_ocean
driver: digital_ocean
client_key: ''
api_key: ''
location: New York 1
@ -119,7 +119,7 @@ must be provided:
.. code-block:: yaml
digitalocean-config:
provider: digital_ocean
driver: digital_ocean
client_key: wFGEwgregeqw3435gDger
api_key: GDE43t43REGTrkilg43934t34qT43t4dgegerGEgg
location: New York 1

View File

@ -318,7 +318,7 @@ Ocean, located at: ``tests/integration/files/conf/cloud.providers.d/digital_ocea
.. code-block:: yaml
digitalocean-config:
provider: digital_ocean
driver: digital_ocean
client_key: ''
api_key: ''
location: New York 1

View File

@ -42,21 +42,27 @@ functionality.
Windows Software Repo Changes
=============================
The :mod:`winrepo.update_git_repos <salt.runners.winrepo.update_git_repos>`
runner has been updated to use either GitPython_ or pygit2_ to checkout the git
repositories containing repo data. Existing winrepo git checkouts should be
removed before starting up the salt-master after upgrading, if GitPython_ or
pygit2_ is installed, to allow them to be checked out again.
Several config options have been renamed to make the naming more consistent.
For a list of the winrepo config options, see :ref:`here
<winrepo-config-opts>`.
This enhancement also brings new functionality, see the :mod:`winrepo runner
<salt.runners.winrepo>` documentation for more information.
The :mod:`winrepo.update_git_repos <salt.runners.winrepo.update_git_repos>`
runner has been updated to use either pygit2_ or GitPython_ to checkout the git
repositories containing repo data. If pygit2_ or GitPython_ is installed,
existing winrepo git checkouts should be removed after upgrading to 2015.8.0,
to allow them to be checked out again by running
:py:func:`winrepo.update_git_repos <salt.runners.winrepo.update_git_repos>`.
This enhancement also brings new functionality, see the :ref:`Windows Software
Repository <2015-8-0-winrepo-changes>` documentation for more information.
If neither GitPython_ nor pygit2_ are installed, then Salt will fall back to
the pre-existing behavior for :mod:`winrepo.update_git_repos
<salt.runners.winrepo.update_git_repos>`.
<salt.runners.winrepo.update_git_repos>`, and a warning will be logged in the
master log.
.. _GitPython: https://github.com/gitpython-developers/GitPython
.. _pygit2: https://github.com/libgit2/pygit2
.. _GitPython: https://github.com/gitpython-developers/GitPython
JBoss 7 State
=============

View File

@ -1,7 +1,13 @@
.. _windows-package-manager:
===========================
Windows Software Repository
===========================
.. note::
Git repository management for the Windows Software Repository has changed
in version 2015.8.0. Please see :ref:`below <2015-8-0-winrepo-changes>` for
important details if upgrading from an earlier Salt release.
The Salt Windows Software Repository provides a package manager and software
repository similar to what is provided by yum and apt on Linux.
@ -48,12 +54,13 @@ between the pre and post ``pkg.list_pkgs`` results.
Usage
=====
By default, the Windows software repository is found at ``/srv/salt/win/repo``
This can be changed in the master config file (default location is
``/etc/salt/master``) by modifying the ``win_repo`` variable, but this must
reside somewhere inside the master's `file_roots`. Each piece of software
should have its own directory which contains the installers and a package
definition file. This package definition file is a YAML file named
By default, the Windows software repository is found at ``/srv/salt/win/repo``.
This can be changed in the master config file by setting the
:conf_master:`winrepo_dir` option (**NOTE:** this option was called
``win_repo`` in Salt versions prior to 2015.8.0). However, this path must
reside somewhere inside the master's :conf_master:`file_roots`. Each piece of
software should have its own directory which contains the installers and a
package definition file. This package definition file is a YAML file named
``init.sls``.
The package definition file should look similar to this example for Firefox:
@ -197,7 +204,8 @@ Alternatively the ``uninstaller`` can also simply repeat the URL of the msi file
Generate Repo Cache File
========================
Once the sls file has been created, generate the repository cache file with the winrepo runner:
Once the sls file has been created, generate the repository cache file with the
winrepo runner:
.. code-block:: bash
@ -247,9 +255,9 @@ The above line will install the latest version of Firefox.
The above line will install version 16.0.2 of Firefox.
If a different version of the package is already installed it will
be replaced with the version in winrepo (only if the package itself supports
live updating).
If a different version of the package is already installed it will be replaced
with the version in the winrepo (only if the package itself supports live
updating).
You can also specify the full name:
@ -274,33 +282,44 @@ future ``pkg.purge`` may direct the installer to remove all configs and
settings for software packages that support that option.
Standalone Minion Salt Windows Repo Module
==========================================
In order to facilitate managing a Salt Windows software repo with Salt on a
Standalone Minion on Windows, a new module named winrepo has been added to
Salt. winrepo matches what is available in the salt runner and allows you to
manage the Windows software repo contents. Example: ``salt '*'
winrepo.genrepo``
Standalone Minion on Windows, a :mod:`winrepo execution module
<salt.modules.win_repo>` is available. This execution module matches what is
available in the :mod:`winrepo runner <salt.runners.winrepo>` and allows for
Windows software repo contents to be managed on a standalone Windows minion.
For example, to generate the winrepo cache, ``salt-call winrepo.genrepo`` would
be run.
.. note::
The :mod:`winrepo execution module <salt.modules.win_repo>` does not
support the :ref:`new features <2015-8-0-winrepo-changes>` added in
version 2015.8.0.
Git Hosted Repo
===============
Windows software package definitions can also be hosted in one or more git
repositories. The default repo is one hosted on GitHub.com by SaltStack,Inc., which
includes package definitions for open source software. This repo points to the
HTTP or ftp locations of the installer files. Anyone is welcome to send a pull
request to this repo to add new package definitions. Browse the repo
here: `https://github.com/saltstack/salt-winrepo
<https://github.com/saltstack/salt-winrepo>`_ .
repositories. The default repo is one hosted on GitHub.com by SaltStack, Inc.,
which includes package definitions for open source software. This repo points
to the HTTP or ftp locations of the installer files. Anyone is welcome to send
a pull request to this repo to add new package definitions. Browse the repo
here: `https://github.com/saltstack/salt-winrepo.git
<https://github.com/saltstack/salt-winrepo.git>`_ .
Configure which git repos the master can search for package definitions by
modifying or extending the ``win_gitrepos`` configuration option list in the
master config.
Configure which git repositories the master can search for package definitions
by modifying or extending the :conf_master:`winrepo_remotes` option (**NOTE:**
this option was called ``win_gitrepos`` in Salt versions prior to 2015.8.0).
Checkout each git repo in ``win_gitrepos``, compile your package repository
cache and then refresh each minion's package cache:
Use the :py:func:`winrepo.update_git_repos
<salt.runners.winrepo.update_git_repos>` runner to clone/update the configured
reops, then use :py:func:`winrepo.genrepo <salt.runners.winrepo.genrepo>`
runner to compile the repository cache. Finally, use :py:func:`pkg.refresh_db
<salt.modules.win_pkg.refresh_db>` on each minion to have them update their
copy of the repository cache. Command examples are as follows:
.. code-block:: bash
@ -310,12 +329,82 @@ cache and then refresh each minion's package cache:
.. _wiki: http://wpkg.org/Category:Silent_Installers
.. _2015-8-0-winrepo-changes:
Changes in Version 2015.8.0
===========================
Many of the winrepo configuration parameters have changed in version 2015.8.0
to make the naming more consistent. The old parameter names will still work,
but a warning will be logged indicating that the old name is deprecated. For a
list of the winrepo config options, see :ref:`here <winrepo-config-opts>`.
Starting in version 2015.8.0, the :py:func:`winrepo.update_git_repos
<salt.runners.winrepo.update_git_repos>` runner now makes use of the same
underlying code used by the :ref:`Git Fileserver Backend <tutorial-gitfs>` and
:ref:`Git External Pillar <tutorial-git_pillar>` to maintain and update its
local clones of git repositories. If a compatible version of either pygit2_
(0.20.3 and later) or GitPython_ (0.3.0 or later) is installed, then Salt will
use it instead of the old method (which invokes the :py:func:`git.latest
<salt.states.git.latest>` state).
.. note::
If compatible versions of both pygit2_ and GitPython_ are installed, then
Salt will prefer pygit2_, to override this behavior use the
:conf_master:`winrepo_provider` configuration parameter:
.. code-block:: yaml
winrepo_provider: gitpython
.. _pygit2: https://github.com/libgit2/pygit2
.. _GitPython: https://github.com/gitpython-developers/GitPython
One important change this brings is the the fact that each repo configured
under the :conf_master:`winrepo_remotes` option (``win_gitrepos`` in Salt
versions prior to 2015.8.0) will have its URL hashed and and the files will be
checked out into a subdirectory containing that hashed name (for example,
``/srv/salt/win/repo/f42c3382aeeaa8733908e5c256dba1ca/myprogram.sls``). There
is no functional reason for the hashed name, it just comes from using the same
back-end code that gitfs and git_pillar are using.
To minimize potential issues, it is a good idea to remove any winrepo git
repositories that were checked out by the old (pre-2015.8.0) winrepo code when
upgrading the master to 2015.8.0 or later, and run
:py:func:`winrepo.update_git_repos <salt.runners.winrepo.update_git_repos>` to
clone them anew after the master is started.
Additional added features include the ability to access authenticated git
repositories (**NOTE:** pygit2_ only), and to set per-remote config settings. An
example of this would be the following:
.. code-block:: yaml
winrepo_remotes:
- https://github.com/saltstack/salt-winrepo.git
- git@github.com:myuser/myrepo.git:
- pubkey: /path/to/key.pub
- privkey: /path/to/key
- passphrase: myaw3s0m3pa$$phr4$3
- https://github.com/myuser/privaterepo.git:
- user: mygithubuser
- password: correcthorsebatterystaple
.. note::
Per-remote configuration settings work in the same fashion as they do in
gitfs, with global parameters being overridden by their per-remote
counterparts (for instance, setting :conf_master:`winrepo_passphrase` would
set a global passphrase for winrepo that would apply to all SSH-based
remotes, unless overridden by a ``passphrase`` per-remote parameter).
See :ref:`here <gitfs-per-remote-config>` for more a more in-depth
explanation of how per-remote configuration works in gitfs, the same
principles apply to winrepo.
Troubleshooting
===============
Incorrect name/version
----------------------

View File

@ -923,7 +923,7 @@ class LocalClient(object):
if raw is None:
break
if gather_errors:
if raw['tag'] == '_salt_error':
if raw['tag'] == '_salt_error' and 'id' in raw['data']:
ret = {raw['data']['id']: raw['data']['data']}
yield ret
if 'minions' in raw.get('data', {}):

View File

@ -17,7 +17,7 @@
# CREATED: 10/15/2012 09:49:37 PM WEST
#======================================================================================================================
set -o nounset # Treat unset variables as an error
__ScriptVersion="2015.07.22"
__ScriptVersion="2015.08.06"
__ScriptName="bootstrap-salt.sh"
#======================================================================================================================
@ -282,7 +282,7 @@ usage() {
'install_<distro>_check_services' checks. You can also do this by
touching /tmp/disable_salt_checks on the target host. Defaults \${BS_FALSE}
-H Use the specified http proxy for the installation
-Z Enable external software source for newer ZeroMQ(Only available for RHEL/CentOS/Fedora based distributions)
-Z Enable external software source for newer ZeroMQ(Only available for RHEL/CentOS/Fedora/Ubuntu based distributions)
EOT
} # ---------- end of function usage ----------
@ -504,6 +504,7 @@ __exit_cleanup() {
if [ $_KEEP_TEMP_FILES -eq $BS_FALSE ]; then
# Clean up the checked out repository
echodebug "Cleaning up the Salt Temporary Git Repository"
cd "${__SALT_GIT_CHECKOUT_PARENT_DIR}"
rm -rf "${__SALT_GIT_CHECKOUT_DIR}"
else
echowarn "Not cleaning up the Salt Temporary git repository on request"
@ -1326,14 +1327,8 @@ __check_end_of_life_versions() {
ubuntu)
# Ubuntu versions not supported
#
# < 10
# = 10.10
# = 11.04
# = 11.10
if ([ "$DISTRO_MAJOR_VERSION" -eq 10 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]) || \
([ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$DISTRO_MINOR_VERSION" -eq 04 ]) || \
([ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]) || \
[ "$DISTRO_MAJOR_VERSION" -lt 10 ]; then
# < 12.04
if [ "$DISTRO_MAJOR_VERSION" -lt 12 ]; then
echoerror "End of life distributions are not supported."
echoerror "Please consider upgrading to the next stable. See:"
echoerror " https://wiki.ubuntu.com/Releases"
@ -1766,14 +1761,20 @@ install_ubuntu_deps() {
# Need python-apt for managing packages via Salt
__PACKAGES="${__PACKAGES} python-apt"
echoinfo "Installing Python Requests/Chardet from Chris Lea's PPA repository"
if [ "$DISTRO_MAJOR_VERSION" -gt 11 ] || ([ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$DISTRO_MINOR_VERSION" -gt 04 ]); then
# Above Ubuntu 11.04 add a -y flag
add-apt-repository -y "ppa:chris-lea/python-requests" || return 1
add-apt-repository -y "ppa:chris-lea/python-chardet" || return 1
else
add-apt-repository "ppa:chris-lea/python-requests" || return 1
add-apt-repository "ppa:chris-lea/python-chardet" || return 1
if [ "$DISTRO_MAJOR_VERSION" -lt 14 ]; then
echoinfo "Installing Python Requests/Chardet from Chris Lea's PPA repository"
if [ "$DISTRO_MAJOR_VERSION" -gt 11 ] || ([ "$DISTRO_MAJOR_VERSION" -eq 11 ] && [ "$DISTRO_MINOR_VERSION" -gt 04 ]); then
# Above Ubuntu 11.04 add a -y flag
add-apt-repository -y "ppa:chris-lea/python-requests" || return 1
add-apt-repository -y "ppa:chris-lea/python-chardet" || return 1
add-apt-repository -y "ppa:chris-lea/python-urllib3" || return 1
add-apt-repository -y "ppa:chris-lea/python-crypto" || return 1
else
add-apt-repository "ppa:chris-lea/python-requests" || return 1
add-apt-repository "ppa:chris-lea/python-chardet" || return 1
add-apt-repository "ppa:chris-lea/python-urllib3" || return 1
add-apt-repository "ppa:chris-lea/python-crypto" || return 1
fi
fi
__PACKAGES="${__PACKAGES} python-requests"
@ -1839,13 +1840,17 @@ install_ubuntu_stable_deps() {
add-apt-repository "ppa:$STABLE_PPA" || return 1
fi
__PACKAGES=""
if [ ! "$(echo "$STABLE_REV" | egrep '^(2015\.8|latest)$')" = "" ]; then
# We need a recent tornado package
__REQUIRED_TORNADO="tornado >= 4.0"
check_pip_allowed "You need to allow pip based installations (-P) in order to install the python package '${__REQUIRED_TORNADO}'"
if [ "$(which pip)" = "" ]; then
__apt_get_install_noinput python-setuptools python-pip
__PACKAGES="${__PACKAGES} python-setuptools python-pip"
fi
__PACKAGES="${__PACKAGES} python-dev"
# shellcheck disable=SC2086
__apt_get_install_noinput $__PACKAGES
pip install -U "${__REQUIRED_TORNADO}"
fi
@ -1887,14 +1892,18 @@ install_ubuntu_git_deps() {
__git_clone_and_checkout || return 1
__PACKAGES=""
if [ -f "${__SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" ]; then
# We're on the develop branch, install whichever tornado is on the requirements file
__REQUIRED_TORNADO="$(grep tornado "${__SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")"
if [ "${__REQUIRED_TORNADO}" != "" ]; then
__PACKAGES="${__PACKAGES} python-dev"
check_pip_allowed "You need to allow pip based installations (-P) in order to install the python package '${__REQUIRED_TORNADO}'"
if [ "$(which pip)" = "" ]; then
__apt_get_install_noinput python-setuptools python-pip
__PACKAGES="${__PACKAGES} python-setuptools python-pip"
fi
# shellcheck disable=SC2086
__apt_get_install_noinput $__PACKAGES
pip install -U "${__REQUIRED_TORNADO}"
fi
fi
@ -2389,6 +2398,7 @@ install_debian_git_deps() {
__REQUIRED_TORNADO="$(grep tornado "${__SALT_GIT_CHECKOUT_DIR}/requirements/base.txt")"
if [ "${__REQUIRED_TORNADO}" != "" ]; then
check_pip_allowed "You need to allow pip based installations (-P) in order to install the python package '${__REQUIRED_TORNADO}'"
__apt_get_install_noinput python-dev
pip install -U "${__REQUIRED_TORNADO}" || return 1
fi
fi
@ -3026,10 +3036,10 @@ install_centos_git() {
_PYEXE=python2
fi
if [ -f "${__SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then
$_PYEXE setup.py install --salt-config-dir="$_SALT_ETC_DIR" || \
$_PYEXE setup.py --salt-config-dir="$_SALT_ETC_DIR" install || return 1
$_PYEXE setup.py install --prefix=/usr --salt-config-dir="$_SALT_ETC_DIR" || \
$_PYEXE setup.py --prefix=/usr --salt-config-dir="$_SALT_ETC_DIR" install || return 1
else
$_PYEXE setup.py install || return 1
$_PYEXE setup.py install --prefix=/usr || return 1
fi
return 0
}

View File

@ -381,9 +381,6 @@ VALID_OPTS = {
# Events matching a tag in this list should never be sent to an event returner.
'event_return_blacklist': list,
# The source location for the winrepo sls files
'win_repo_source_dir': str,
# This pidfile to write out to when a deamon starts
'pidfile': str,
@ -570,9 +567,21 @@ VALID_OPTS = {
# The logfile location for salt-key
'key_logfile': str,
'win_repo': str,
'win_repo_mastercachefile': str,
'win_gitrepos': list,
# The source location for the winrepo sls files
# (used by win_pkg.py, minion only)
'winrepo_source_dir': str,
'winrepo_dir': str,
'winrepo_cachefile': str,
'winrepo_remotes': list,
'winrepo_branch': str,
'winrepo_ssl_verify': bool,
'winrepo_user': str,
'winrepo_password': str,
'winrepo_insecure_auth': bool,
'winrepo_privkey': str,
'winrepo_pubkey': str,
'winrepo_passphrase': str,
# Set a hard limit for the amount of memory modules can consume on a minion.
'modules_max_memory': int,
@ -843,7 +852,10 @@ DEFAULT_MINION_OPTS = {
'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,
'win_repo_source_dir': 'salt://win/repo/',
'winrepo_source_dir': 'salt://win/repo/',
'winrepo_dir': 'c:\\salt\\file_roots\\winrepo',
'winrepo_cachefile': 'winrepo.p',
'winrepo_remotes': ['https://github.com/saltstack/salt-winrepo.git'],
'pidfile': os.path.join(salt.syspaths.PIDFILE_DIR, 'salt-minion.pid'),
'range_server': 'range:80',
'tcp_keepalive': True,
@ -1042,10 +1054,17 @@ DEFAULT_MASTER_OPTS = {
'verify_env': True,
'permissive_pki_access': False,
'default_include': 'master.d/*.conf',
'win_repo': os.path.join(salt.syspaths.BASE_FILE_ROOTS_DIR, 'win', 'repo'),
'win_repo_mastercachefile': os.path.join(salt.syspaths.BASE_FILE_ROOTS_DIR,
'win', 'repo', 'winrepo.p'),
'win_gitrepos': ['https://github.com/saltstack/salt-winrepo.git'],
'winrepo_dir': os.path.join(salt.syspaths.BASE_FILE_ROOTS_DIR, 'win', 'repo'),
'winrepo_cachefile': 'winrepo.p',
'winrepo_remotes': ['https://github.com/saltstack/salt-winrepo.git'],
'winrepo_branch': 'master',
'winrepo_ssl_verify': False,
'winrepo_user': '',
'winrepo_password': '',
'winrepo_insecure_auth': False,
'winrepo_privkey': '',
'winrepo_pubkey': '',
'winrepo_passphrase': '',
'syndic_wait': 5,
'jinja_lstrip_blocks': False,
'jinja_trim_blocks': False,

View File

@ -102,10 +102,10 @@ class Client(object):
# Backwards compatibility
saltenv = env
dest = os.path.join(self.opts['cachedir'],
'files',
saltenv,
path)
dest = salt.utils.path_join(self.opts['cachedir'],
'files',
saltenv,
path)
destdir = os.path.dirname(dest)
cumask = os.umask(63)
if not os.path.isdir(destdir):

View File

@ -778,7 +778,12 @@ def version(name, check_remote=False, source=None, pre_versions=False):
log.error(err)
raise CommandExecutionError(err)
cmd = [choc_path, 'version', name]
if _LooseVersion(chocolatey_version()) >= _LooseVersion('0.9.9'):
choco_cmd = "list"
else:
choco_cmd = "version"
cmd = [choc_path, choco_cmd, name]
if not salt.utils.is_true(check_remote):
cmd.append('-LocalOnly')
if salt.utils.is_true(pre_versions):
@ -800,13 +805,13 @@ def version(name, check_remote=False, source=None, pre_versions=False):
# pairs is shown in rows...
if not salt.utils.is_true(check_remote):
ver_re = re.compile(r'(\S+)\s+(.+)')
for line in result['stdout'].split('\n'):
for line in result['stdout'].split('\n')[:-1]:
for name, ver in ver_re.findall(line):
ret['name'] = name
ret['found'] = ver
else:
ver_re = re.compile(r'(\S+)\s+:\s*(.*)')
for line in result['stdout'].split('\n'):
for line in result['stdout'].split('\n')[:-1]:
for key, value in ver_re.findall(line):
ret[key] = value

View File

@ -1089,7 +1089,7 @@ def comment_line(path,
regex.lstrip('^').rstrip('$'),
'$' if regex.endswith('$') else '')
else:
regex = '^{0}({1}){2}'.format(
regex = r'^{0}\s*({1}){2}'.format(
char,
regex.lstrip('^').rstrip('$'),
'$' if regex.endswith('$') else '')

View File

@ -47,7 +47,7 @@ def add(overlay):
ret = list()
old_overlays = list_local()
cmd = 'layman --quietness=0 --add {0}'.format(overlay)
add_attempt = __salt__['cmd.run_all'](cmd, python_shell=False)
add_attempt = __salt__['cmd.run_all'](cmd, python_shell=False, stdin='y')
if add_attempt['retcode'] != 0:
raise salt.exceptions.CommandExecutionError(add_attempt['stdout'])
new_overlays = list_local()

View File

@ -135,8 +135,8 @@ def read_key(hkey, path, key=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'
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,
@ -248,8 +248,8 @@ def set_key(hkey, path, value, key=None, vtype='REG_DWORD', reflection=True):
'''
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'
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,
@ -353,8 +353,8 @@ def create_key(hkey, path, key=None, value=None, reflection=True):
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 set a registry'
'value. This functionality will be'
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,
@ -406,8 +406,8 @@ def delete_key(hkey, path, key=None, reflection=True):
'''
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'
salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry '
'value. This functionality will be '
'removed in Salt Boron')
return delete_value(hive=hkey,
key=path,

View File

@ -965,7 +965,7 @@ def build_routes(iface, **settings):
'''
template = 'rh6_route_eth.jinja'
if float(__grains__['osrelease']) < 6:
if __grains__['osrelease'][0] < 6:
template = 'route_eth.jinja'
log.debug('Template name: ' + template)

View File

@ -6,6 +6,7 @@ from __future__ import absolute_import
# Import Python libs
import logging
import json
# Import Salt libs
import salt.utils
@ -13,6 +14,13 @@ import salt.utils.decorators as decorators
log = logging.getLogger(__name__)
# Function aliases
__func_alias__ = {
'list_installed': 'list',
'update_installed': 'update',
'import_image': 'import'
}
# Define the module's virtual name
__virtualname__ = 'imgadm'
@ -36,6 +44,27 @@ def _exit_status(retcode):
return ret
def _parse_image_meta(image=None, detail=False):
if not image:
return {}
if detail:
return {
'name': image['manifest']['name'],
'version': image['manifest']['version'],
'os': image['manifest']['os'],
'description': image['manifest']['description'],
'published': image['manifest']['published_at'],
'source': image['source']
}
else:
return '{name}@{version} [{date}]'.format(
name=image['manifest']['name'],
version=image['manifest']['version'],
date=image['manifest']['published_at'],
)
def __virtual__():
'''
Provides imgadm only on SmartOS
@ -63,70 +92,90 @@ def version():
return ret[-1]
def update_installed():
def update_installed(uuid=''):
'''
Gather info on unknown images (locally installed)
Gather info on unknown image(s) (locally installed)
uuid : string
Specifies uuid of image
CLI Example:
.. code-block:: bash
salt '*' imgadm.update_installed()
salt '*' imgadm.update [uuid]
'''
imgadm = _check_imgadm()
if imgadm:
cmd = '{0} update'.format(imgadm)
cmd = '{0} update {1}'.format(imgadm, uuid).rstrip()
__salt__['cmd.run'](cmd)
return {}
def avail(search=None):
def avail(search=None, verbose=False):
'''
Return a list of available images
search : string
Specifies search keyword
verbose : boolean (False)
Specifies verbose output
CLI Example:
.. code-block:: bash
salt '*' imgadm.avail [percona]
salt '*' imgadm.avail verbose=True
'''
ret = {}
imgadm = _check_imgadm()
cmd = '{0} avail'.format(imgadm)
cmd = '{0} avail -j'.format(imgadm)
res = __salt__['cmd.run_all'](cmd)
retcode = res['retcode']
result = {}
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
if search:
for line in res['stdout'].splitlines():
if search in line:
ret = line
else:
ret = res['stdout'].splitlines()
return ret
for image in json.loads(res['stdout']):
if image['manifest']['disabled'] or not image['manifest']['public']:
continue
if search and search not in image['manifest']['name']:
# we skip if we are searching but don't have a match
continue
result[image['manifest']['uuid']] = _parse_image_meta(image, verbose)
return result
def list_installed():
def list_installed(verbose=False):
'''
Return a list of installed images
verbose : boolean (False)
Specifies verbose output
CLI Example:
.. code-block:: bash
salt '*' imgadm.list_installed
salt '*' imgadm.list [verbose=True]
'''
ret = {}
imgadm = _check_imgadm()
cmd = '{0} list'.format(imgadm)
cmd = '{0} list -j'.format(imgadm)
res = __salt__['cmd.run_all'](cmd)
retcode = res['retcode']
result = {}
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
ret = res['stdout'].splitlines()
return ret
for image in json.loads(res['stdout']):
result[image['manifest']['uuid']] = _parse_image_meta(image, verbose)
return result
def show(uuid=None):
@ -150,7 +199,7 @@ def show(uuid=None):
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
ret[uuid] = res['stdout'].splitlines()
ret = json.loads(res['stdout'])
return ret
@ -175,19 +224,24 @@ def get(uuid=None):
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
ret[uuid] = res['stdout'].splitlines()
ret = json.loads(res['stdout'])
return ret
def import_image(uuid=None):
def import_image(uuid=None, verbose=False):
'''
Import an image from the repository
uuid : string
Specifies uuid to import
verbose : boolean (False)
Specifies verbose output
CLI Example:
.. code-block:: bash
salt '*' imgadm.import_image e42f8c84-bbea-11e2-b920-078fab2aab1f
salt '*' imgadm.import e42f8c84-bbea-11e2-b920-078fab2aab1f [verbose=True]
'''
ret = {}
if not uuid:
@ -200,14 +254,17 @@ def import_image(uuid=None):
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
ret[uuid] = res['stdout'].splitlines()
return ret
return {uuid: _parse_image_meta(get(uuid), verbose)}
def delete(uuid=None):
'''
Remove an installed image
uuid : string
Specifies uuid to import
CLI Example:
.. code-block:: bash
@ -225,8 +282,48 @@ def delete(uuid=None):
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
ret[uuid] = res['stdout'].splitlines()
return ret
# output: Deleted image d5b3865c-0804-11e5-be21-dbc4ce844ddc
result = []
for image in res['stdout'].splitlines():
image = [var for var in image.split(" ") if var]
result.append(image[2])
return result
def vacuum(verbose=False):
'''
Remove unused images
verbose : boolean (False)
Specifies verbose output
CLI Example:
.. code-block:: bash
salt '*' imgadm.vacuum [verbose=True]
'''
ret = {}
imgadm = _check_imgadm()
cmd = '{0} vacuum -f'.format(imgadm)
res = __salt__['cmd.run_all'](cmd)
retcode = res['retcode']
if retcode != 0:
ret['Error'] = _exit_status(retcode)
return ret
# output: Deleted image d5b3865c-0804-11e5-be21-dbc4ce844ddc (lx-centos-6@20150601)
result = {}
for image in res['stdout'].splitlines():
image = [var for var in image.split(" ") if var]
result[image[2]] = {
'name': image[3][1:image[3].index('@')],
'version': image[3][image[3].index('@')+1:-1]
}
if verbose:
return result
else:
return list(result.keys())
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

View File

@ -109,6 +109,12 @@ def set_zone(timezone):
salt '*' timezone.set_zone 'America/Denver'
'''
if salt.utils.which('timedatectl'):
try:
__salt__['cmd.run']('timedatectl set-timezone {0}'.format(timezone))
except CommandExecutionError:
pass
if 'Solaris' in __grains__['os_family']:
zonepath = '/usr/share/lib/zoneinfo/{0}'.format(timezone)
else:

View File

@ -389,7 +389,11 @@ def chfullname(name, fullname):
salt '*' user.chfullname foo "Foo Bar"
'''
fullname = str(fullname)
if fullname is None:
fullname = ''
else:
fullname = str(fullname)
pre_info = _get_gecos(name)
if not pre_info:
return False
@ -415,7 +419,11 @@ def chroomnumber(name, roomnumber):
salt '*' user.chroomnumber foo 123
'''
roomnumber = str(roomnumber)
if roomnumber is None:
roomnumber = ''
else:
roomnumber = str(roomnumber)
pre_info = _get_gecos(name)
if not pre_info:
return False
@ -441,7 +449,11 @@ def chworkphone(name, workphone):
salt '*' user.chworkphone foo "7735550123"
'''
workphone = str(workphone)
if workphone is None:
workphone = ''
else:
workphone = str(workphone)
pre_info = _get_gecos(name)
if not pre_info:
return False
@ -467,7 +479,11 @@ def chhomephone(name, homephone):
salt '*' user.chhomephone foo "7735551234"
'''
homephone = str(homephone)
if homephone is None:
homephone = ''
else:
homephone = str(homephone)
pre_info = _get_gecos(name)
if not pre_info:
return False

View File

@ -6,13 +6,17 @@ from __future__ import absolute_import
# Import python libs
import re
import logging
# Import salt libs
import salt.utils
from salt.ext import six
# Define the module's virtual name
__virtualname__ = 'firewall'
log = logging.getLogger(__name__)
def __virtual__():
'''
@ -119,11 +123,18 @@ def add_rule(name, localport, protocol='tcp', action='allow', dir='in'):
'dir={0}'.format(dir),
'localport={0}'.format(localport),
'action={0}'.format(action)]
return __salt__['cmd.run'](cmd, python_shell=False) == 'Ok.'
ret = __salt__['cmd.run'](cmd, python_shell=False)
if isinstance(ret, six.string_types):
return ret.strip() == 'Ok.'
else:
log.error('firewall.add_rule failed: {0}'.format(ret))
return False
def delete_rule(name, localport, protocol='tcp', dir='in'):
'''
.. versionadded:: 2015.8.0
Delete an existing firewall rule
CLI Example:
@ -137,4 +148,9 @@ def delete_rule(name, localport, protocol='tcp', dir='in'):
'protocol={0}'.format(protocol),
'dir={0}'.format(dir),
'localport={0}'.format(localport)]
return __salt__['cmd.run'](cmd, python_shell=False) == 'Ok.'
ret = __salt__['cmd.run'](cmd, python_shell=False)
if isinstance(ret, six.string_types):
return ret.endswith('Ok.')
else:
log.error('firewall.delete_rule failed: {0}'.format(ret))
return False

View File

@ -93,9 +93,9 @@ def latest_version(*names, **kwargs):
latest_installed = sorted(installed_pkgs[name], cmp=_reverse_cmp_pkg_versions).pop()
log.debug('Latest installed version of package {0} is {1}'.format(name, latest_installed))
# get latest available (from win_repo) version of package
# get latest available (from winrepo_dir) version of package
pkg_info = _get_package_info(name)
log.trace('Raw win_repo pkg_info for {0} is {1}'.format(name, pkg_info))
log.trace('Raw winrepo pkg_info for {0} is {1}'.format(name, pkg_info))
latest_available = _get_latest_pkg_version(pkg_info)
if latest_available:
log.debug('Latest available version of package {0} is {1}'.format(name, latest_available))
@ -371,25 +371,47 @@ def refresh_db(saltenv='base'):
salt '*' pkg.refresh_db
'''
__context__.pop('winrepo.data', None)
repo = __opts__['win_repo_source_dir']
cached_files = __salt__['cp.cache_dir'](repo, saltenv, include_pat='*.sls')
if 'win_repo_source_dir' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo_source_dir\' config option is deprecated, please '
'use \'winrepo_source_dir\' instead.'
)
winrepo_source_dir = __opts__['win_repo_source_dir']
else:
winrepo_source_dir = __opts__['winrepo_source_dir']
cached_files = __salt__['cp.cache_dir'](
winrepo_source_dir,
saltenv,
include_pat='*.sls'
)
genrepo(saltenv=saltenv)
return cached_files
def _get_local_repo_dir(saltenv='base'):
master_repo_src = __opts__['win_repo_source_dir']
if 'win_repo_source_dir' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo_source_dir\' config option is deprecated, please '
'use \'winrepo_source_dir\' instead.'
)
winrepo_source_dir = __opts__['win_repo_source_dir']
else:
winrepo_source_dir = __opts__['winrepo_source_dir']
dirs = []
dirs.append(salt.syspaths.CACHE_DIR)
dirs.extend(['minion', 'files'])
dirs.append(saltenv)
dirs.extend(master_repo_src[7:].strip('/').split('/'))
dirs.extend(winrepo_source_dir[7:].strip('/').split('/'))
return os.sep.join(dirs)
def genrepo(saltenv='base'):
'''
Generate win_repo_cachefile based on sls files in the win_repo
Generate winrepo_cachefile based on sls files in the winrepo
CLI Example:
@ -626,7 +648,10 @@ def remove(name=None, pkgs=None, version=None, extra_uninstall_flags=None, **kwa
uninstaller = pkginfo[version].get('installer')
if not uninstaller:
return 'Error: No installer or uninstaller configured for package {0}'.format(name)
if uninstaller.startswith('salt:'):
if uninstaller.startswith('salt:') \
or uninstaller.startswith('http:') \
or uninstaller.startswith('https:') \
or uninstaller.startswith('ftp:'):
cached_pkg = \
__salt__['cp.is_cached'](uninstaller)
if not cached_pkg:

View File

@ -2,10 +2,11 @@
r'''
Module to manage Windows software repo on a Standalone Minion
The following options must be set in the Minion config:
file_client: local
win_repo_cachefile: c:\salt\file_roots\winrepo\winrepo.p
win_repo: c:\salt\file_roots\winrepo
``file_client: local`` must be set in the minion config file. Other config
options of interest include:
* :conf_minion:`winrepo_dir`
* :conf_minion:`winrepo_cachefile`
Place all Windows package files in the 'win_repo' directory.
'''
@ -46,7 +47,7 @@ def __virtual__():
def genrepo():
r'''
Generate win_repo_cachefile based on sls files in the win_repo
Generate winrepo_cachefile based on sls files in the win_repo
CLI Example:
@ -54,13 +55,31 @@ def genrepo():
salt-call winrepo.genrepo -c c:\salt\conf
'''
if 'win_repo' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = __opts__['win_repo']
else:
winrepo_dir = __opts__['winrepo_dir']
if 'win_repo_cachefile' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo_cachefile\' config option is deprecated, please '
'use \'winrepo_cachefile\' instead.'
)
winrepo_cachefile = __opts__['win_repo_cachefile']
else:
winrepo_cachefile = __opts__['winrepo_cachefile']
ret = {}
repo = __opts__['win_repo']
if not os.path.exists(repo):
os.makedirs(repo)
winrepo = __opts__['win_repo_cachefile']
if not os.path.exists(winrepo_dir):
os.makedirs(winrepo_dir)
renderers = salt.loader.render(__opts__, __salt__)
for root, dirs, files in os.walk(repo):
for root, dirs, files in os.walk(winrepo_dir):
for name in files:
if name.endswith('.sls'):
config = salt.template.compile_template(
@ -77,7 +96,8 @@ def genrepo():
revmap[repodata['full_name']] = pkgname
ret.setdefault('repo', {}).update(config)
ret.setdefault('name_map', {}).update(revmap)
with salt.utils.fopen(os.path.join(repo, winrepo), 'w+b') as repo:
with salt.utils.fopen(
os.path.join(winrepo_dir, winrepo_cachefile), 'w+b') as repo:
repo.write(msgpack.dumps(ret))
salt.output.display_output(ret, 'pprint', __opts__)
return ret
@ -91,25 +111,43 @@ def update_git_repos():
This function will not work unless git is installed and the git module
is further updated to work on Windows. In the meantime just place all
Windows package files in the ``win_repo`` directory.
Windows package files in the :conf_minion:`winrepo_dir` directory.
'''
if 'win_repo' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = __opts__['win_repo']
else:
winrepo_dir = __opts__['winrepo_dir']
if 'win_gitrepos' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_gitrepos\' config option is deprecated, please use '
'\'winrepo_remotes\' instead.'
)
winrepo_remotes = __opts__['win_gitrepos']
else:
winrepo_remotes = __opts__['winrepo_remotes']
ret = {}
#mminion = salt.minion.MasterMinion(__opts__)
repo = __opts__['win_repo']
gitrepos = __opts__['win_gitrepos']
for gitrepo in gitrepos:
#if '/' in gitrepo:
#targetname = gitrepo.split('/')[-1]
for remote in winrepo_remotes:
#if '/' in remote:
#targetname = remote.split('/')[-1]
#else:
#targetname = gitrepo
targetname = gitrepo
#targetname = remote
targetname = remote
rev = None
# If a revision is specified, use it.
if len(gitrepo.strip().split(' ')) > 1:
rev, gitrepo = gitrepo.strip().split(' ')
gittarget = os.path.join(repo, targetname)
#result = mminion.states['git.latest'](gitrepo,
result = __salt__['git.latest'](gitrepo,
if len(remote.strip().split(' ')) > 1:
rev, remote = remote.strip().split(' ')
gittarget = os.path.join(winrepo_dir, targetname)
#result = mminion.states['git.latest'](remote,
result = __salt__['git.latest'](remote,
rev=rev,
target=gittarget,
force=True)

View File

@ -1,22 +1,33 @@
# -*- coding: utf-8 -*-
'''
Module for managing windows systems.
:depends:
- win32net
Support for reboot, shutdown, etc
'''
from __future__ import absolute_import
# Import python libs
import logging
import re
import datetime
import time
from datetime import datetime
# Import 3rd Party Libs
try:
from shlex import quote as _cmd_quote # pylint: disable=E0611
import win32net
import win32api
import pywintypes
from ctypes import windll
HAS_WIN32NET_MODS = True
except ImportError:
from pipes import quote as _cmd_quote
HAS_WIN32NET_MODS = False
# Import salt libs
import salt.utils
import salt.utils.locales
from salt.modules.reg import read_value
# Set up logging
log = logging.getLogger(__name__)
@ -27,11 +38,11 @@ __virtualname__ = 'system'
def __virtual__():
'''
This only supports Windows
Set the system module of the kernel is Windows
'''
if not salt.utils.is_windows():
return False
return __virtualname__
if HAS_WIN32NET_MODS and salt.utils.is_windows():
return __virtualname__
return False
def _convert_minutes_seconds(timeout, in_seconds=False):
@ -43,7 +54,14 @@ def _convert_minutes_seconds(timeout, in_seconds=False):
def halt(timeout=5, in_seconds=False):
'''
Halt a running system
Halt a running system.
:param int timeout:
Number of seconds before halting the system.
Default is 5 seconds.
:return: True is successful.
:rtype: bool
timeout
The wait time before the system will be shutdown.
@ -59,7 +77,7 @@ def halt(timeout=5, in_seconds=False):
salt '*' system.halt 5
'''
return shutdown(timeout, in_seconds)
return shutdown(timeout=timeout, in_seconds=in_seconds)
def init(runlevel):
@ -84,7 +102,14 @@ def init(runlevel):
def poweroff(timeout=5, in_seconds=False):
'''
Poweroff a running system
Power off a running system.
:param int timeout:
Number of seconds before powering off the system.
Default is 5 seconds.
:return: True if successful
:rtype: bool
timeout
The wait time before the system will be shutdown.
@ -100,12 +125,19 @@ def poweroff(timeout=5, in_seconds=False):
salt '*' system.poweroff 5
'''
return shutdown(timeout, in_seconds)
return shutdown(timeout=timeout, in_seconds=in_seconds)
def reboot(timeout=5, in_seconds=False, wait_for_reboot=False):
'''
Reboot the system
Reboot a running system.
:param int timeout:
Number of seconds before rebooting the system.
Default is 5 seconds.
:return: True if successful
:rtype: bool
timeout
The wait time before the system will be shutdown.
@ -133,28 +165,57 @@ def reboot(timeout=5, in_seconds=False, wait_for_reboot=False):
salt '*' system.reboot 5
salt '*' system.reboot 5 True
'''
seconds = _convert_minutes_seconds(timeout, in_seconds)
cmd = ['shutdown', '/r', '/t', '{0}'.format(seconds)]
ret = __salt__['cmd.run'](cmd, python_shell=False)
ret = shutdown(timeout=timeout, reboot=True, in_seconds=in_seconds)
if wait_for_reboot:
seconds = _convert_minutes_seconds(timeout, in_seconds)
time.sleep(seconds + 30)
return ret
def shutdown(timeout=5, in_seconds=False):
def shutdown(message=None, timeout=5, force_close=True, reboot=False, in_seconds=False):
'''
Shutdown a running system
Shutdown a running system.
timeout
The wait time before the system will be shutdown.
:param str message:
A message to display to the user before shutting down.
in_seconds
:param int timeout:
The length of time that the shutdown dialog box should be displayed, in
seconds. While this dialog box is displayed, the shutdown can be stopped
by the shutdown_abort function.
If dwTimeout is not zero, InitiateSystemShutdown displays a dialog box
on the specified computer. The dialog box displays the name of the user
who called the function, displays the message specified by the lpMessage
parameter, and prompts the user to log off. The dialog box beeps when it
is created and remains on top of other windows in the system. The dialog
box can be moved but not closed. A timer counts down the remaining time
before a forced shutdown.
If dwTimeout is zero, the computer shuts down without displaying the
dialog box, and the shutdown cannot be stopped by shutdown_abort.
Default is 5
:param bool in_seconds:
Whether to treat timeout as seconds or minutes.
.. versionadded:: 2015.8.0
:param bool force_close:
True to force close all open applications. False displays a dialog box
instructing the user to close the applications.
:param bool reboot:
True restarts the computer immediately after shutdown.
False caches to disk and safely powers down the system.
:return: True if successful
:rtype: bool
CLI Example:
.. code-block:: bash
@ -162,14 +223,32 @@ def shutdown(timeout=5, in_seconds=False):
salt '*' system.shutdown 5
'''
seconds = _convert_minutes_seconds(timeout, in_seconds)
cmd = ['shutdown', '/s', '/t', '{0}'.format(seconds)]
ret = __salt__['cmd.run'](cmd, python_shell=False)
return ret
if message:
message = message.decode('utf-8')
try:
win32api.InitiateSystemShutdown('127.0.0.1', message, timeout,
force_close, reboot)
return True
except pywintypes.error as exc:
(number, context, message) = exc
log.error('Failed to shutdown the system')
log.error('nbr: {0}'.format(number))
log.error('ctx: {0}'.format(context))
log.error('msg: {0}'.format(message))
return False
def shutdown_hard():
'''
Shutdown a running system with no timeout or warning
Shutdown a running system with no timeout or warning.
:param int timeout:
Number of seconds before shutting down the system.
Default is 5 seconds.
:return: True if successful
:rtype: bool
CLI Example:
@ -177,27 +256,61 @@ def shutdown_hard():
salt '*' system.shutdown_hard
'''
cmd = ['shutdown', '/p', '/f']
ret = __salt__['cmd.run'](cmd, python_shell=False)
return ret
return shutdown(timeout=0)
def shutdown_abort():
'''
Abort a shutdown. Only available while the dialog box is being
displayed to the user. Once the shutdown has initiated, it cannot be aborted
:return: True if successful
:rtype: bool
'''
try:
win32api.AbortSystemShutdown('127.0.0.1')
return True
except pywintypes.error as exc:
(number, context, message) = exc
log.error('Failed to abort system shutdown')
log.error('nbr: {0}'.format(number))
log.error('ctx: {0}'.format(context))
log.error('msg: {0}'.format(message))
return False
def lock():
'''
Lock the workstation.
:return: True if successful
:rtype: bool
'''
return windll.user32.LockWorkStation()
def set_computer_name(name):
'''
Set the Windows computer name
:param str name:
The new name to give the computer. Requires a reboot to take effect.
:return:
Returns a dictionary containing the old and new names if successful.
False if not.
CLI Example:
.. code-block:: bash
salt 'minion-id' system.set_computer_name 'DavesComputer'
'''
cmd = ('wmic computersystem where name="%COMPUTERNAME%"'
' call rename name="{0}"'.format(name))
log.debug('Attempting to change computer name. Cmd is: {0}'.format(cmd))
ret = __salt__['cmd.run'](cmd, python_shell=True)
if 'ReturnValue = 0;' in ret:
ret = {'Computer Name': {'Current': get_computer_name()}}
if name:
name = name.decode('utf-8')
if windll.kernel32.SetComputerNameW(name):
ret = {'Computer Name': {'Current': get_system_info()['name']}}
pending = get_pending_computer_name()
if pending not in (None, False):
ret['Computer Name']['Pending'] = pending
@ -213,6 +326,10 @@ def get_pending_computer_name():
retrieving the pending computer name, ``False`` will be returned, and an
error message will be logged to the minion log.
:return:
Returns the pending name if pending restart. Returns none if not pending
restart.
CLI Example:
.. code-block:: bash
@ -220,26 +337,11 @@ def get_pending_computer_name():
salt 'minion-id' system.get_pending_computer_name
'''
current = get_computer_name()
cmd = ['reg', 'query',
'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName',
'/v', 'ComputerName']
output = __salt__['cmd.run'](cmd, python_shell=False)
pending = None
for line in output.splitlines():
try:
pending = re.search(
r'ComputerName\s+REG_SZ\s+(\S+)',
line
).group(1)
break
except AttributeError:
continue
if pending is not None:
pending = read_value('HKLM',
r'SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName',
'ComputerName')['vdata']
if pending:
return pending if pending != current else None
log.error('Unable to retrieve pending computer name using the '
'following command: {0}'.format(cmd))
return False
@ -247,58 +349,90 @@ def get_computer_name():
'''
Get the Windows computer name
:return:
Returns the computer name if found. Otherwise returns False
CLI Example:
.. code-block:: bash
salt 'minion-id' system.get_computer_name
'''
cmd = ['net', 'config', 'server']
lines = __salt__['cmd.run'](cmd, python_shell=False).splitlines()
for line in lines:
if 'Server Name' in line:
_, srv_name = line.split('Server Name', 1)
return srv_name.strip().lstrip('\\')
return False
name = get_system_info()['name']
return name if name else False
def set_computer_desc(desc):
def set_computer_desc(desc=None):
'''
Set the Windows computer description
:param str desc:
The computer description
:return: False if it fails. Description if successful.
CLI Example:
.. code-block:: bash
salt 'minion-id' system.set_computer_desc 'This computer belongs to Dave!'
'''
cmd = ['net',
'config',
'server',
u'/srvcomment:{0}'.format(salt.utils.locales.sdecode(desc))]
__salt__['cmd.run'](cmd, python_shell=False)
# Make sure the system exists
# Return an object containing current information array for the computer
system_info = win32net.NetServerGetInfo(None, 101)
# If desc is passed, decode it for unicode
if desc:
system_info['comment'] = desc.decode('utf-8')
else:
return False
# Apply new settings
try:
win32net.NetServerSetInfo(None, 101, system_info)
except win32net.error as exc:
(number, context, message) = exc
log.error('Failed to update system')
log.error('nbr: {0}'.format(number))
log.error('ctx: {0}'.format(context))
log.error('msg: {0}'.format(message))
return False
return {'Computer Description': get_computer_desc()}
set_computer_description = set_computer_desc
def get_system_info():
'''
Get system information.
:return:
Returns a Dictionary containing information about the system to include
name, description, version, etc...
:rtype: dict
'''
system_info = win32net.NetServerGetInfo(None, 101)
return system_info
def get_computer_desc():
'''
Get the Windows computer description
:return:
Returns the computer description if found. Otherwise returns False
CLI Example:
.. code-block:: bash
salt 'minion-id' system.get_computer_desc
'''
cmd = ['net', 'config', 'server']
lines = __salt__['cmd.run'](cmd, python_shell=False).splitlines()
for line in lines:
if 'Server Comment' in line:
_, desc = line.split('Server Comment', 1)
return desc.strip()
return False
desc = get_system_info()['comment']
return desc if desc else False
get_computer_description = get_computer_desc
@ -308,29 +442,28 @@ def join_domain(
username=None,
password=None,
account_ou=None,
account_exists=False
):
account_exists=False):
'''
Join a computer to an Active Directory domain
domain
:param str domain:
The domain to which the computer should be joined, e.g.
``my-company.com``
username
:param str username:
Username of an account which is authorized to join computers to the
specified domain. Need to be either fully qualified like
``user@domain.tld`` or simply ``user``
password
:param str password:
Password of the specified user
account_ou : None
:param str account_ou:
The DN of the OU below which the account for this computer should be
created when joining the domain, e.g.
``ou=computers,ou=departm_432,dc=my-company,dc=com``
account_exists : False
:param bool account_exists:
Needs to be set to ``True`` to allow re-using an existing account
CLI Example:
@ -354,27 +487,20 @@ def join_domain(
join_options = 3
if account_exists:
join_options = 1
cmd = ('wmic /interactive:off ComputerSystem Where '
'name="%computername%" call JoinDomainOrWorkgroup FJoinOptions={0} '
'Name={1} UserName={2} Password="{3}"'
).format(
join_options,
_cmd_quote(domain),
_cmd_quote(username),
password)
if account_ou:
# contrary to RFC#2253, 2.1, 'wmic' requires a ; as a RDN separator
# for the DN
account_ou = account_ou.replace(',', ';')
add_ou = ' AccountOU="{0}"'.format(account_ou)
cmd = cmd + add_ou
ret = __salt__['cmd.run'](cmd, python_shell=True)
if 'ReturnValue = 0;' in ret:
ret = windll.netapi32.NetJoinDomain(None,
domain,
account_ou,
username,
password,
join_options)
if ret == 0:
return {'Domain': domain}
return_values = {
2: 'Invalid OU or specifying OU is not supported',
5: 'Access is denied',
53: 'The network path was not found',
87: 'The parameter is incorrect',
110: 'The system cannot open the specified object',
1323: 'Unable to update the password',
@ -384,115 +510,249 @@ def join_domain(
2691: 'The machine is already joined to the domain',
2692: 'The machine is not currently joined to a domain',
}
for value in return_values:
if 'ReturnValue = {0};'.format(value) in ret:
log.error(return_values[value])
log.error(return_values[ret])
return False
def _validate_datetime(newdatetime, valid_formats):
def unjoin_domain(username=None, password=None, disable=False):
'''
Validate `newdatetime` against list of date/time formats understood by
windows.
Unjoin a computer from an Active Directory Domain
:param username:
Username of an account which is authorized to join computers to the
specified domain. Need to be either fully qualified like
``user@domain.tld`` or simply ``user``
:param str password:
Password of the specified user
:param bool disable:
Disable the user account in Active Directory. True to disable.
:return: True if successful. False if not. Log contains error code.
:rtype: bool
CLI Example:
.. code-block:: bash
salt 'minion-id' system.unjoin_domain username='unjoinuser' \\
password='unjoinpassword' disable=True
'''
unjoin_options = 0
if disable:
unjoin_options = 2
ret = windll.netapi32.NetUnjoinDomain(None,
username,
password,
unjoin_options)
if ret == 0:
return True
return_values = {
2: 'Invalid OU or specifying OU is not supported',
5: 'Access is denied',
53: 'The network path was not found',
87: 'The parameter is incorrect',
110: 'The system cannot open the specified object',
1323: 'Unable to update the password',
1326: 'Logon failure: unknown username or bad password',
1355: 'The specified domain either does not exist or could not be contacted',
2224: 'The account already exists',
2691: 'The machine is already joined to the domain',
2692: 'The machine is not currently joined to a domain',
}
log.error(return_values[ret])
return False
def _get_date_time_format(dt_string):
'''
Function that detects the date/time format for the string passed.
:param str dt_string:
A date/time string
:return: The format of the passed dt_string
:rtype: str
'''
valid_formats = [
'%I:%M:%S %p',
'%I:%M %p',
'%H:%M:%S',
'%H:%M',
'%Y-%m-%d',
'%m-%d-%y',
'%m-%d-%Y',
'%m/%d/%y',
'%m/%d/%Y',
'%Y/%m/%d'
]
for dt_format in valid_formats:
try:
datetime.datetime.strptime(newdatetime, dt_format)
return True
datetime.strptime(dt_string, dt_format)
return dt_format
except ValueError:
continue
return False
def _validate_time(newtime):
'''
Validate `newtime` against list of time formats understood by windows.
'''
valid_time_formats = [
'%I:%M:%S %p',
'%I:%M %p',
'%H:%M:%S',
'%H:%M'
]
return _validate_datetime(newtime, valid_time_formats)
def _validate_date(newdate):
'''
Validate `newdate` against list of date formats understood by windows.
'''
valid_date_formats = [
'%Y-%m-%d',
'%m/%d/%y',
'%y/%m/%d'
]
return _validate_datetime(newdate, valid_date_formats)
def get_system_time():
'''
Get the Windows system time
Get the system time.
CLI Example:
.. code-block:: bash
salt '*' system.get_system_time
:return: Returns the system time in HH:MM AM/PM format.
:rtype: str
'''
cmd = 'time /T'
return __salt__['cmd.run'](cmd, python_shell=True)
return datetime.strftime(datetime.now(), "%I:%M %p")
def set_system_time(newtime):
'''
Set the Windows system time
Set the system time.
:param str newtime:
The time to set. Can be any of the following formats.
- HH:MM:SS AM/PM
- HH:MM AM/PM
- HH:MM:SS (24 hour)
- HH:MM (24 hour)
:return: Returns True if successful. Otherwise False.
:rtype: bool
'''
# Parse time values from new time
time_format = _get_date_time_format(newtime)
dt_obj = datetime.strptime(newtime, time_format)
# Set time using set_system_date_time()
return set_system_date_time(hours=int(dt_obj.strftime('%H')),
minutes=int(dt_obj.strftime('%M')),
seconds=int(dt_obj.strftime('%S')))
def set_system_date_time(years=None,
months=None,
days=None,
hours=None,
minutes=None,
seconds=None):
'''
Set the system date and time. Each argument is an element of the date, but
not required. If an element is not passed, the current system value for that
element will be used. For example, if you don't pass the year, the current
system year will be used. (Used by set_system_date and set_system_time)
:param int years: Years digit, ie: 2015
:param int months: Months digit: 1 - 12
:param int days: Days digit: 1 - 31
:param int hours: Hours digit: 0 - 23
:param int minutes: Minutes digit: 0 - 59
:param int seconds: Seconds digit: 0 - 59
:return: True if successful. Otherwise False.
:rtype: bool
CLI Example:
.. code-block:: bash
salt '*' system.set_system_time '11:31:15 AM'
salt '*' system.set_system_date_ time 2015 5 12 11 37 53
'''
if not _validate_time(newtime):
# Get the current date/time
try:
date_time = win32api.GetLocalTime()
except win32api.error as exc:
(number, context, message) = exc
log.error('Failed to get local time')
log.error('nbr: {0}'.format(number))
log.error('ctx: {0}'.format(context))
log.error('msg: {0}'.format(message))
return False
cmd = 'time {0}'.format(newtime)
return not __salt__['cmd.retcode'](cmd, python_shell=True)
# Check for passed values. If not passed, use current values
if not years:
years = date_time[0]
if not months:
months = date_time[1]
if not days:
days = date_time[3]
if not hours:
hours = date_time[4]
if not minutes:
minutes = date_time[5]
if not seconds:
seconds = date_time[6]
# Create the time tuple to be passed to SetLocalTime, including day_of_week
time_tuple = (years, months, days, hours, minutes, seconds, 0)
try:
win32api.SetLocalTime(time_tuple)
except win32api.error as exc:
(number, context, message) = exc
log.error('Failed to set local time')
log.error('nbr: {0}'.format(number))
log.error('ctx: {0}'.format(context))
log.error('msg: {0}'.format(message))
return False
return True
def get_system_date():
'''
Get the Windows system date
:return: Returns the system date.
:rtype: str
CLI Example:
.. code-block:: bash
salt '*' system.get_system_date
'''
cmd = 'date /T'
return __salt__['cmd.run'](cmd, python_shell=True)
return datetime.strftime(datetime.now(), "%a %m/%d/%Y")
def set_system_date(newdate):
'''
Set the Windows system date. Use <mm-dd-yy> format for the date.
:param str newdate:
The date to set. Can be any of the following formats
- YYYY-MM-DD
- MM-DD-YYYY
- MM-DD-YY
- MM/DD/YYYY
- MM/DD/YY
- YYYY/MM/DD
CLI Example:
.. code-block:: bash
salt '*' system.set_system_date '03-28-13'
'''
if not _validate_date(newdate):
return False
cmd = 'date {0}'.format(newdate)
return not __salt__['cmd.retcode'](cmd, python_shell=True)
# Parse time values from new time
date_format = _get_date_time_format(newdate)
dt_obj = datetime.strptime(newdate, date_format)
# Set time using set_system_date_time()
return set_system_date_time(years=int(dt_obj.strftime('%Y')),
months=int(dt_obj.strftime('%m')),
days=int(dt_obj.strftime('%d')))
def start_time_service():
'''
Start the Windows time service
:return: True if successful. Otherwise False
:rtype: bool
CLI Example:
.. code-block:: bash
@ -506,6 +766,9 @@ def stop_time_service():
'''
Stop the Windows time service
:return: True if successful. Otherwise False
:rtype: bool
CLI Example:
.. code-block:: bash

View File

@ -135,7 +135,7 @@ authenication parameter names prefixed with ``git_pillar`` instead of ``gitfs``
:conf_master:`git_pillar_passphrase`, etc.).
A full list of the git_pillar configuration options can be found :ref:`here
<git-pillar-config-opts>`.
<git_pillar-config-opts>`.
.. _GitPython: https://github.com/gitpython-developers/GitPython
.. _pygit2: https://github.com/libgit2/pygit2

View File

@ -177,6 +177,17 @@ def save_load(jid, clear_load):
serial = salt.payload.Serial(__opts__)
# Save the invocation information
try:
if not os.path.exists(jid_dir):
os.makedirs(jid_dir)
serial.dump(
clear_load,
salt.utils.fopen(os.path.join(jid_dir, LOAD_P), 'w+b')
)
except IOError as exc:
log.warning('Could not write job invocation cache file: {0}'.format(exc))
# if you have a tgt, save that for the UI etc
if 'tgt' in clear_load:
ckminions = salt.utils.minions.CkMinions(__opts__)
@ -191,19 +202,9 @@ def save_load(jid, clear_load):
minions,
salt.utils.fopen(os.path.join(jid_dir, MINIONS_P), 'w+b')
)
except IOError:
except IOError as exc:
log.warning('Could not write job cache file for minions: {0}'.format(minions))
# Save the invocation information
try:
if not os.path.exists(jid_dir):
os.makedirs(jid_dir)
serial.dump(
clear_load,
salt.utils.fopen(os.path.join(jid_dir, LOAD_P), 'w+b')
)
except IOError as exc:
log.warning('Could not write job invocation cache file: {0}'.format(exc))
log.debug('Job cache write failure: {0}'.format(exc))
def get_load(jid):

View File

@ -49,20 +49,7 @@ def hash(*args, **kwargs):
salt-run survey.hash "*" file.get_hash /etc/salt/minion survey_sort=up
'''
bulk_ret = _get_pool_results(*args, **kwargs)
for k in bulk_ret:
print('minion pool :\n'
'------------')
print(k['pool'])
print('pool size :\n'
'----------')
print(' ' + str(len(k['pool'])))
print('pool result :\n'
'-------')
print(' ' + str(k['result']))
print('\n')
return bulk_ret
return _get_pool_results(*args, **kwargs)
def diff(*args, **kwargs):

View File

@ -17,6 +17,7 @@ except ImportError:
# Import salt libs
from salt.exceptions import SaltRenderError
import salt.utils
import salt.utils.gitfs
import logging
import salt.minion
import salt.loader
@ -24,10 +25,12 @@ import salt.template
log = logging.getLogger(__name__)
PER_REMOTE_PARAMS = ('ssl_verify',)
def genrepo():
'''
Generate win_repo_cachefile based on sls files in the win_repo
Generate winrepo_cachefile based on sls files in the winrepo_dir
CLI Example:
@ -35,13 +38,31 @@ def genrepo():
salt-run winrepo.genrepo
'''
if 'win_repo' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = __opts__['win_repo']
else:
winrepo_dir = __opts__['winrepo_dir']
if 'win_repo_mastercachefile' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo_mastercachefile\' config option is deprecated, '
'please use \'winrepo_cachefile\' instead.'
)
winrepo_cachefile = __opts__['win_repo_mastercachefile']
else:
winrepo_cachefile = __opts__['winrepo_cachefile']
ret = {}
repo = __opts__['win_repo']
if not os.path.exists(repo):
os.makedirs(repo)
winrepo = __opts__['win_repo_mastercachefile']
if not os.path.exists(winrepo_dir):
os.makedirs(winrepo_dir)
renderers = salt.loader.render(__opts__, __salt__)
for root, _, files in os.walk(repo):
for root, _, files in os.walk(winrepo_dir):
for name in files:
if name.endswith('.sls'):
try:
@ -50,25 +71,44 @@ def genrepo():
renderers,
__opts__['renderer'])
except SaltRenderError as exc:
log.debug('Failed to render {0}.'.format(os.path.join(root, name)))
log.debug(
'Failed to render {0}.'.format(
os.path.join(root, name)
)
)
log.debug('Error: {0}.'.format(exc))
continue
if config:
revmap = {}
for pkgname, versions in six.iteritems(config):
log.debug(
'Compiling winrepo data for package \'{0}\''
.format(pkgname)
)
for version, repodata in six.iteritems(versions):
log.debug(
'Compiling winrepo data for {0} version {1}'
.format(pkgname, version)
)
if not isinstance(version, six.string_types):
config[pkgname][str(version)] = \
config[pkgname].pop(version)
if not isinstance(repodata, dict):
log.debug('Failed to compile'
'{0}.'.format(os.path.join(root, name)))
__jid_event__.fire_event({'error': 'Failed to compile {0}.'.format(os.path.join(root, name))}, 'progress')
log.debug(
'Failed to compile {0}.'.format(
os.path.join(root, name)
)
)
__jid_event__.fire_event(
{'error': 'Failed to compile {0}.'.format(
os.path.join(root, name))},
'progress')
continue
revmap[repodata['full_name']] = pkgname
ret.setdefault('repo', {}).update(config)
ret.setdefault('name_map', {}).update(revmap)
with salt.utils.fopen(os.path.join(repo, winrepo), 'w+b') as repo:
with salt.utils.fopen(
os.path.join(winrepo_dir, winrepo_cachefile), 'w+b') as repo:
repo.write(msgpack.dumps(ret))
return ret
@ -83,23 +123,70 @@ def update_git_repos():
salt-run winrepo.update_git_repos
'''
ret = {}
mminion = salt.minion.MasterMinion(__opts__)
repo = __opts__['win_repo']
gitrepos = __opts__['win_gitrepos']
for gitrepo in gitrepos:
if '/' in gitrepo:
targetname = gitrepo.split('/')[-1]
else:
targetname = gitrepo
rev = None
# If a revision is specified, use it.
if len(gitrepo.strip().split(' ')) > 1:
rev, gitrepo = gitrepo.strip().split(' ')
gittarget = os.path.join(repo, targetname)
result = mminion.states['git.latest'](gitrepo,
rev=rev,
target=gittarget,
force=True)
ret[result['name']] = result['result']
return ret
if 'win_repo' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = __opts__['win_repo']
else:
winrepo_dir = __opts__['winrepo_dir']
if 'win_gitrepos' in __opts__:
salt.utils.warn_until(
'Nitrogen',
'The \'win_gitrepos\' config option is deprecated, please use '
'\'winrepo_remotes\' instead.'
)
winrepo_remotes = __opts__['win_gitrepos']
else:
winrepo_remotes = __opts__['winrepo_remotes']
if not any((salt.utils.gitfs.HAS_GITPYTHON, salt.utils.gitfs.HAS_PYGIT2)):
# Use legacy code
if not salt.utils.is_windows():
# Don't warn on Windows, because Windows can't do cool things like
# use pygit2. It has to fall back to git.latest.
salt.utils.warn_until(
'Nitrogen',
'winrepo git support now requires either GitPython or pygit2. '
'Please install either GitPython >= {0} (or pygit2 >= {1} with '
'libgit2 >= {2}), clear out the winrepo_dir ({3}), and '
'restart the salt-master service.'.format(
salt.utils.gitfs.GITPYTHON_MINVER,
salt.utils.gitfs.PYGIT2_MINVER,
salt.utils.gitfs.LIBGIT2_MINVER,
winrepo_dir
)
)
ret = {}
mminion = salt.minion.MasterMinion(__opts__)
for remote in winrepo_remotes:
if '/' in remote:
targetname = remote.split('/')[-1]
else:
targetname = remote
rev = None
# If a revision is specified, use it.
if len(remote.strip().split(' ')) > 1:
rev, remote = remote.strip().split(' ')
gittarget = os.path.join(winrepo_dir, targetname)
result = mminion.states['git.latest'](remote,
rev=rev,
target=gittarget,
force=True)
ret[result['name']] = result['result']
return ret
else:
# New winrepo code utilizing salt.utils.gitfs
try:
winrepo = salt.utils.gitfs.WinRepo(__opts__)
winrepo.init_remotes(winrepo_remotes, PER_REMOTE_PARAMS)
winrepo.fetch_remotes()
winrepo.checkout()
except Exception as exc:
msg = 'Failed to update winrepo_remotes: {0}'.format(exc)
log.error(msg, exc_info_on_loglevel=logging.DEBUG)
return msg
return winrepo.winrepo_dirs

View File

@ -461,7 +461,7 @@ def present(name, bare=True, user=None, force=False, shared=None):
shared
Specify the permission for sharing, see git-init for details (Default: None)
.. versionadded:: XXXX
.. versionadded:: 2015.5
'''
name = os.path.expanduser(name)
ret = {'name': name, 'result': True, 'comment': '', 'changes': {}}

View File

@ -359,11 +359,15 @@ def present(name,
win_description (Windows Only)
A brief description of the purpose of the users account.
.. versionchanged:: 2015.8.0
'''
fullname = salt.utils.locales.sdecode(fullname)
roomnumber = salt.utils.locales.sdecode(roomnumber)
workphone = salt.utils.locales.sdecode(workphone)
homephone = salt.utils.locales.sdecode(homephone)
'''
if fullname is not None:
fullname = salt.utils.locales.sdecode(fullname)
if roomnumber is not None:
roomnumber = salt.utils.locales.sdecode(roomnumber)
if workphone is not None:
workphone = salt.utils.locales.sdecode(workphone)
if homephone is not None:
homephone = salt.utils.locales.sdecode(homephone)
ret = {'name': name,
'changes': {},

View File

@ -16,6 +16,7 @@ import itertools
# Salt Modules
import salt.runner
import salt.utils
import salt.config
@ -57,28 +58,52 @@ def genrepo(name, force=False, allow_empty=False):
'changes': {},
'comment': ''}
master_config = salt.config.master_config(os.path.join(salt.syspaths.CONFIG_DIR, 'master'))
win_repo = master_config['win_repo']
win_repo_mastercachefile = master_config['win_repo_mastercachefile']
master_config = salt.config.master_config(
os.path.join(salt.syspaths.CONFIG_DIR, 'master')
)
# Check if the win_repo directory exists
# if not search for a file with a newer mtime than the win_repo_mastercachefile file
if 'win_repo' in master_config:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = master_config['win_repo']
else:
winrepo_dir = master_config['winrepo_dir']
if 'win_repo_mastercachefile' in master_config:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo_mastercachefile\' config option is deprecated, '
'please use \'winrepo_cachefile\' instead.'
)
winrepo_cachefile = master_config['win_repo_mastercachefile']
else:
winrepo_cachefile = master_config['winrepo_cachefile']
# We're actually looking for the full path to the cachefile here, so
# prepend the winrepo_dir
winrepo_cachefile = os.path.join(winrepo_dir, winrepo_cachefile)
# Check if the winrepo directory exists
# if not search for a file with a newer mtime than the winrepo_cachefile file
execute = False
if not force:
if not os.path.exists(win_repo):
if not os.path.exists(winrepo_dir):
ret['result'] = False
ret['comment'] = 'missing {0}'.format(win_repo)
ret['comment'] = '{0} is missing'.format(winrepo_dir)
return ret
elif not os.path.exists(win_repo_mastercachefile):
elif not os.path.exists(winrepo_cachefile):
execute = True
ret['comment'] = 'missing {0}'.format(win_repo_mastercachefile)
ret['comment'] = '{0} is missing'.format(winrepo_cachefile)
else:
win_repo_mastercachefile_mtime = os.stat(win_repo_mastercachefile)[stat.ST_MTIME]
for root, dirs, files in os.walk(win_repo):
winrepo_cachefile_mtime = os.stat(winrepo_cachefile)[stat.ST_MTIME]
for root, dirs, files in os.walk(winrepo_dir):
for name in itertools.chain(files, dirs):
full_path = os.path.join(root, name)
if os.stat(full_path)[stat.ST_MTIME] > win_repo_mastercachefile_mtime:
ret['comment'] = 'mtime({0}) < mtime({1})'.format(win_repo_mastercachefile, full_path)
if os.stat(full_path)[stat.ST_MTIME] > winrepo_cachefile_mtime:
ret['comment'] = 'mtime({0}) < mtime({1})'.format(winrepo_cachefile, full_path)
execute = True
break
@ -93,7 +118,7 @@ def genrepo(name, force=False, allow_empty=False):
runner_ret = runner.cmd('winrepo.genrepo', [])
ret['changes'] = {'winrepo': runner_ret}
if isinstance(runner_ret, dict) and runner_ret == {} and not allow_empty:
os.remove(win_repo_mastercachefile)
os.remove(winrepo_cachefile)
ret['result'] = False
ret['comment'] = 'winrepo.genrepo returned empty'
return ret

View File

@ -84,6 +84,14 @@ except ImportError:
log = logging.getLogger(__name__)
# Minimum versions for backend providers
GITPYTHON_MINVER = '0.3'
PYGIT2_MINVER = '0.20.3'
LIBGIT2_MINVER = '0.20.0'
# dulwich.__version__ is a versioninfotuple so we can compare tuples
# instead of using distutils.version.LooseVersion
DULWICH_MINVER = (0, 9, 4)
def failhard(role):
'''
@ -175,6 +183,12 @@ class GitProvider(object):
self.id = remote
self.get_url()
# Winrepo doesn't support the 'root' option, but it still must be part
# of the GitProvider object because other code depends on it. Add it as
# an empty string.
if 'root' not in repo_conf:
repo_conf['root'] = ''
# Set all repo config params as attributes
for key, val in six.iteritems(repo_conf):
setattr(self, key, val)
@ -212,15 +226,15 @@ class GitProvider(object):
log.critical(msg, exc_info_on_loglevel=logging.DEBUG)
failhard(self.role)
def check_pillar_root(self):
def check_root(self):
'''
Check if the relative root path exists in the checked-out copy of the
remote. Return the full path to that relative root if it does exist,
otherwise return None.
'''
pillar_root = os.path.join(self.cachedir, self.root)
if os.path.isdir(pillar_root):
return pillar_root
root_dir = os.path.join(self.cachedir, self.root).rstrip(os.sep)
if os.path.isdir(root_dir):
return root_dir
log.error(
'Root path \'{0}\' not present in {1} remote \'{2}\', '
'skipping.'.format(self.root, self.role, self.id)
@ -350,10 +364,10 @@ class GitProvider(object):
'''
Examine self.id and assign self.url (and self.branch, for git_pillar)
'''
if self.role == 'git_pillar':
# With git_pillar, the remote is specified in the format
# "<branch> <url>", so that we can get a unique identifier to
# hash for each remote.
if self.role in ('git_pillar', 'winrepo'):
# With winrepo and git_pillar, the remote is specified in the
# format '<branch> <url>', so that we can get a unique identifier
# to hash for each remote.
try:
self.branch, self.url = self.id.split(None, 1)
except ValueError:
@ -394,7 +408,7 @@ class GitPython(GitProvider):
self.repo.git.checkout(ref)
except Exception:
continue
return self.check_pillar_root()
return self.check_root()
log.error(
'Failed to checkout {0} from {1} remote \'{2}\': remote ref does '
'not exist'.format(self.branch, self.role, self.id)
@ -578,7 +592,7 @@ class GitPython(GitProvider):
except KeyError:
# File not found or repo_path points to a directory
break
return blob, blob.hexsha
return blob, blob.hexsha if blob is not None else blob
def get_tree(self, tgt_env):
'''
@ -646,10 +660,10 @@ class Pygit2(GitProvider):
self.repo.checkout(local_ref)
# Reset HEAD to the commit id of the remote ref
self.repo.reset(oid, pygit2.GIT_RESET_HARD)
return self.check_pillar_root()
return self.check_root()
elif tag_ref in refs:
self.repo.checkout(tag_ref)
return self.check_pillar_root()
return self.check_root()
except Exception as exc:
log.error(
'Failed to checkout {0} from {1} remote \'{2}\': {3}'.format(
@ -933,7 +947,7 @@ class Pygit2(GitProvider):
blob = self.repo[oid]
except KeyError:
break
return blob, blob.hex
return blob, blob.hex if blob is not None else blob
def get_tree(self, tgt_env):
'''
@ -1271,7 +1285,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method
break
except KeyError:
break
return blob, blob.sha().hexdigest()
return blob, blob.sha().hexdigest() if blob is not None else blob
def get_conf(self):
'''
@ -1437,11 +1451,14 @@ class GitBase(object):
'''
Base class for gitfs/git_pillar
'''
def __init__(self, opts, valid_providers=VALID_PROVIDERS):
def __init__(self, opts, valid_providers=VALID_PROVIDERS, cache_root=None):
self.opts = opts
self.valid_providers = valid_providers
self.get_provider()
self.cache_root = os.path.join(self.opts['cachedir'], self.role)
if cache_root is not None:
self.cache_root = cache_root
else:
self.cache_root = os.path.join(self.opts['cachedir'], self.role)
self.env_cache = os.path.join(self.cache_root, 'envs.p')
self.hash_cachedir = os.path.join(
self.cache_root, self.role, 'hash')
@ -1782,15 +1799,14 @@ class GitBase(object):
# pylint: disable=no-member
gitver = distutils.version.LooseVersion(git.__version__)
minver_str = '0.3.0'
minver = distutils.version.LooseVersion(minver_str)
minver = distutils.version.LooseVersion(GITPYTHON_MINVER)
# pylint: enable=no-member
errors = []
if gitver < minver:
errors.append(
'Git fileserver backend is enabled in master config file, but '
'the GitPython version is earlier than {0}. Version {1} '
'detected.'.format(minver_str, git.__version__)
'detected.'.format(GITPYTHON_MINVER, git.__version__)
)
if not salt.utils.which('git'):
errors.append(
@ -1834,12 +1850,10 @@ class GitBase(object):
# pylint: disable=no-member
pygit2ver = distutils.version.LooseVersion(pygit2.__version__)
pygit2_minver_str = '0.20.3'
pygit2_minver = distutils.version.LooseVersion(pygit2_minver_str)
pygit2_minver = distutils.version.LooseVersion(PYGIT2_MINVER)
libgit2ver = distutils.version.LooseVersion(pygit2.LIBGIT2_VERSION)
libgit2_minver_str = '0.20.0'
libgit2_minver = distutils.version.LooseVersion(libgit2_minver_str)
libgit2_minver = distutils.version.LooseVersion(LIBGIT2_MINVER)
# pylint: enable=no-member
errors = []
@ -1847,13 +1861,13 @@ class GitBase(object):
errors.append(
'Git fileserver backend is enabled in master config file, but '
'pygit2 version is earlier than {0}. Version {1} detected.'
.format(pygit2_minver_str, pygit2.__version__)
.format(PYGIT2_MINVER, pygit2.__version__)
)
if libgit2ver < libgit2_minver:
errors.append(
'Git fileserver backend is enabled in master config file, but '
'libgit2 version is earlier than {0}. Version {1} detected.'
.format(libgit2_minver_str, pygit2.LIBGIT2_VERSION)
.format(LIBGIT2_MINVER, pygit2.LIBGIT2_VERSION)
)
if not salt.utils.which('git'):
errors.append(
@ -1893,16 +1907,13 @@ class GitBase(object):
elif 'dulwich' not in self.valid_providers:
return False
dulwich_version = dulwich.__version__
dulwich_min_version = (0, 9, 4)
errors = []
if dulwich_version < dulwich_min_version:
if dulwich.__version__ < DULWICH_MINVER:
errors.append(
'Git fileserver backend is enabled in the master config file, but '
'the installed version of Dulwich is earlier than {0}. Version {1} '
'detected.'.format(dulwich_min_version, dulwich_version)
'detected.'.format(DULWICH_MINVER, dulwich.__version__)
)
if errors:
@ -2218,7 +2229,6 @@ class GitPillar(GitBase):
else:
base_branch = self.opts['{0}_branch'.format(self.role)]
env = 'base' if repo.branch == base_branch else repo.branch
log.critical(env)
self.pillar_dirs[cachedir] = env
def update(self):
@ -2232,3 +2242,36 @@ class GitPillar(GitBase):
and just run pillar.fetch_remotes() there.
'''
return self.fetch_remotes()
class WinRepo(GitBase):
'''
Functionality specific to the winrepo runner
'''
def __init__(self, opts):
self.role = 'winrepo'
# Dulwich has no function to check out a branch/tag, so this will be
# limited to GitPython and Pygit2 for the forseeable future.
if 'win_repo' in opts:
salt.utils.warn_until(
'Nitrogen',
'The \'win_repo\' config option is deprecated, please use '
'\'winrepo_dir\' instead.'
)
winrepo_dir = opts['win_repo']
else:
winrepo_dir = opts['winrepo_dir']
GitBase.__init__(self,
opts,
valid_providers=('gitpython', 'pygit2'),
cache_root=winrepo_dir)
def checkout(self):
'''
Checkout the targeted branches/tags from the winrepo remotes
'''
self.winrepo_dirs = {}
for repo in self.remotes:
cachedir = repo.checkout()
if cachedir is not None:
self.winrepo_dirs[repo.url] = cachedir

View File

@ -168,6 +168,31 @@ class UserTest(integration.ModuleCase,
ret = self.run_state('user.absent', name='salt_test')
self.assertSaltTrueReturn(ret)
@destructiveTest
@skipIf(os.geteuid() != 0, 'you must be root to run this test')
def test_user_present_gecos_none_fields(self):
'''
This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
It ensures that if no GECOS data is supplied, the fields will be coerced
into empty strings as opposed to the string "None".
'''
ret = self.run_state(
'user.present', name='salt_test', fullname=None, roomnumber=None,
workphone=None, homephone=None
)
self.assertSaltTrueReturn(ret)
ret = self.run_function('user.info', ['salt_test'])
self.assertReturnNonEmptySaltType(ret)
self.assertEqual('', ret['fullname'])
self.assertEqual('', ret['roomnumber'])
self.assertEqual('', ret['workphone'])
self.assertEqual('', ret['homephone'])
ret = self.run_state('user.absent', name='salt_test')
self.assertSaltTrueReturn(ret)
if __name__ == '__main__':
from integration import run_tests

View File

@ -90,9 +90,9 @@ class TimezoneTestCase(TestCase):
'''
Test to unlinks, then symlinks /etc/localtime to the set timezone.
'''
ret = ('Zone does not exist: /usr/share/lib/zoneinfo/timezone')
mock = MagicMock(side_effect=[False, True, True])
with patch.dict(timezone.__grains__, {'os_family': 'Solaris'}):
def zone_checking_and_unlinking():
ret = ('Zone does not exist: /usr/share/lib/zoneinfo/timezone')
mock = MagicMock(side_effect=[False, True, True])
with patch.object(os.path, 'exists', mock):
self.assertEqual(timezone.set_zone('timezone'), ret)
@ -102,6 +102,14 @@ class TimezoneTestCase(TestCase):
MagicMock(return_value=None)}):
self.assertTrue(timezone.set_zone('timezone'))
with patch.dict(timezone.__grains__, {'os_family': 'Solaris'}):
with patch.object(salt.utils, 'which', return_value=False):
zone_checking_and_unlinking()
with patch.object(salt.utils, 'which', return_value=True):
with patch.dict(timezone.__salt__, {'cmd.run': MagicMock(return_value='')}):
zone_checking_and_unlinking()
def test_zone_compare(self):
'''
Test to checks the hash sum between the given timezone, and the

View File

@ -36,14 +36,14 @@ class WinRepoTestCase(TestCase):
@patch('salt.loader.render', MagicMock(return_valu=''))
def test_genrepo(self):
'''
Test to generate win_repo_cachefile
based on sls files in the win_repo
Test to generate winrepo_cachefile based on sls files in the
winrepo_dir
'''
with patch.dict(win_repo.__opts__, {'win_repo': 'c:\\salt'}):
with patch.dict(win_repo.__opts__, {'winrepo_dir': 'c:\\salt'}):
mock_bool = MagicMock(return_value=True)
with patch.object(os.path, 'exists', mock_bool):
with patch.dict(win_repo.__opts__,
{'win_repo_cachefile': 'cache.c'}):
{'winrepo_cachefile': 'cache.c'}):
mock = MagicMock(return_value={})
with patch.object(os, 'walk', mock):
with patch('salt.utils.fopen', mock_open()):
@ -53,11 +53,11 @@ class WinRepoTestCase(TestCase):
def test_update_git_repos(self):
'''
Test to checkout git repos containing
Windows Software Package Definitions
Test to checkout git repos containing Windows software package
definitions
'''
with patch.dict(win_repo.__opts__, {'win_repo': 'c:\\salt'}):
with patch.dict(win_repo.__opts__, {'win_gitrepos': {}}):
with patch.dict(win_repo.__opts__, {'winrepo_dir': 'c:\\salt'}):
with patch.dict(win_repo.__opts__, {'winrepo_remotes': {}}):
mock = MagicMock(return_value=True)
with patch.object(salt.output, 'display_output', mock):
self.assertDictEqual(win_repo.update_git_repos(), {})

View File

@ -5,6 +5,7 @@
# Import Python Libs
from __future__ import absolute_import
from datetime import datetime
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
@ -20,6 +21,16 @@ ensure_in_syspath('../../')
# Import Salt Libs
from salt.modules import win_system
# Import 3rd Party Libs
try:
import win32net # pylint: disable=W0611
import win32api # pylint: disable=W0611
import pywintypes # pylint: disable=W0611
from ctypes import windll # pylint: disable=W0611
HAS_WIN32NET_MODS = True
except ImportError:
HAS_WIN32NET_MODS = False
win_system.__salt__ = {}
@ -43,6 +54,7 @@ class WinSystemTestCase(TestCase):
self.assertEqual(win_system.init(3),
'Not implemented on Windows at this time.')
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_poweroff(self):
'''
Test to poweroff a running system
@ -51,6 +63,7 @@ class WinSystemTestCase(TestCase):
with patch.object(win_system, 'shutdown', mock):
self.assertEqual(win_system.poweroff(), 'salt')
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_reboot(self):
'''
Test to reboot the system
@ -60,6 +73,7 @@ class WinSystemTestCase(TestCase):
self.assertEqual(win_system.reboot(), 'salt')
mock.assert_called_once_with(['shutdown', '/r', '/t', '300'], python_shell=False)
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_reboot_with_timeout_in_minutes(self):
'''
Test to reboot the system with a timeout
@ -69,6 +83,7 @@ class WinSystemTestCase(TestCase):
self.assertEqual(win_system.reboot(5, in_seconds=False), 'salt')
mock.assert_called_once_with(['shutdown', '/r', '/t', '300'], python_shell=False)
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_reboot_with_timeout_in_seconds(self):
'''
Test to reboot the system with a timeout
@ -78,6 +93,7 @@ class WinSystemTestCase(TestCase):
self.assertEqual(win_system.reboot(5, in_seconds=True), 'salt')
mock.assert_called_once_with(['shutdown', '/r', '/t', '5'], python_shell=False)
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_reboot_with_wait(self):
'''
Test to reboot the system with a timeout and
@ -91,6 +107,7 @@ class WinSystemTestCase(TestCase):
mock.assert_called_once_with(['shutdown', '/r', '/t', '300'], python_shell=False)
sleep_mock.assert_called_once_with(330)
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_shutdown(self):
'''
Test to shutdown a running system
@ -99,6 +116,7 @@ class WinSystemTestCase(TestCase):
with patch.dict(win_system.__salt__, {'cmd.run': mock}):
self.assertEqual(win_system.shutdown(), 'salt')
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_shutdown_hard(self):
'''
Test to shutdown a running system with no timeout or warning
@ -107,6 +125,7 @@ class WinSystemTestCase(TestCase):
with patch.dict(win_system.__salt__, {'cmd.run': mock}):
self.assertEqual(win_system.shutdown_hard(), 'salt')
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_set_computer_name(self):
'''
Test to set the Windows computer name
@ -126,6 +145,7 @@ class WinSystemTestCase(TestCase):
self.assertFalse(win_system.set_computer_name("salt"))
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_get_pending_computer_name(self):
'''
Test to get a pending computer name.
@ -140,6 +160,7 @@ class WinSystemTestCase(TestCase):
self.assertEqual(win_system.get_pending_computer_name(),
'(salt)')
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_get_computer_name(self):
'''
Test to get the Windows computer name
@ -150,6 +171,7 @@ class WinSystemTestCase(TestCase):
self.assertFalse(win_system.get_computer_name())
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_set_computer_desc(self):
'''
Test to set the Windows computer description
@ -163,6 +185,7 @@ class WinSystemTestCase(TestCase):
),
{'Computer Description': "Salt's comp"})
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_get_computer_desc(self):
'''
Test to get the Windows computer description
@ -173,6 +196,7 @@ class WinSystemTestCase(TestCase):
self.assertFalse(win_system.get_computer_desc())
@skipIf(not HAS_WIN32NET_MODS, 'this test needs w32net and other windows libraries')
def test_join_domain(self):
'''
Test to join a computer to an Active Directory domain
@ -193,10 +217,16 @@ class WinSystemTestCase(TestCase):
'''
Test to get system time
'''
mock = MagicMock(return_value="11:31:15 AM")
with patch.dict(win_system.__salt__, {'cmd.run': mock}):
self.assertEqual(win_system.get_system_time(), '11:31:15 AM')
tm = datetime.strftime(datetime.now(), "%I:%M %p")
win_tm = win_system.get_system_time()
try:
self.assertEqual(win_tm, tm)
except AssertionError:
# handle race condition
import re
self.assertTrue(re.search(r'^\d{2}:\d{2} \w{2}$', win_tm))
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_set_system_time(self):
'''
Test to set system time
@ -213,10 +243,10 @@ class WinSystemTestCase(TestCase):
'''
Test to get system date
'''
mock = MagicMock(return_value="03-28-13")
with patch.dict(win_system.__salt__, {'cmd.run': mock}):
self.assertEqual(win_system.get_system_date(), '03-28-13')
date = datetime.strftime(datetime.now(), "%a %m/%d/%Y")
self.assertEqual(win_system.get_system_date(), date)
@skipIf(not HAS_WIN32NET_MODS, 'this test needs the w32net library')
def test_set_system_date(self):
'''
Test to set system date

View File

@ -57,11 +57,11 @@ class MockRunnerClient(object):
@skipIf(NO_MOCK, NO_MOCK_REASON)
class WinrepoTestCase(TestCase):
'''
Validate the winrepo state
Validate the winrepo state
'''
def test_genrepo(self):
'''
Test to refresh the winrepo.p file of the repository
Test to refresh the winrepo.p file of the repository
'''
ret = {'name': 'salt',
'changes': {},
@ -70,21 +70,21 @@ class WinrepoTestCase(TestCase):
mock = MagicMock(side_effect=[False, True, True, True, True, True,
True])
with patch.object(os.path, 'exists', mock):
ret.update({'comment': 'missing /srv/salt/win/repo'})
ret.update({'comment': '/srv/salt/win/repo is missing'})
self.assertDictEqual(winrepo.genrepo('salt'), ret)
mock = MagicMock(return_value={'win_repo': 'salt',
'win_repo_mastercachefile': 'abc'})
mock = MagicMock(return_value={'winrepo_dir': 'salt',
'winrepo_cachefile': 'abc'})
with patch.object(salt.config, 'master_config', mock):
mock = MagicMock(return_value=[0, 1, 2, 3, 4, 5, 6, 7, 8])
with patch.object(os, 'stat', mock):
mock = MagicMock(return_value=[])
with patch.object(os, 'walk', mock):
with patch.dict(winrepo.__opts__, {"test": True}):
with patch.dict(winrepo.__opts__, {'test': True}):
ret.update({'comment': '', 'result': None})
self.assertDictEqual(winrepo.genrepo('salt'), ret)
with patch.dict(winrepo.__opts__, {"test": False}):
with patch.dict(winrepo.__opts__, {'test': False}):
ret.update({'result': True})
self.assertDictEqual(winrepo.genrepo('salt'), ret)