Compare commits

..

646 Commits

Author SHA1 Message Date
1e8aa2499e set canonical url for 2.3 release 2022-06-28 12:57:19 -07:00
89424880ff [2.3][backport] Update eol docs for 2.3 (#72760)
* manually stub out old porting guides

(cherry picked from commit dedd8fa771)

* manually remove Edit on Github

(cherry picked from commit d5c30abcca)

* add eol banner

(cherry picked from commit 5daf37d89e)

* point all older release pages to devel (#71428)

(cherry picked from commit 3be597419d)
(cherry picked from commit 35abfbf582)
2020-12-01 09:44:08 -08:00
b20520f500 Adds the non-deprecated ansible_host var (#34452)
OpenStack dynamic inventory is still using the deprecated
ansible_ssh_host. This patch adds ansible_host until such
time as ansible_ssh_host is removed

This is a backport from [1].

[1]: https://github.com/ansible/ansible/pull/23153
2018-05-22 16:40:44 -05:00
fde8c9b4ef Pin httptester SHA.
(cherry picked from commit 8232c95f42)
2018-03-20 07:14:54 -07:00
02f3eed0e9 Fix uri test on Python 2.6.
(cherry picked from commit 1fd9a616a4)
2018-03-19 23:15:16 -07:00
aea7abcb15 New release v2.3.4.0-0.1.rc1 2018-02-28 12:51:06 -06:00
0db22a8b29 Temporarily disable subversion test on osx.
(cherry picked from commit f283edcb19)
2018-02-26 13:27:43 -08:00
52f6b03a11 Fix rst link syntax.
(cherry picked from commit 1f43d5fc75)
2018-02-26 11:34:55 -08:00
fca0cccebf system/service module initctl location usage (#19712)
* Call initctl version based on initctl's retrieved location

* Remove the use of start/stop/restart in favor of initctl

* Provide correct argument order for initctl usage
2018-02-26 11:38:04 -06:00
c0d3915bd2 Add https retrieval via TLSv1.2 to changelog 2018-02-23 11:07:27 -08:00
6020c0d4f6 Prefer the stdlib SSLContext over urllib3 context
We do not go through the effort of finding the right PROTOCOL setting if
we have SSLContext in the stdlib.  So we do not want to hit the code
that uses PROTOCOL to set the urllib3-provided ssl context when
SSLContext is available.  Also, the urllib3 implementation appears to
have a bug in some recent versions.  Preferring the stdlib version will
work around that for those with Python-2.7.9+ as well.

Fixes #26235
Fixes #25402
Fixes #31998

(cherry picked from commit 725ae96e1b)
2018-02-23 11:05:43 -08:00
bc9b44d907 Fix pip integration test.
(cherry picked from commit ea70b49b11)
2018-01-31 23:28:24 -08:00
fb14b36f7f Remove EOL openSUSE Leap 42.2 from CI.
(cherry picked from commit abbc1ed4e6)
2018-01-31 21:53:23 -08:00
857f959135 loop doesn't exist in 2.4
(cherry picked from commit 6a6ae0cede)
2018-01-24 08:51:05 -08:00
5bd16d438d Add environment in loop fix to changelog 2018-01-24 08:51:05 -08:00
deaa9a21f9 Fix using loops with environment and add tests (#32796)
(cherry picked from commit 7bb35e8781)
2018-01-24 08:51:05 -08:00
6233daaa44 Add ssh flush() fix to changelog 2018-01-18 09:34:57 -08:00
f0cae29d57 Ensure that the become password is written on py3 in the ssh connection plugin. Fixes #34727
(cherry picked from commit 29c1d5cb5d)
2018-01-18 09:33:24 -08:00
2c116617de Fix Linux blockdevice size computation (#34645)
Linux' sysfs _always_ reports device size in 512b sector units,
regardless of the device's actual, physical blocksize.

Backport of PR#34475 originally written by jtru

Original Commit ID: 603d31685c

Signed-off-by: Adam Miller <admiller@redhat.com>
2018-01-10 06:27:22 -08:00
204d0f7bea Make xattr test conditional on feature support.
(cherry picked from commit 77726b471f)
2018-01-08 23:58:30 -08:00
fcba7a086a avoid use of Write-Host in config script
(cherry picked from commit 82996d5b26)
2017-12-20 22:52:24 -08:00
a787488990 add GlobalHttpFirewallAccess arg
(cherry picked from commit a9ca0389b6)
2017-12-20 21:35:20 -08:00
0255ab2e27 New release v2.3.3.0-1 2017-12-20 11:49:41 -06:00
797d999513 Update FreeBSD completion for ansible-test.
(cherry picked from commit 73132d3906)
2017-12-05 22:34:30 -08:00
3a963a68c2 Limit pytest < 3.3.0 for python 2.6.
(cherry picked from commit 58286ef93b)
2017-12-05 22:32:45 -08:00
6e1f29cde2 Limit paramiko to < 2.4.0 for python 2.6.
(cherry picked from commit 5f5e150771)
2017-12-05 22:32:37 -08:00
30b0103ceb Update FreeBSD versions used in CI. 2017-12-05 21:21:01 -08:00
218103d540 Update vyos completion in network.txt.
(cherry picked from commit 3a6fad38fa)
2017-11-22 10:17:35 -08:00
f0f2031eaf Use vyos/1.1.8 in CI.
(cherry picked from commit 887f227994)
2017-11-22 10:16:13 -08:00
b123fa4d6f Fix and re-enable zypper* integration tests in CI.
(cherry picked from commit 781219bcfd)
2017-11-17 15:54:23 -08:00
7256dd17ae Pin Shippable build image to v5.4.1. (#32988)
* Pin Shippable build image to v5.4.1.
* Remove `pre_ci` to eliminate extra git sync.
2017-11-16 11:34:40 -08:00
54cfb022c2 New release v2.3.3.0-0.3.rc3 2017-11-10 16:00:14 -06:00
012998c5f7 Revert "Add template lookup fix to changelog"
This reverts commit 994ed2c443.
2017-11-09 10:24:43 -08:00
6eb485c136 Revert "Do not escape backslashes when using the template lookup plugin"
This reverts commit 2b40463a48.

Decided that this change was too big for a bugfix release.  Make it
2.4.x only.
2017-11-09 10:24:43 -08:00
49f3dda7f6 WIP: Resolve CI issues for stable-2.3. (#32605)
* Revert "If pip install requirements.txt fails, upgrade pip (#32399)"

This reverts commit 2fb4f547a9.

* Avoid pep8 user warning in 1.7.1.
* Limit cryptography version for Windows tests.
* Upgrade pip in virtualenv for pip test.
* Upgrade pip in virtualenv for groupby_filter test.
* Upgrade pip in virtualenv for template_jinja2_latest test.
2017-11-06 17:32:47 -08:00
b77de1bd5d If we can't find a .py file for the system six, use our bundled copy instead.
Fixes #32567
2017-11-06 11:22:54 -08:00
2fb4f547a9 If pip install requirements.txt fails, upgrade pip (#32399)
* If pip install requirements.txt fails, upgrade pip

* Use pycodestyle instead of pep8 (#25947)

(cherry picked from commit 4b3d6dfa8a)

* Ignore more

* pylint lint fixes

* Ignore more
2017-11-06 15:54:37 +00:00
eaa2fcc73f Fix password leak in logs for provider argument (#32215)
* Fix password leak in logs for provider argument

Since provider argument is not validated against a spec
the `no_log` arguments are not handled leading to password
leaking to syslogs.
To fix this:
*  Mask password and other `no_log` provider arguments in action plugin
*  In case of eapi and nxapi as the password is used in module code,
*  copy the provider password to top-level password argument which
*  handles `no_log` correctly. This will, however, throw a deprecation
*  warning message for password arg even if it is not given as a
*  top-level argument.

* Remove auth details from provider args in action plugin

* Update CHANGELOG
2017-11-03 11:27:14 -05:00
4c6612eeba Fix patching to epel package
(cherry picked from commit be9cc70b74)
2017-10-30 14:41:30 -07:00
c4085eb07c Add hostname fix for rhel7 2017-10-18 16:30:18 -07:00
b27e86ac07 hostname: fix for a new version of rhel (#31839)
Fixes #31811
(cherry picked from commit efec43dd1e)
2017-10-18 16:29:33 -07:00
9e116c1b65 New release v2.3.3.0-0.2.rc2 2017-10-17 11:39:33 -05:00
4cddc2e7c9 Backport ansible-test updates from devel.
The primary change is use of the new servers for
provisioning remote OS X instances for use in CI.
2017-10-12 21:52:17 -07:00
03a0ea682b restored 2.4/2.5 compat 2017-10-12 12:58:25 -04:00
152c895b1f wait_for: treat broken connections as "unready" (#28839)
* wait_for: treat broken connections as "unready"

We have observed the following condition while waiting for hosts:

```
Traceback (most recent call last):
  File "/var/folders/f8/23xp00654plcv2b2tcc028680000gn/T/ansible_8hxm4_/ansible_module_wait_for.py", line 585, in <module>
    main()
  File "/var/folders/f8/23xp00654plcv2b2tcc028680000gn/T/ansible_8hxm4_/ansible_module_wait_for.py", line 535, in main
    s.shutdown(socket.SHUT_RDWR)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 57] Socket is not connected
```

This appears to happen while the host is still starting; we believe something is
accepting our connection but immediately resetting it. In these cases, we'd
prefer to continue waiting instead of immediately failing the play.

This patch has been applied locally for some time, and we have seen no adverse
effects.

* wait_for: fixup change

We were missing an import and a space after the `#`

(cherry picked from commit 402b095841)
2017-10-12 11:40:42 -04:00
60d9513efb New release v2.3.3.0-0.1.rc1 2017-09-30 12:17:08 -05:00
4eea3e91ad restored 'static' which is still used in 2.3 2017-09-30 12:17:08 -05:00
a9e8f38342 validate include_role args (#28077)
* validate include_role args
* removed unused static

(cherry picked from commit d89dd75769)
2017-09-29 10:52:46 -04:00
fd37f27d2b Add jenkins_plugin CVE fix to changelog 2017-09-26 11:25:20 -07:00
4d5b9ae803 Remove example of using params for the url_password
params could be logged so never use it for passwords.

Also add code to raise an error if passwords are used in that field.

References #30874

(cherry picked from commit 863fcb5ace)
2017-09-25 18:34:53 -07:00
43e0a0369b fix for yaml inventory in not likeing 'none' 2017-09-20 16:55:36 -04:00
82754c7a31 revert win_file headers back to original format so cherry picking works 2017-09-19 07:15:35 +10:00
a606321975 Updated changelog to for win_file check mode fix 2017-09-19 06:50:16 +10:00
f1f8d0319f win_file: Fix check-mode issue removing dirs (#30475)
This fixed #30442

(cherry picked from commit 229a86c952)
2017-09-19 06:49:45 +10:00
4f5bf2e08f Use safe_load to load yaml (#30408)
Replace `yaml.load` with `yaml.safe_load`

(cherry picked from commit 8c3bf20a13)
2017-09-15 14:39:16 +05:30
b4004e5046 Document boolean default value treatment (#30062)
* Consistency and document treatment of default bool values

* Document that default bool values can be any Ansible recognized bool.
  choose the one that reads better in context
* For fragments used by the copy module, make bool types use type=bool and not choices

* Edit for clarity

(cherry picked from commit 8a2f069468)
2017-09-14 13:29:25 -07:00
48d821e611 update changelog for Tower module_utils SSL fix 2017-09-14 09:26:59 -07:00
4a58187103 Fixes verify_ssl option when False in ansible_tower module util (#30308)
* Fixes verify_ssl option when False in ansible_tower module util

* fixed comparison to None per PEP-8 standards

(cherry picked from commit 4980ebf064)
2017-09-14 09:26:59 -07:00
e8e2c5a9f7 [cloud] update the local variable route_table with the latest tag changes (#23136) (#29989) 2017-09-14 12:30:09 +10:00
01cbdb9878 Update changelog to show windows become fix on output streams 2017-09-14 07:06:15 +10:00
4f049ab74e fixed become to show the stdout and stderr streams instead of the StreamReader (#30254)
(cherry picked from commit 77b2aca5a2)
2017-09-14 07:03:49 +10:00
a859c8bba5 Add vars_prompt fix to changelog 2017-09-13 10:53:27 -07:00
48dd3be986 Updated Display.do_var_prompt to use to_native on prompt ( Fixes #30265 ) (#30285)
* Updated Display.prompt to use the normalized prompt message.

(cherry picked from commit ea8af15dfe)
2017-09-13 10:42:02 -07:00
4114a4cfc5 removed orig_exec as that is 2.4 feature 2017-09-12 17:21:22 -04:00
ba4f0e9228 make os_security_group_rule idempotent (#23707)
* Fix issue #19610
(cherry picked from commit 6b6e5665aa)
2017-09-12 07:24:54 -07:00
b8e02b0dc1 Create a new pipe for sshpass on retries. Fixes #29095
(cherry picked from commit d043ba2673)
2017-09-11 08:49:56 -07:00
09d38049eb Fix wheel dependency on python 2.6. (#29388)
* Fix wheel dependency on python 2.6.
* Limit wheel version for tox on python 2.6.

(cherry picked from commit 50ae33d3c1)
2017-09-11 00:06:30 -07:00
c22f8a4ae4 Add blockinfile fix to changelog 2017-09-09 12:50:51 -07:00
4367a45668 Fixes #26793: convert insert regex to_bytes before searching
(cherry picked from commit fcad4f38b4)
2017-09-09 12:49:44 -07:00
afa71ace67 Add py3 jail fix to changelog 2017-09-09 11:56:20 -07:00
4bb52d52b9 Fix py3 string issue in jail connection plugin (take 2) (#28374)
* Fix py3 string issue in jail connection plugin

(cherry picked from commit 436b173b24)
2017-09-09 11:54:53 -07:00
5fbe1e2798 Add cloudtrail profile fix to changelog 2017-09-09 10:09:42 -07:00
a4edac599a Fix connection credentials for cloudtrail module in stable 2.3. Fixes #28821. 2017-09-09 10:07:28 -07:00
d31ba7240f Revert "Temporarily disable failing opensuse test jobs."
This reverts commit 31d2eb0828.

(cherry picked from commit 67c7bd8745)
2017-09-07 11:49:19 -07:00
2c2ca9b34e updated chlog 2017-09-06 23:27:10 -04:00
54ad5b5f49 fix check mode for solaris enable/disable (#29049)
(cherry picked from commit 7804049592)
2017-09-06 23:26:44 -04:00
aa6f3f91ba Temporarily disable failing opensuse test jobs.
(cherry picked from commit 31d2eb0828)
2017-09-06 19:51:29 -07:00
7787ed26bf less confusing 'args' message (#29053)
* less confusing 'args' message
* fix test

(cherry picked from commit fe3b4325c2)
2017-09-06 19:50:07 -04:00
64db935b25 Ensure proper conversion while backing up of junos config (#28958) (#28992)
* Ensure proper conversion while backing up of junos config

* Minor changes

* Fix review comment

*  Open config backup file in binary mode

(cherry picked from commit cc9ed352dd)
2017-09-04 20:48:35 +05:30
46934c195c Add filetree non-ascii fix to changelog 2017-09-01 08:35:01 -07:00
0ba2fb1b47 Fix encoding error on grp.gr_name, which can contain non-ascii chars at domain PCs (#25804)
* Fix encoding errors on grp.gr_name, which can contain non-ascii character at LDAP/AD domain workstations

* fix: utils.to_text() is now used instead of py3-incompatible unicode() method

(cherry picked from commit c16d258a27)
2017-09-01 08:34:22 -07:00
20e47b6132 Junos_config unicode (#23369) (#28913)
* Try to handle unicode output more sensibly

* Appears I'm getting latin1 instead

Ugh.

(cherry picked from commit 689b93bf14)
2017-09-01 15:42:16 +05:30
9dc41ae578 CSS for versioned docs TOC header. 2017-08-31 21:04:22 -07:00
368130f131 Updated CSS for versioned docs - back ported from level. 2017-08-31 17:42:31 -07:00
37523edaf7 Fixed index so TOC points to new community landing page. 2017-08-31 16:46:36 -07:00
578255dd4b Bulk rst/community backport (#28896) 2017-08-31 15:43:08 -04:00
c4984a4c4c Handle AttributeError in vmware module_utils
When vm has no MAC address assigned to it. Fix handles
attribute error if MAC address is not set.

Fixes: #28471

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2017-08-31 13:43:19 +02:00
11346284b1 [cloud] Backport handling of CloudFormation failure state - fixes #24596 #24596 #26603 (#28713) 2017-08-30 16:31:55 -04:00
051bcb2c6f Replace opensuse42.1 with opensuse42.3 in CI.
(cherry picked from commit af9b0ba47b)
2017-08-30 11:11:15 -07:00
8bb12fba3d fix two broken absolute links (#28766)
* fix two broken absolute links

instead of using absolute links, we use normal Sphinx mechanics to make sure those links work portably in the future

* reformat list so paragraphs are properly indented
2017-08-30 15:57:10 +01:00
4b7e4cfa2b updated changelog for win-get-url TLS backport 2017-08-30 16:53:34 +10:00
8db83172d3 win_get_url.ps1 - enable TLS1.1/TLS1.2 if they're available but disabled (#26833)
(cherry picked from commit 4cec83471c)
2017-08-30 16:51:16 +10:00
c3917f395a updated with cp 2017-08-29 09:50:57 -04:00
0777565a29 allow pesky 'bridge' facts to bypass facts filter (#28401)
* allow pesky 'bridge' facts to bypass facts filter

fixes #27729, #23577

* I ate pepe

(cherry picked from commit c06f8a3f9b)
2017-08-29 09:50:10 -04:00
3adb5a62e0 updated changelog as per backport 2017-08-25 22:15:54 -04:00
f5af666164 Update connection logic in vmware module_utils
Fix updates logic of connection in vmware module_utils.

Fixes: #28577

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2017-08-25 22:15:19 -04:00
abfada309c Add efs py3 fix to changelog 2017-08-23 11:47:32 -07:00
fe8d1fbf8d Fixing Issue #27270 - EFS TypeError (#27318)
* Fixing Issue #27270 regarding a TypeError invoked by the addition of a Filter type and List type.

* Fix SecurityGroup from always being reported as changed on PY3

On Python3, filter returns a generator.  This causes us to report that
security groups are always defined on Python3 even when there are none.

Also change filter() calls into list comprehensions.

(cherry picked from commit b828b5d33b)
2017-08-23 11:45:51 -07:00
275676f2cf update changelog, add fix for exoscale auth 2017-08-22 15:21:44 +02:00
d60b61ed04 exoscale: fix api_key param auth typo
(cherry picked from commit 58cd107166)
2017-08-22 15:19:17 +02:00
9e37d827d4 Add user module fix to changelog 2017-08-19 13:17:34 -07:00
75facf5324 fixed #28183 - user module shadowfile update on SunOS (#28276)
* fixed #28183 - user module shadowfile update on SunOS
(cherry picked from commit b5a00d05d3)
2017-08-19 13:15:55 -07:00
bb4283edc4 Add zip filter py3 fix to changelog 2017-08-17 10:37:22 -07:00
1e3231c967 removing tests cause they rely on 2.4 semantics 2017-08-16 13:53:53 -04:00
a0c3182f2e Fix PEP 8 issues. 2017-08-16 09:09:04 -07:00
b544df3425 fixed changelog and added alternatives backport 2017-08-16 10:38:52 -04:00
873f023b13 alternatives: handle absent link, add integration tests (#27967)
* alternatives: add integration tests

* alternatives: handle absent link (fix AttributeError)

Error occurred at least on Debian Stretch and OpenSuse 42.2:
Traceback (most recent call last):
  File "/tmp/ansible_RY6X41/ansible_module_alternatives.py", line 161, in <module>
    main()
  File "/tmp/ansible_RY6X41/ansible_module_alternatives.py", line 113, in main
    current_path = current_path_regex.search(display_output).group(1)
AttributeError: 'NoneType' object has no attribute 'group'

update-alternatives stdout sample:
dummy - manual mode
  link best version is /usr/bin/dummy1
  link currently absent
  link dummy is /usr/bin/dummy

* alternatives: PEP 8 fixes

* alternatives: fix copyright in integration tests

* alternatives: nested loops handle more than 2 items

Thanks to Michael Scherer (@mscherer) for pointing that.

* alternatives: enable integration tests

(cherry picked from commit 016cd0691c)
2017-08-16 10:36:39 -04:00
ee116637d1 Fix zip filter for Python3
Using the now bundled six library.

Fixes #28117

(cherry picked from commit c9cdc3a259)
2017-08-14 23:04:32 -07:00
457f0bdc74 Add ssh smart transport mode (for sftp/scp/piped) to the changelog 2017-08-14 08:14:25 -07:00
78d153d5a0 the smart transport is broken by ssh retry code
1fe67f9 introduced retries to the ssh connection put file and fetch
file.  Unfortunately, that change broke the smart transport because it
started raising exceptions instead of returning from _run().  This
breakage is documented in #23711.

An attempt to fix it was made at #23717 but the first attempt was
objected to as needing to touch too much code.  The second attmept was
objected to as smart was forced to encapsulate retries (thus retrying
a sftp "rety" times before trying scp "retry" times and then finally
moving onto piped).  This third attempt has retries encapsulate smart.
So each sub-transport is tried once and if all three fail, another retry
attempt is made which tries each of the three again.

Fixes #23711
Fixes #23717

(cherry picked from commit 3edac559d3)
2017-08-14 08:12:41 -07:00
99fcf6d824 fixed a syntax problem that was preventing a warning box from being displayed
(cherry picked from commit ebb1d75ee0)
2017-08-10 12:38:08 -07:00
8348890d7f rhn+register: do not pass username/passwd for registration if none is specified. (#24244) 2017-08-10 10:01:26 -04:00
5b6b402755 Fixes #23558 rpm key ids (#27847)
* Changed rpm-keyid extraction and verification method
* minor style fixes
* fixed rpm key deletion,added integration test for mono key,fixed wording in integration tests

(cherry picked from commit b8d371ca8b)
2017-08-09 07:33:25 -07:00
e471fb3a94 added integration tests for rpm_key (#26134)
(cherry picked from commit 5242ff1b59)
2017-08-09 07:33:10 -07:00
26e6b0c639 iAdd file env var fix to changelog 2017-08-08 09:17:21 -07:00
caaebec7f0 Don't do additional path expand in file module
Since the module's path parameter is of the AnsibleModule type path
it's already being expanded. Hence no need to have the
set_fs_attributes_if_different method do its own expand.

This additional expand is an actual problem when the file module runs
recursively, as real existing file names can be mistakenly expanded to
something completely wrong and non-existing.

Fixes #25005
Fixes #25639

(cherry picked from commit ccc68f7157)
2017-08-08 09:14:07 -07:00
e024cc8470 Fix rabbitmq modules for python3 import
Also get rid of unnecessary capture of exception into a variable for
python-2.4 compat.

(cherry picked from commit 8894c57753)
2017-08-07 19:45:07 -07:00
d6d795cef0 Fix ROADMAP rst format 2017-08-07 18:45:32 -07:00
33c3a3459a Add changelog entry for yum and rabbitmq fixes 2017-08-07 17:29:04 -07:00
d4d6b17228 Clean downloaded rpm files after install (#20594)
(cherry picked from commit 616d5ddc93)
2017-08-07 17:29:04 -07:00
d36a651588 Fix yum with rpm file or url when state=latest (#27775)
(cherry picked from commit fa6ce54011)
2017-08-07 17:29:04 -07:00
278d450329 Added missing return info for win_stat (#27736) 2017-08-07 17:29:04 -07:00
6b8bd1ec09 Add check for requests module
Fix adds check for requests Python module and suggests user to install,
if no requests module installation found.

Fixes: #27643

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 748fa5db35)
2017-08-07 17:29:04 -07:00
95dbb735f1 2.3portingguide (#27671)
* Docs porting guides 2.0 &  2.3 (#27632)

* Create new "Porting Guide" section

Create new landing page
Add porting_guide_2.3

* correct CHANGELOG

* Document blocks

* Document named blocks

* OpenBSD & async action plugins

* OpenBSD & async action plugins

* versioadded for name

* review comments

(cherry picked from commit df58d943d3)

* Correct merge
2017-08-07 17:29:04 -07:00
a92e08c39e Add python3 fix in digital_ocean_tag 2017-08-07 17:29:03 -07:00
33e0e5d4fe Fix JSON parsing for Python3
Fix corrects the parsing of JSON output in Python 3
environment by using to_text API.

Fixes: #26489

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit b266204afa)
2017-08-07 17:29:03 -07:00
566299dd31 'Response' makes more sense here than 'request'
(cherry picked from commit 0f2b3d55b4)
2017-08-07 17:27:28 -07:00
62106d5dcf corrected with_dict example
fixes #17636

(cherry picked from commit 001be55ef0)
2017-08-07 17:27:28 -07:00
da332138dd Fixes to pip with git install instructions
* use git+https:// in the example url because not everyone will have ssh
  keys registered on github
* Remove the link to the github tarballs as they do not work.  users can
  use releases.ansible.com instead.

(cherry picked from commit bf42f94021)
2017-08-07 17:27:28 -07:00
cb1bd058ad changelog: add fixes to be in 2.3.3 2017-08-07 17:27:28 -07:00
1244624d7c Fix for check_mode in archive (#26788)
Fix adds check_mode fix for archive module.

Fixes: #26750

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 156b29b26b)
2017-08-07 17:27:28 -07:00
b5c51c4c56 Improve release and development cycle documentation
This commit:
- Adds a table highlighting the status of each version and provides
  a link to each major release's changelog
- Re-inforces how stable versions are maintained and for how long
- Moves this documentation out of the developer tree (this is
  interesting for users too!) while keeping a link there.

(cherry picked from commit e2d874c744)
2017-08-07 17:27:28 -07:00
53a53ebf73 Updates docs to match module behavior (#26658)
* Updates docs to match module behavior

* Updates docs to match module behavior

Updated using advice from jimi-c

* Removes snippet about git module before v1.8.3

At suggestion of robinro

(cherry picked from commit 90a42d1e53)
2017-08-07 17:27:28 -07:00
5d6da688ed Add changelog entry for the seboolean module fix 2017-08-07 17:27:28 -07:00
3aca12b451 Import to_native 2017-08-07 17:27:28 -07:00
49a27da0b2 added unicode iosxr fix to changelog 2017-08-07 17:27:28 -07:00
5c97a27d20 fix unicode errors in iosxr
(cherry picked from commit 0b5b5ec50a)
2017-08-07 17:27:28 -07:00
2d9cbdc107 Add changelog for ios_config change 2017-08-07 17:27:28 -07:00
60b3c2ad9c Fix #26918: IOS TypeError (#26999)
Fix IOS TypeError

* if flags are None, then ' '.join(flags) fails
* fixed get_defaults_flag so that it returns a list, and ignores lines with white space

Fixes #26918
(cherry picked from commit 9f64e446c6)
2017-08-07 17:27:28 -07:00
8e949c616e Add module_utils example next to library examples (#25390)
(cherry picked from commit 37e757286d)
2017-08-07 17:27:28 -07:00
95ac4c4a96 Add changelog for docker_login py3 fix 2017-08-07 17:27:27 -07:00
4251db2345 [Fixes #26690] Supports Python 3 handling of base64 encoding (#26876)
* [Fixes #26690] Supports Python 3 handling of base64 encoding

* Set text auth to separate variable for reuse

(cherry picked from commit 3f67d167fe)
2017-08-07 17:27:27 -07:00
927548e2f6 cloudstack: cs_role: fix UnboundLocalError in check mode
(cherry picked from commit 6d81c9670f)
2017-08-07 17:27:27 -07:00
ad61c12b06 known_hosts: always use lowercase hostnames for host keys (#26850)
(cherry picked from commit dc408f9035)
2017-08-07 17:27:27 -07:00
80ae8e9b29 Add py3 fix for AnsibleModule.run_command to changelog 2017-08-07 17:27:27 -07:00
fdc8a75218 Need regex and string types to match when cleaning arguments for logging
Fixes #25078

(cherry picked from commit b49be56c5b)
2017-08-07 17:27:27 -07:00
81278323f3 Add hacking/env-setup python3 fixes to the changelog 2017-08-07 17:27:27 -07:00
896becab34 hacking/test-module: fix for python3 (#26194)
* make hacking/test-module compatible with python3
(cherry picked from commit 113f92548a)
2017-08-07 17:27:27 -07:00
db3ae98233 changelog: added entry for win_acl fix 2017-08-07 17:27:27 -07:00
c55b078d92 win_acl: registry support for special service accounts (#26629)
* Fixes #22968
* `APPLICATION PACKAGE AUTHORITY` ACLs also apply to the registry

* fixed nested for loop

(cherry picked from commit 81c22522a5)
2017-08-07 17:27:27 -07:00
d038997d5c Add fix for postgres_user to changelog 2017-08-07 17:27:27 -07:00
3d0462b456 Add pause module py3 fix to changelog 2017-08-07 17:27:27 -07:00
30f813d716 Fix the pause module for python3
* On python3, stdin goes through a buffer that translates from raw bytes
  to text.  this interferes with pause as it (1) performs universal
  newline conversion and therefore '\r' is turned into '\n' and (2) the
  buffering prevents us from getting the typed characters immediately
  (possibly a python3 bug?)  Using the raw byte stream that's behind the
  text decoder fixes these problems.

Unrelated cleanups:
* Use to_text instead of str for conversion into strings to avoid possible tracebacks
* Use either \r or \n as the end of a line.

Fixes #26278
Resolves #26446

(cherry picked from commit 5ceabe939d)
2017-08-07 17:27:27 -07:00
994ed2c443 Add template lookup fix to changelog 2017-08-07 17:27:27 -07:00
2b40463a48 Do not escape backslashes when using the template lookup plugin
This brings the lookup plugin inline with what the template module does.

Fixes #26397

(cherry picked from commit cf5fb0acdf)
2017-08-07 17:27:27 -07:00
743b396e5e Add azure py3 fixes to changelog 2017-08-07 17:27:27 -07:00
6e34fd16d5 Fix Python3 Errors in Azure Cloud Module
When using Python3, the exec_module function errors out with a
unsupported operand type(s) for +: 'dict_keys' and 'list'
error when adding the .keys() to a static list. Use the explicit
list function to make a list of keys and then add to the ['tags'] list.

(cherry picked from commit 171d903d04)
2017-08-07 17:27:27 -07:00
f00d44e0b4 CHANGELOG entry for synchronize fix 2017-08-07 17:27:27 -07:00
ac8598f1db Fix synchronize setting user variable
The user variable stores whether we need to set user@ in our connection
string.  It's now being used at the toplevel of the run() method so the
default needs to be calculated further up the stack

Fixes #24910

(cherry picked from commit 6908038036)
2017-08-07 17:27:27 -07:00
584af4e9f8 2.3.2 CHANGELOG update for win_updates and non-pipelined fixes 2017-08-07 17:27:27 -07:00
392d268809 win_find: fix for empty nested directories (#26164)
(cherry picked from commit 98fc54f02d)
2017-08-07 17:27:27 -07:00
a8afa6b96c Fix hacking/test-module to allow running modules with pdb (#23339)
* Fix hacking/test-module to allow running modules with pdb

* add emacs autosave files to gitignore

(cherry picked from commit 56d33a2967)
2017-08-07 17:27:27 -07:00
c7052b42c7 New release v2.3.2.0-1 2017-08-04 15:24:09 -05:00
611048c6ba Finalizing date for 2.3.2 final release in CHANGELOG 2017-08-04 15:18:06 -05:00
435cdcf84a <doc/dev/modules: Fix an RST typo into external link> (#27615)
Make a link a valid external hyperlink targets.
2017-08-03 14:28:24 -07:00
c869423e0c Use python-crypto instead of python2-cryptography. 2017-08-03 12:39:25 -07:00
96dd226235 Update RPM spec and make targets. (#27712)
(cherry picked from commit b54d00f2de)
2017-08-03 12:39:25 -07:00
eff04e9fa3 modify indent to avoid re-run src template fail (#27689)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-08-03 13:50:44 +05:30
3d446b2fab fix NameError eos_config (#27684)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-08-03 11:39:53 +05:30
987ad8993c Typo on path return Value : "authorzied" (#27555)
Seen on official documentation: http://docs.ansible.com/ansible/latest/authorized_key_module.html
2017-08-02 22:09:49 +01:00
76b5b35458 New release v2.3.2.0-0.5.rc5 2017-08-01 18:51:23 -05:00
360703234e add changelog 2017-08-01 15:39:34 -07:00
25c95a96a8 Fix for ansiballz filenames conflicting with python stdlib modules
The AnsiBallZ wrapper is transferred to the remote machine with
a filename similar to the Ansible-module it runs.  For modules like copy
and tempfile, this can end up conflicting with stdlib modules on the
remote machine depending on how python is setup there.  We have a little
bit of code in the wrapper to deal with this by removing the path that
the ansible module resides in from sys.path.

On MacOSX, that code was having a problem.  The path the module ends up
in included a symlinked directory so we were looking for a path in
sys.path but we had to look for the unsymlinked path instead.

Fix that by using os.path.realpath() instead of os.path.abspath()

(cherry picked from commit 15902f2496)
2017-08-01 15:21:21 -07:00
46846b1973 docs: fix community meetings link (#27264) (#27586)
(cherry picked from commit 9c50933a80)
2017-08-01 17:43:18 +01:00
d0a1679113 [Backport] Multiple fixes for vmware_guest_facts (#27464)
* Updated Folder documentation
* Updated Example
* Updated imports
* Added correct logic to use FindByInventoryPath() API
* Remove get_exception in favor of to_native
* Remove redundant get_obj method

Fixes: #24691

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2017-08-01 09:35:10 -04:00
504558eab3 [Backport] vmware_guest: Fix "KeyError: 'changed'" (#27456)
This is a backport of vmware_guest fix.

Fixes: #27390

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2017-08-01 09:34:43 -04:00
6698dc00e3 Add potential work-around for expect on macOS.
http://pexpect.readthedocs.io/en/stable/commonissues.html#truncated-output-just-before-child-exits

(cherry picked from commit 0c7602fb59)
2017-07-31 13:22:52 -07:00
e579afc432 added backports 2017-07-31 13:10:19 -04:00
96296e8c71 make random_choice more error resilient (#27380)
* make random_choise more error resilient

fixes #27373

(cherry picked from commit b79744f282)
2017-07-31 11:48:26 -04:00
a53cc97f19 ensure prefix in plugin loading to avoid conflicts
when using 'all' to load all plugins were ending in main namespace
creating conflicts with each other and random modulesr
 i.e. when trying to access json callback we were getting json 'parsing' lib

(cherry picked from commit b93b9e68d7)
2017-07-31 11:48:26 -04:00
c276466262 Fix error with meta: clear_facts (#26406)
Using `meta: clear_facts` was failing with
`coercing to Unicode: need string or buffer, Host found`

This applies the same fix as 3101e24.

Fixes #26405
(cherry picked from commit 23041c3b6c)
2017-07-28 09:19:09 -05:00
532b4338f4 New release v2.3.2.0-0.4.rc4 2017-07-26 09:54:02 -05:00
7a6c5dd1ab Fix using DNF group upgrade/remove api
(cherry picked from commit 119c9e5d6e)
2017-07-26 07:39:49 -07:00
8f8d4d103f updated with recent cherry picks 2017-07-26 10:07:25 -04:00
5b39de5013 better reading of 'facts'
(cherry picked from commit c7e841e0e4)
2017-07-26 09:37:02 -04:00
9d435fd47b Add seboolean fix to the changelog 2017-07-25 15:55:48 -07:00
1628a25d8d Workaround python-libselinux API change (#25685)
In the past, selinux.security_get_boolean_names did return 'bytes'
on python 3, but this was changed to return string later, cf:
b8711e2eaf

So we have to convert to bytes only if the API return us bytes.

Fix #25651
(cherry picked from commit e2d6ecfa40)
2017-07-25 15:54:54 -07:00
0a7bad68dc Avoid using deprecated group_install API
DNF's base.group_install() function accepts a string as its first
argument.  Prior to DNF-2, compatibility code existed which allowed this
function to accept a base.comps.Group object instead.  That is no longer
possible.

Pass "group.id" to base.group_install() instead of "group" to work
around this.

(cherry picked from commit ccce74cf7b)
2017-07-25 15:36:58 -07:00
2385e2be27 include_role handlers bug fix (#26335)
* Ensure that include_role properly fires handlers

include_role needs to ensure that any handlers included
with the role are added to the _notified_handler and
_listening_handler lists of the TaskQueueManager, otherwise
it fails when trying to run the handler.

Additionally, the handler needs to be added to the
PlayIterator's `_uuid_cache` or it fails after running
the handler

Add more uuid debug statements - this code was hard
to debug with existing debug statements, so add more
uuid information at little additional output cost.

Fixes #18411

* Add tests for include_role handlers

Tests for #18411

(cherry picked from commit ef8c9798d3)
2017-07-25 16:37:24 -05:00
91f70a4462 Fix performance issue while match pattern in large inventory list 2017-07-25 17:19:48 -04:00
28fa228d93 Fix for nonutf8 filenames causing crashes when setting permissions
Fixes #23861

(cherry picked from commit b26ee657b5)
2017-07-25 00:16:57 -07:00
795e75433e Expand the result from pwd to make the test more robust
Sometimes MacOSX's pwd doesn't return an expanded path.  Not sure why
but this test is still valid if we expand it via a playbook filter so
go ahead and do that.

(cherry picked from commit 6a41a4f311)
2017-07-24 10:27:46 -07:00
ddc124297a Update changelog for utf8 recurse files bug 2017-07-24 09:22:08 -07:00
9a05efcab9 Fix for to_text and to_bytes error handlers
* surrogate_then_strict doesn't exist.  Switch to surrogate_or_strict
  instead.
* Found some bugs in the _text.py implementation
  * The composed error handlers (error handlers which are made up of two
    or more python encoding error handlers) had a wrong string in it,
    'surrogate_or_escape' doesn't exist.  Replaced that with
    'surrogate_or_replace' which is the correct handler name.
  * Left comment about the implicit conditions that are part of the
    surrogate_then_replace code path

Fixes #23865
Fixes #23861

(cherry picked from commit fc5d71de0d)
2017-07-24 09:22:08 -07:00
0e0400b12e Disable zypper* tests which are timing out.
(cherry picked from commit d031ff8aec)
2017-07-24 09:21:00 -07:00
8eba034942 Add su_pass fix to changelog 2017-07-24 08:00:59 -07:00
13901eeb70 Fix legacy su handling (bad conditional would not fire at the right time)
(cherry picked from commit aa9941aaf7)
2017-07-24 07:59:52 -07:00
668266552e Bulk dev_guide from devel to 2.3 (#27205)
* Bulk dev_guide from devel to 2.3

* Scot's feedback
2017-07-24 09:38:43 +01:00
065f74f0ee Bulk import network doc changes from devel to 2.3 (#27204) 2017-07-23 14:23:30 +01:00
b66d9cc14e fix nxos_interface state default (#27108)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-07-21 12:56:31 +05:30
a1c15a9277 New release v2.3.2.0-0.3.rc3 2017-07-20 09:23:52 -05:00
316ef8a069 Add make target for printing version (#26657) (#27030) 2017-07-19 09:04:17 +01:00
a3817721fc Cherry pick EAPI tearup/down tests changes (#26938)
* Replace Ethernet5 for Ethernet2 on eos integration tests (#26674)

In our CI, we only have 3 NICS: Management1, Ethernet1 and
Ethernet2.
(cherry picked from commit 4006b5d18f)

* Add CHANGELOG entry
2017-07-18 11:02:56 +02:00
4490cc9e9e Cherry pick eapi tearup down changes (#26935)
* Remove enable EAPI from prepare_eos_tests (#26910)

Enabling EAPI is not common on CLI *and* EAPI tests, therefore
enabling it should be put at the eapi.yaml task level.
(cherry picked from commit 258d2058cd)

* Add missing provider on disable eapi tasks (#26928)

(cherry picked from commit 4532c791fd)

* Add CHANGELOG entry
2017-07-18 10:33:19 +02:00
32b4342209 Cherry pick 2.4 eos banner fixes (#26904)
* Fix multiple EOS EAPI code and test issues (#26651)

(cherry picked from commit b81209c187)

* Fix eos_banner basic-motd eapi asserts (#23398)

The commands in EAPI does not contain the plain command sent to the
device as a one liner, but it is split in cmd/input keys.
(cherry picked from commit ce9826d76e)

* Add CHANGELOG entry
2017-07-17 17:59:31 +02:00
85e9a07117 privilege escalation for eos integration test (#26597)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-07-10 19:30:30 +05:30
23020bf9d9 Revert "postgresql_user: fix bugs related to 'expires' option (backport #23862) (#26539)"
This reverts commit 5432414c9d.
2017-07-07 10:13:17 -07:00
5432414c9d postgresql_user: fix bugs related to 'expires' option (backport #23862) (#26539)
* Change 'valid until' even it's the only updated field

(cherry picked from commit 460d932aa8)

* value is changed when another value is provided

(cherry picked from commit 460d932aa8)

* value isn't returned when unset

(cherry picked from commit 460d932aa8)

* Fix comparison between user input and applied configuration

(cherry picked from commit 460d932aa8)
2017-07-07 10:11:33 -07:00
022ba4fbea New release v2.3.2.0-0.2.rc2 2017-07-07 11:46:40 -05:00
71444d0c37 Update CHANGELOG.md to include wait_for fix. 2017-07-05 19:08:49 -07:00
154b0d2210 Fix wait_for with newer versions of psutil. (#26455)
* Add support for newer psutil versions.

(cherry picked from commit 895e6c5d06)
2017-07-05 19:06:49 -07:00
4deb45eff6 Making iosxr check_args call module_util/iosxr check_args. Fixes #25501 (#26261) (#26444)
(cherry picked from commit 1d62283796)
2017-07-06 00:20:08 +05:30
b223c7e0a2 changelog: fix for win_chocolatey where it didn't fail if the version did not exist 2017-07-05 08:31:12 +10:00
ffadbf680d win_chocolatey: Ensure chocolatey to fail (#26416)
Currently chocolatey is not failing when the user requests version X,
but version X is not available in the repository.

Obviously the module should fail in this case.

This fixes #25393
(cherry picked from commit b9d018885a)
2017-07-05 08:29:54 +10:00
29ac96e09e changelog: added fix for win_regedit and idempotency on dwords 2017-07-05 08:26:36 +10:00
7f5a0715bf win_regedit: fix for same dword value (#26415)
(cherry picked from commit 8e9d04043a)
2017-07-05 08:24:26 +10:00
8ced21101f changelog: added win_chocolatey upgrade of all packages fix 2017-07-05 08:10:23 +10:00
69175a5077 win_chocolatey: Fix updating 'all' packages (#26417)
This fixes #15018
(cherry picked from commit 69ade22243)
2017-07-05 08:09:01 +10:00
333d177325 changelog: add backported fixes by me (#26403) 2017-07-04 19:07:37 +02:00
0c8459b01b cloudstack: cs_instance: fix KeyError: 'sshkeypair' (#26399)
(cherry picked from commit 37b22673fb)
2017-07-04 17:20:10 +02:00
fa65417ba0 updated with change 2017-07-03 23:07:53 -04:00
144d0b6f9e update auth_flag variable after STARTTLS connection is established, fixes #26376
(cherry picked from commit 5c0c985547)
2017-07-03 23:07:53 -04:00
8ad00c0128 CHANGELOG update for become/runas fix 2017-07-03 17:48:27 -07:00
f9f83c5826 converted become runas to explicit CreateProcessWithLogonW
* fixes become_method: runas for unprivileged users
* sets permissions on tempdir appropriately
* allows automatic system environment generation for new token (old Process.Start way prevents this)
* add basic become runas tests

(cherry picked from commit 6d99a0a934)
2017-07-03 17:43:50 -07:00
e947321831 Remove trailing newlines (#26350) 2017-07-03 13:58:32 +01:00
9d94a309ca Remove test of openvswitch_db state (#26349)
The `state:` option didn't exist in Ansible 2.3, so don't test it.
2017-07-03 13:18:32 +01:00
1ad1ad6ace Missing prepare_ovs_tests directory (#26337)
openvswitch_db tests have been backported from devel to stable-2.3[1],
but the role to prepare_ovs_tests was missing from the backport, hence
the test, when run complained about missing roles.

This commit aims to bring this directory into stable-2.3 tree.

[1] https://github.com/ansible/ansible/pull/26330
2017-07-03 10:02:07 +02:00
94660f792a Add openvswitch_db tests (#26330)
openvswitch_db tests were added during 2.4 development, though the
module still existed in 2.3, so backport the tests.

This is needed for distributed-ci.
2017-07-02 21:59:07 +01:00
b1e0f78a07 fix win_updates failure with dict-typed args
Switch to dicts in common code caused silent failures during arg translation, so default values and non-check-mode were always used.
* fixes #23653
* fixes #24062
* fixes #22938
* fixes #25156
(cherry picked from commit e6f364e2d6)

(cherry picked from commit 95fead611c)
2017-06-30 17:20:28 -07:00
888096ec4c 2.3.2 CHANGELOG update for win_updates and non-pipelined fixes
(cherry picked from commit 2a6e5eedb7)
2017-06-30 17:20:19 -07:00
0c31f31385 cloudstack: cs_template: default is_routing=None, fixes template upload for users (#26248)
(cherry picked from commit 363761fc16)
2017-06-29 17:46:10 +02:00
e36f568194 Limit yamllint version on python 2.6.
(cherry picked from commit 55aec8ebc9)
2017-06-29 08:35:32 -07:00
6ad5a31437 parted: Add missing LC_TYPE override for env vars (#26242)
(cherry picked from commit 7f6c7c6334)
2017-06-29 15:57:03 +02:00
269550993d fix nxos_feature (#26132)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-06-29 11:05:02 +05:30
e943505ab2 letsencrypt: FIX CN parsing to work with OpenSSL 1.1 (#25935)
As we can see in
9537453586
:

CN used to be without whitespaces around the `=` but OpenSSL 1.1 introduced
whitespaces:
1.0.1: subject=/CN=example.com
1.1.0: subject=CN = example.com

This commit makes them optional.

OpenSSL 1.1 is present on the newly-released Debian Stretch, so absence
of this fix makes us not being able to use this module on this distro.
(cherry picked from commit 9474f20f2d)
2017-06-28 09:21:21 +02:00
7424e1c417 New release v2.3.2.0-0.1.rc1 2017-06-27 11:33:22 -05:00
6cca156fde re-enable non-pipelined mode for Powershell (#26124)
* fixes #23986
* fixes 3rd-party Windows connection plugins that don't support pipelining (eg awsrun)

(cherry picked from commit 6677559c69)
2017-06-26 22:57:59 -07:00
940a78c5ba Update FreeBSD pg test to use postgresql95-server.
The py-psycopg2 package now requires postgresql95-server instead of
postgresql93-server. Installing py-psycopg2 will automatically remove
postgresql93-server if it is installed, breaking integration tests.

(cherry picked from commit 15beaed6bc)
2017-06-26 13:54:40 -07:00
1731962155 updated changelog 2017-06-26 16:01:20 -04:00
44b3d67ef3 Fix ansible ad-hoc to respect ANSIBLE_STDOUT_CALLBACK (#26098)
* Fix ansible ad-hoc to respect ANSIBLE_STDOUT_CALLBACK

* Ansible ad-hoc 'stdout_callback' should work only with 'bin_ansible_callbacks'

(cherry picked from commit 6d59160744)
2017-06-26 16:01:01 -04:00
ba453452f0 Missing Else statement (#25457) (#26113)
Missing the final Else statement in the conditional statement
(cherry picked from commit e391206acc)
2017-06-26 19:26:39 +01:00
4b49b96ca1 cloudstack: cs_host: revamp fixes several issues
(cherry picked from commit 1f5839777b)
2017-06-26 14:41:48 +02:00
7c38f7cdfa fix networkdid->networkid in cs_nic.py (#25914)
(cherry picked from commit f6e4019804)
2017-06-24 09:49:58 +02:00
eeaa676577 Don't include dependent roles in the dep chain for include_role
The dependency chain should not include roles below the parent, as it
can introduce very weird things like conditionals from child deps impacting
non-related roles.

Fixes #25136

(cherry picked from commit 020317b21bf54f49db56b95893be5e63a17ea4f8)
2017-06-22 13:22:31 +01:00
5512c94017 correctly set delegated host name in results
(cherry picked from commit a457c2af59)
2017-06-20 15:00:06 -04:00
cac3cfa9eb MySQL Password updates (#25825)
* MySQL Password updates

* Disable user_password_update_test

(cherry picked from commit 448efdb9e5)
2017-06-19 16:22:37 -07:00
bf34bdb32c updated changelog with backport 2017-06-19 19:11:51 -04:00
3a25aca272 fixed danlging version_info 2017-06-19 19:10:41 -04:00
73aa4c930d Revert "add a any() to wait_for for python 2.4 compatibility (#25876)"
This reverts commit 7fbd7fc4f8.
2017-06-19 15:46:19 -07:00
ec26494167 backported delegation/facts fix, see #25880 2017-06-19 18:09:15 -04:00
7fbd7fc4f8 add a any() to wait_for for python 2.4 compatibility (#25876) 2017-06-19 15:48:02 -04:00
e998b7e40f 2.3bug25844flowdock (#25873)
* Correct failure message in flowdock (#25844)

As per documentation and code, external_user_name is
required parameter is case of type 'chat'.
Fix corrects error message displayed to user.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit a4ebde1516)

* Fix for flowdock error message when external_user_name is missing
2017-06-19 17:23:29 +01:00
2bfdb77ed4 2.3bug20202 (#25864)
* htpasswd: fix passlib module version comparison (#20202)

Previously, we used StrictVersion which failed to parse some passlib
version strings. For example, Debian currently ship passlib with a
__version__ of '1.7.0.post20161128115349'

StrictVersion throws an exception when parsing this version string.

Change to using LooseVersion which successfully parses version strings
such as this.

Fixes #20199
(cherry picked from commit 0be0aa5f10)

* htpasswd: fix passlib module version comparison
2017-06-19 14:00:27 +01:00
8813b4f03d Update docs based on 23946 (#25860)
* Update docs based on 23946

Original PR https://github.com/ansible/ansible/pull/23946

* files/copy.py is now clean
2017-06-19 11:59:40 +01:00
e1dbb02b66 Fix module params assignment in jabber module (#25850)
Fix corrects variable assignment from module params

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 561d678f52)
2017-06-19 10:08:51 +02:00
a40b1c455d Use stronger password for MySQL (#25821) (#25822)
Previously we were getting "Your password does not satisfy the current policy requirements"
Possibly caused by a software update on Fedora
(cherry picked from commit 7ee7fa7332)
2017-06-17 13:12:30 +01:00
b5c2f2dc71 fix KeyError on eAPI transport for use_ssl and validate_certs (#25788)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-06-16 16:26:00 +05:30
dddcf0f6ad fix deprecation for transport param when not used (#25782)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2017-06-16 14:56:40 +05:30
8c2e9257d4 Do not set default value for any_errors_fatal in Base
Setting default values for FieldAttribute values created in the Base class
prevents the _get_parent_attribute() code from working correctly, as the value
is always non-None.

Related to #22924

(cherry picked from commit c5b8196ff1)
2017-06-16 01:56:39 -05:00
ff578cc1b3 updated clog with vault view patch 2017-06-15 11:32:34 -04:00
419d21c509 pager should not log
fixes #25719

(cherry picked from commit df2fcecd62)
2017-06-15 11:32:13 -04:00
5605091dc1 Have cs_host search both name and ipaddress fields when fetching the host from listHosts. (#25628)
Make ip_address an alias of name to allow playbooks to more clearly make
use of IP addreses.
(cherry picked from commit d5becd728e)
2017-06-14 09:19:53 +02:00
6cb0666d0a [cloud] ASGRetry - add retry on throttling and add backoff to calls in ec2_asg (#24339)
* Use AWSRetry decorator in ec2_asg

* Rebased on stable-2.3

Added tries, delay, and backoff

Adding throttling to the list of errors for AWSRetry

* Create custom retry class for ec2_asg while it still uses boto

* remove changes to ec2.py

* BotoServerError exception has error_code attribute

* add info to the changelog
2017-06-13 15:55:57 -04:00
08f3b83812 clog update 2017-06-13 10:38:51 -04:00
ae5c9f93b7 add validation to fetch for source/dest
also added missing display

(cherry picked from commit c4169d93e8)
2017-06-13 10:38:18 -04:00
19cf1b2281 Updated changelog with last 2 cps 2017-06-12 10:26:52 -04:00
68d21e6729 Fix hash_key_name to be optional for delete (#25009)
(cherry picked from commit 3ac9273507)
2017-06-12 10:26:02 -04:00
09635b8460 Correct fail_json call in rpm_key
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit e160bcf237)
2017-06-12 09:11:09 -04:00
ebf7c6c37b Add docker connection plugin py3 fix to the changelog 2017-06-10 07:12:48 -07:00
ccd170cbdd Convert docker cmd output to native, early
(cherry picked from commit 23eebb62e6)
2017-06-10 07:11:39 -07:00
be0b86ce81 cloudstack: cs_zone: fix missing type bool for params
(cherry picked from commit f8e3540e9f)
2017-06-09 18:11:37 +02:00
603d52f8fe cloud: ovirt: Fix upgraded state of the ovirt_hosts module (#25535) 2017-06-09 11:45:19 -04:00
a1ceb1c404 Template parent include path before finding its dirname (#23202)
Given parent include path "{{ var | default('path/file.yml') }}"
os.path.dirname(parent_include_path) yields {{ var | default('path/
which is incorrect in itself but also causes templating errors
due to unbalanced quotes. Fix both problems by templating
parent include path before finding its dirname.
2017-06-08 23:48:20 -05:00
b6e4266aa5 2.3bug25396 2 (#25486)
Don't fail when creating a Foreman organization fixes(#25299)
2017-06-08 12:55:25 +01:00
9aa1a2b871 Fix for RabbitMQ 3.6.7 endpoint return code (#25485)
https://github.com/ansible/ansible/pull/22715
2017-06-08 12:40:30 +01:00
c5971f018f RabbitMQ 3.6.7 changed a couple of response codes (#22715) (#25484)
(cherry picked from commit 6bd1681203)
2017-06-08 12:36:06 +01:00
8455251bec Document ansible-galaxy fix 2017-06-07 07:40:01 -07:00
e4fae653da Fix --force for unversionned requirements (#23391)
In current stable (2.2), ansible galaxy install --force do erase
a role, even if the version is not set. This commit should restore
that specific behavior, in accordance to people reports:
  https://github.com/ansible/ansible/issues/11266#issuecomment-273801480

It was also the behavior planned in the initial discussion:
"if you're not fixing versions in your roles file, then it's fine
to expect that the role will be reinstalled each time you run
ansible-galaxy install.", cf https://github.com/ansible/ansible/pull/12904
(cherry picked from commit 78836ec0b9)
2017-06-07 07:38:24 -07:00
ba6276a4b1 Add AnsiBallZ low disk space error to changelog 2017-06-07 06:40:51 -07:00
ef5e9806dd When cleaning up the AnsiBallZ tempdir we need to not fail if the tempdir wasn't created
If the temp directory creation failed in mkdtemp then temp_path is never
given a value.  This would lead to a NameError exception which would
obfuscate the original error (out of disk space being a common one).  By
catching NameError, python will raise the original exception as we want.

Fixes #17215

(cherry picked from commit 80c1765653)
2017-06-07 06:39:47 -07:00
1b00e43d2a cloud: ovirt: Fix searching of network in datacenter (#25248)
(cherry picked from commit bcc5bffd8e)
2017-06-07 00:28:53 +02:00
9954077a0a Changelog entry for pip virtualenv fix 2017-06-05 17:05:08 -07:00
c37aca62ef fix proposal for issue #25151: [python3] pip failed to create virtual env when using custom command (pyvenv) (#25241)
* Fix proposal for bug 25151

* Fix proposal for bug 25151 - pip module, pyvenv validation

* Graceful fail when virtualenv_python is defined and virtualenv_command uses the venv module

* Making sure that venv is being used as a modue "-m venv"

* Updating syntax in validations

* Updating syntax in validations - fixing stupid typo "[)"

* Raising an error if virtualenv_command is pyvenv or venv and virtualenv_python is used

* trailing whitespace gone, pyvenv, venv validation and docs update

* cleaning whitespaces from blank lines

(cherry picked from commit bc4a8dbaa4)
2017-06-05 17:03:54 -07:00
5ebaaf26bb Reenable git tests (#25341)
* Revert "Temporarily disable failing git test."
* Use correct hash for depth=1 test

(cherry picked from commit 8f7c8ef3a5)
2017-06-05 12:21:53 +08:00
dd5dde6c0e Temporarily disable failing git test.
(cherry picked from commit dab1b1fe5b)
2017-06-04 20:42:20 +08:00
767f0e5d3f Changelog entry for digital_ocean dyn inventory py3 fix 2017-06-03 13:57:34 -07:00
db121421a6 python 3 compatibility: import guard around ConfigParser
In python3 `ConfigParser` has become `configparser`. Added
an import guard that aliases it back to the old name.

(cherry picked from commit bc9dbf38b0)
2017-06-03 13:56:45 -07:00
8bfc36db6e Add missing provider on basic-motd IOS test (#25307)
Without this it fails, as it needs elevated privs.
(cherry picked from commit ffc74fdca2)
2017-06-02 17:07:06 +02:00
58d23ba378 added chnlog for towerjob fix 2017-06-02 10:17:42 -04:00
a09fbb4b15 Fix handling of extra_vars_path parameter. (#25272)
tower-cli process_extra_vars takes a list.
(cherry picked from commit d0cc980223)
2017-06-02 10:17:42 -04:00
cb8517ba0a added parted i18n fix 2017-06-02 10:17:42 -04:00
5512e7a27c Fixes parted i18n issues (#24991)
* Fixed issue 24969

* Used C locale and global env update.

(cherry picked from commit f364d7af8e)
2017-06-02 10:17:42 -04:00
5d6fd93474 Add support to fetch old style junos facts (#25250) (#25292)
* Add support to fetch old style junos facts

Fixes #25050

Add support to fetch old style facts supported in Ansible <= 2.2
To fetch old style facts value `gather_subset` value shoule be `all`
and `junos-eznc` is required to be installed on control node as a
prerequisite.

* Remove unwanted import

(cherry picked from commit 85219dfdf3)
2017-06-02 16:29:42 +05:30
c5aec5703a Add ec2 policy sorting python3 fix 2017-06-01 11:30:39 -07:00
33b88e9770 Fixing policy sorting for Python 3
(cherry picked from commit 3c3e9c3b36)
2017-06-01 11:29:25 -07:00
25ff5bd353 Convert basestring to string_types (#25228)
(cherry picked from commit c1f0260ae3)
2017-06-01 10:25:00 -07:00
0fefd8493b Adds documentation of implicit regex match removal (#24934) (#25255)
regex_replace has a implicit parameter for `replacement` and thus can remove the matched string
(cherry picked from commit aa9ea3d43a)
2017-06-01 12:14:24 -05:00
da8963d788 Temporary work-around for setuptools 36.0.0 bug. (#25243)
* Temporary work-around for setuptools 36.0.0 bug.
* Use older setuptools for pip integration test.
* Limit isort version to avoid new test failures.

(cherry picked from commit 9d8aa43c67)
2017-06-01 12:14:24 -05:00
250a1cfeca Update facts module to support the new OS10 10.3 release (#25090) (#25223)
* Update facts module to support the new OS10 10.3 release

* Address PEP8 issues reported by ansibot

(cherry picked from commit e0db5d23cc)
2017-06-01 12:14:24 -05:00
cedd0f5da2 Fix return code (#23592)
The Honeybadger API returns 201 for success, not 200.
(cherry picked from commit 16c2207d21)
2017-06-01 12:14:24 -05:00
ec545d7b42 Add provider param to prepare_iosxr_tests role tasks (#25163)
This will avoid passing -u -k to ansible-playbook
(cherry picked from commit 69efb61008)
2017-06-01 12:14:23 -05:00
9d4875a727 Misc typo fix in fleet inventory (#25174)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>(cherry picked from commit 3a82246d82)
2017-06-01 12:14:23 -05:00
23277a622c aos_login change default port and add version check (#24752) (#25171)
* Change default port for aos_login and force type to Integer

* Add check to make sure aos-pyez is present and has the right version

* Update min version requirement in doc

* Change default port in documentation as well

(cherry picked from commit 6dd1fc6f34)
2017-06-01 12:14:23 -05:00
d07ab49904 Update main.yml 2017-06-01 12:14:23 -05:00
3932c53328 Fix IndexError when junos_config contains multiple delete lines (#25139) (#25148)
* Prevent IndexError when deleting multiple lines

The old code will raise `IndexError: list assignment index out of range` when deleting multiple lines because the indexes of the original and the copy get out of sync. Solved by deleting from the high indexes first so the lower ones remain stable.

* Don't load configuration if nothing to load

Instead of sending an empty candidate config (for example because the candidate only consisted of `delete` lines, and all of them were filtered out by `filter_delete_statements`) just return. JunOS seems to get confused by empty changes, and if the candidate config is empty then it's a no-op anyway.

(cherry picked from commit 06f76a2741)
2017-06-01 12:14:23 -05:00
d7ce5e68ea Fixed backup file behavior in check mode (#24899)
Fixes ansible/ansible#21523
(cherry picked from commit ce584571e8)
2017-06-01 12:14:23 -05:00
748b7c423f [cloud] Backport handling of CloudFormation int parameter values - fixes #23593 (#25051) 2017-06-01 12:14:23 -05:00
2eb727f1fe [cloud] Bugfix: Make wait_timeout integer type in redshift module (#25063)
Fix stricts datatype of wait_timeout to int as module
is using it as integer.

Fixes #25056

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2017-06-01 12:14:23 -05:00
31b531ad65 add empty links in docker_container fix to changelog 2017-06-01 12:14:23 -05:00
704c6f09c7 fixes #19550 (docker_container with empty links list always restarts)
(cherry picked from commit 7363776174)
2017-06-01 12:14:23 -05:00
70328b18d4 Update changelog with more fixes 2017-06-01 12:14:23 -05:00
2e5b4a9b2c Docker does not output Status after pull anymore.
- Docker 1.12 on CemtoOS7 does not output status line anymore.
- Do not rely on Docker output to verify if the image was the latest.

(cherry picked from commit 5f3c887c38)
2017-06-01 12:14:23 -05:00
b05b5b9347 Properly handle Docker image comparison for published_ports defined as IP::PORT
- Published port defined as IP::PORT where parsed in expected.parameters
  as 0.0.0.0::PORT leading to changed==True on every playbook run.

(cherry picked from commit 64f63a3cac)
2017-06-01 12:14:22 -05:00
4978566117 Fixed #21464 - docker_network: TypeError with existing network (#24266)
Fixed #22530 - docker_network Failed but Overlay network created successfully on Docker swarm mode
(cherry picked from commit 3610a2457f)
2017-06-01 12:14:22 -05:00
121941635d Add docker fixes 2017-06-01 12:14:22 -05:00
bf94109ade rebuild docker containers if there are less ports exposed
(cherry picked from commit cb3026f769)
2017-06-01 12:14:22 -05:00
e42b4a266b Add os_user fix to changelog 2017-06-01 12:14:22 -05:00
93fed65ea2 os_user: fix module undefined
module variable in the function is undefined. Pass it.

fix "NameError: name 'module' is not defined"

(cherry picked from commit a5c70dc672)
2017-06-01 12:14:22 -05:00
095be9c904 updated changelog service fix 2017-06-01 12:14:22 -05:00
dfb00f4c5f fixes for insserv on SLES11
fixes #23700, seems SLES11 has diff behaviour of insserv
these changes are compatible with debian/ubuntu.

(cherry picked from commit a86878c425)
2017-06-01 12:14:22 -05:00
0d57e17d67 Add docker_container fix to changelog 2017-06-01 12:14:22 -05:00
c3d5e2da91 typo in security opts
(cherry picked from commit fab2dfd1c6)
2017-06-01 12:14:22 -05:00
af0583d8b6 updated chlog 2017-06-01 12:14:22 -05:00
718554a39e updated with solaris fact backport fix 2017-06-01 12:14:22 -05:00
20008be317 Solaris fact fix (#24793)
* ensure locale for solaris fact gathering

fixes issue with locale interfering with proper reading of decimals
fixes #24542

* fixed typoe

(cherry picked from commit e558ec19cd)
2017-06-01 12:14:22 -05:00
f9d781bcab add xattr integration tests to ci (#24950)
* add xattr integration tests to ci

* fix package syntax

* remove unnecessary become, disable xattr for bsd and osx

(cherry picked from commit 4b6db5db7c)
2017-06-01 12:14:21 -05:00
081e98739e add integration tests for xattr module (#24947)
* add integration tests for xattr module

* fix whitespace

(cherry picked from commit 25aac6151f)
2017-06-01 12:14:21 -05:00
dd20427db9 Fix expect for python 3 (#24912)
* Fix expect for python 3

- Change generator next to python 3 compatible
- Added tests for expect

* Add pexpect to integration.txt

- add pexpect library to requirements for integration tests

* Use ansible_python_interpreter in integration tests for expect

* Use double-quotes for expect integration tests

* Cast user input to string for expect integration tests

* Cast user input to string earlier in expect integration tests

* Use ansible.module_utils.six.moves input for expect integration tests

* Fix yamllint errors in the expect test

* Use cat to trigger timeout for expect integration tests

* Use realpath filter in expect integration tests

(cherry picked from commit daada2000c)
2017-06-01 12:14:21 -05:00
c57e5e1305 Remove vertica_schema from the pep8 legacy files 2017-06-01 12:14:21 -05:00
1eef136c7c Fix bad merge of vertica_user 2017-06-01 12:14:21 -05:00
091a379da1 Vertica schema fix (#24915)
* replace deprecated cmp() with custom conditional
cmp is not present in Python3 but several modules use it
Reference 24756
(cherry picked from commit 5240e5a230)
2017-06-01 12:14:21 -05:00
ef40b0085b Read directory_mode as 'raw' type
Reads the directory_mode param as 'raw' type to mirror the same behavior as mode.
This'll cause non-quoted values to be represented as an int, rather than a str.

Covered by 'assert recursive copied directories mode' test.

Fixes #24202

(cherry picked from commit 8d8cfb5fcd)
2017-06-01 12:14:21 -05:00
f82e80dac6 Bugfix: Directories in /etc/skel will get users ownership when home dir is created (#24943)
* Bugfix: Directories in /etc/skel will get users ownership when home dir is created
* Bugfix: Chmod works now recursive for the home dir

(cherry picked from commit 0dc5e8bf71)
2017-06-01 12:14:21 -05:00
cd659994bd Remove empty file that didn't exist in 2.3.0 2017-06-01 12:14:21 -05:00
0ace2b4332 Os port fix (#24913)
* replace deprecated cmp() with custom conditional
cmp is not present in Python3 but several modules use it
Reference 24756
(cherry picked from commit 1e4b227e6f)
2017-06-01 12:13:39 -05:00
ecb38fdf73 New release v2.3.1.0-1 2017-06-01 10:57:37 -05:00
87578049a0 Updating CHANGELOG for final release 2017-06-01 10:52:39 -05:00
fb636cb6f0 New release v2.3.1.0-0.2.rc2 2017-05-23 13:55:45 -05:00
f67a59bce6 Also check the iterator for failed host status in linear strategy
When only looking at the failed state of the TaskResult, certain failures
cause the linear strategy to fail out sooner than it should and not execute
the always portion of blocks.

Fixes #24301

(cherry picked from commit f217dae938)
2017-05-23 13:17:40 -05:00
8d0ea29df0 Added win_copy recursive integration test with trailing path separator. (#24523)
This is a reproducer for https://github.com/ansible/ansible/issues/23559

Tests will fail until https://github.com/ansible/ansible/pull/23581 is merged

Note that I believe another commit is also needed for this to work,
specifically the change from: https://github.com/ansible/ansible/pull/23326
(cherry picked from commit b46c098581)
2017-05-23 11:05:41 -07:00
1a8d6fb4cb win_copy: Fix recursive copy (#23581)
This fixes #23559.

This should be backported to v2.3 branch too.
(cherry picked from commit 9cd6f1bf91)
2017-05-23 11:05:28 -07:00
598b34a326 updated changelog with backported fixes 2017-05-23 10:38:18 -04:00
bffa355c6c Include error exception in AnsibleError
- Use to_native instead of str

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit f9b836a901)
2017-05-23 10:20:02 -04:00
a5e6639739 sysctl: switch basestring to string_types (#24277)
(cherry picked from commit 08a3ea2221)
2017-05-22 16:05:13 -07:00
daf2b5e5fb Changed assemble_from_fragments to use os.path.join (#24909)
Fixes #19437
(cherry picked from commit f8e47e2204)
2017-05-22 15:42:17 -07:00
3ad37b320f Bugfix for setting user groups on OpenBSD
(cherry picked from commit 2e392f47c8)
2017-05-22 18:16:31 -04:00
1cd78b91d9 Letsencrypt fix (#24906)
* Replaced deprecated cmp with custom condition

References  #24756

* Fix PEP 08 indention

(cherry picked from commit 16d522cf2c)
2017-05-22 14:59:05 -07:00
74f6c46e46 Converted the response from _get_url_data using to_native (#24901)
Updated the exception message to no longer use e.message.
Fixes #24526
(cherry picked from commit 45e4b8f97a)
2017-05-22 14:27:47 -07:00
97da8e161b Remove deprecation for username/password eos_user, nxos_user and Doc update (#24880) (#24893)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit 9fb9c00092)
2017-05-22 22:05:44 +05:30
e5f4d2b9c2 Fixed wrong variable in cumulus network module (#23950)
Signed-off-by: Phil Huang <phil_huang@edge-core.com>(cherry picked from commit 98a8b967d2)
2017-05-19 12:49:40 -04:00
b99f4892d7 remove self from function outside of class (#24017)
* remove self from function outside of class

* fix indentation

(cherry picked from commit 45ac28ba04)
2017-05-19 11:49:28 -04:00
7849e595b1 Base changes required to allow winrm to work on py3 (#24744)
(cherry picked from commit e7d8ebf080)
2017-05-18 16:11:04 -07:00
4542e83fa0 Convert some more base64 strings to text for winrm, to support async and become (#24796)
(cherry picked from commit 1eed6c5b3d)
2017-05-18 16:09:42 -07:00
c7b3e420b7 add segfault detection to TQM
* prevents indefinite hangs when a worker segfaults
(cherry picked from commit 569377e951)
2017-05-18 14:59:31 -04:00
ac8cb2a106 Downgraded more modules from Curated to Community (#24751) (#24784) 2017-05-18 11:13:47 -07:00
af417120e1 Fix transport getting set to None when not set explicitly (#24769) (#24773)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit feafae70b5)
2017-05-18 15:48:55 +05:30
3b82490c6f Save commit_timeout as string in junos_config (#24761) (#24764)
Fix converts commit_timeout to string as
Elementree.SubElement requires text as string.

Fixes #24611

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 2f955e7da8)
2017-05-18 13:36:08 +05:30
c5067cff6b Fix for ansible/ansible-modules-core#1568
When checksums of local and remote files match, and when follow = True,
determine if remote destination is a symlink. If so, de-reference it and
pass the link target to the file module as 'dest'.

This change fixes an edge case in file copy behavior when:

- 'dest' is a symlink to some other file ('realdest')
- follow = True
- the checksums of the source file, 'src', and the symlink target, 'realdest',
  match.

Because the checksums match, the copy module is skipped and the file module
is invoked directly with 'dest' = the symlink, and 'src' = the source of the
copy module, whether that source is present on the target machine or not.

When 'src' doesn't exist on the target machine, this leads to an error that
looks like this because it can't change the target of the symlink:

TASK [copy] ********************************************************************
fatal: [192.168.56.101]: FAILED! => {"changed": false, "checksum": "f572d396fae9206628714fb2ce00f72e94f2258f", "failed": true, "gid": 1000, "group": "ajdecon", "mode": "0777", "msg": "src file does not exist, use \"force=yes\" if you really want to create the link: /tmp/issue1568/dest_dir/source", "owner": "ajdecon", "path": "/tmp/issue1568/dest_dir/dest", "size": 8, "src": "source", "state": "link", "uid": 1000}

When the path 'src' *does* exist on the target machine, the file module makes
this the symlink "dest -> src" instead of "dest -> realdest"... even if the
checksum of 'src' on the target machine is different from the checksum of 'src'
on the machine where Ansible is running.

(cherry picked from commit 2f74f6738d)
2017-05-18 02:32:02 -05:00
180ce9ffe6 Avoid default serialization of classes in dump_attrs
For playbook base objects, when dumping attributes via dump_attrs() an
attribute like loop_control is a class. Using the default serialization
for these is slow and consumes a lot of memory. Since LoopControl is also
based on the Base class, we can use serialize() instead and save a lot of
resources.

This also adds a from_attrs() complimentary method to nicely turn the
dumped attrs back into proper field attributes.

Fixes #23579

(cherry picked from commit 78478e80ea)
2017-05-17 06:57:11 -05:00
3a6fd9448e Limit sphinx version on python 2.6. (#24678)
* Limit sphinx version on python 2.6.
* Fix issues identified by rstcheck.

(cherry picked from commit 9178e176b5)
2017-05-17 01:07:41 +08:00
7e605f4e84 Use delegated vars for the delegated host name
In _process_pending_results (strategy/__init__.py), we were using the delegate_to
field directly from the original task, which was not being templated correctly.
As an alternate to #23599, this patch instead pulls the host name out of the delegated
vars passed back in the task result dictionary to avoid having to re-template things.

Fixes #23599
Fixes #20508

(cherry picked from commit e5cd675b38)
2017-05-16 10:46:40 -05:00
f7318ec891 updated changelog with bugfix 2017-05-15 09:32:58 -04:00
4506da6a6f Fix UnboundLocalError in basic.py
* Fix for UnboundLocalError while accessing deprecations
  in result
* Add Unit test

Fixes #24592

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 764b4b20ec)
2017-05-15 09:32:35 -04:00
a43374ed32 Set facts type to dict
With newer versions of ansible, module arguments are assumed to
be strings unless otherwise specified.  Our 'facts' argument is
expected to be a dictionary, so tell ansible that.

Without this, the argument will arrive as a string and be written
to the facter file inside string quotes.  Facter will produce the
following error:

  undefined method `each' for #<String:0x000000016ee640>

This was originally fixed and found in the Ansible Puppet role which
is maintained by the OpenStack infrastructure team.

8d0f0bfd0a
2017-05-14 14:10:21 -04:00
cc18296cc5 Fix timeout issue in ansible-connection (#24556) (#24579)
Fixes #24520 ansible-connection needs
to wait on timeout value of play-context
instead of ssh default timeout
(cherry picked from commit 5ec7f40196)
2017-05-13 18:35:13 +05:30
d94ac763b6 removing folded style formatting for synopsis (#22746)
(cherry picked from commit e539726543)
2017-05-12 12:02:07 -04:00
40ea76cf5a Add bugfixes to changelog 2017-05-12 05:44:28 -07:00
cdd6ab000b Fix template not showing a diff with a directory
Template can take a directory as the destination.  When that's the case,
we need to diff between the source and the file inside of the directory.
That happened when the directory was specified with a trailing slash but
not when it was specified on its own.  This change fixes that.

Fixes #24413

(cherry picked from commit 548cacdf6a)
2017-05-11 20:37:55 -07:00
58438762a1 Fix import of shlex_quote
the backport here 1f3f4cf702 forgot that
in ansible-2.3, the six library in ansible.module_utils is only 1.4.
1.4 doesn't have shlex_quote.  Importing it from ansible.compat works
for ansible-2.3.
2017-05-11 17:30:11 -07:00
41e3027fda Fix pam_limits writing text to a file opened in binary mode
Fixes #24392

(cherry picked from commit 16325f6f15)
2017-05-11 17:17:53 -07:00
6f92ca058a Downgrading module from core to community (#24463) (#24512) 2017-05-11 13:10:19 -07:00
5a47644dc6 added bugfix to changelog 2017-05-11 15:48:19 -04:00
1f3f4cf702 deal with null/none connections
fixes #23621
pushed 'connection resolution' to play_context
override fieldattribute getter

(cherry picked from commit c50cf22d52)
2017-05-11 15:47:09 -04:00
5f0be9dcd0 slightly increase win_async_wrapper fire and forget sleeptime
* should fix Shippable timeouts when AWS CPU credits are low- right on the bubble of failure w/ 5s execution
(cherry picked from commit ead23783be)
2017-05-09 11:23:05 -07:00
5a3f52d988 New release v2.3.1.0-0.1.rc1 2017-05-09 08:47:02 -05:00
15f635f7c3 Reference correct variable and key for role expiry (#23397) (#24405)
Previously, this module could throw the following error message:
    NameError: global name 'current_roles_attrs' is not defined

The referencing key should also match the name of the column, which is
rolvaliduntil, not rol_valid_until
(cherry picked from commit c5adf08c40)
2017-05-09 14:06:28 +01:00
b87ffb2082 Check if api_key and app_key before proceeding (#24336) (#24403)
Fix adds check if app_key and api_key provided by
user is correct or not. If this combination is wrong
then fail with appropriate error message given by
Datadog server

Fixes https://github.com/ansible/ansible/issues/24325

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit e342b281d8)
2017-05-09 13:27:30 +01:00
787303284f fix spurious warnings with ansible_winrm_kinit_X args (#24380)
* added to pywinrm arg whitelist
* clarified error text on kinit_mode error
* fixes #23822
(cherry picked from commit 98ff93b2db)
2017-05-08 11:31:03 -07:00
a1886911fc Fixing security issue with lookup returns not tainting the jinja2 environment
CVE-2017-7481

Lookup returns wrap the result in unsafe, however when used through the
standard templar engine, this does not result in the jinja2 environment being
marked as unsafe as a whole. This means the lookup result looses the unsafe
protection and may become simple unicode strings, which can result in bad
things being re-templated.

This also adds a global lookup param and cfg options for lookups to allow
unsafe returns, so users can force the previous (insecure) behavior.

(cherry picked from commit 72dfb1570d22ac519350a8c09e76c458789120ed)
2017-05-08 11:11:47 -05:00
ab399146b4 fixed yum.parse_check_update regex (#24331)
Output of `yum check-update` can contain lines with long package names and long
repository label names, which will be broken into multiple lines, which need to
be sanitized. The solution to this has been fixed and refactored in 2.3 in form
of parse_check_update(), but it still contains subtle bug, which makes such
multi-lines invisible to later logic (such packages aren't included in
parse_check_update()) output. The problem is caused by using '\1' in re.sub(),
instead of proper r'\1', which literally puts unicode symbol \1 into resulting
output.
(cherry picked from commit c4ad0f86c7)
2017-05-08 10:53:08 -04:00
572c07ddb3 Fix vaulted vars templating
Use the default repr of AnsibleVaultEncryptedUnicode.data instead
of a custom one, since jinja templating ends up using the repr()
results.

Fixes #23846, #24175

(cherry picked from commit 7fe2064162)
2017-05-08 10:16:35 -04:00
2cab2118a1 Give user whatever information we have from ssh-keyscan
ssh-keyscan isn't very verbose about errors.  Give the user whatever
information we have available even if it isn't much.  At least they will
know how we were running ssh-keyscan and why there's an error now.

Fixes #19440

(cherry picked from commit 4bf8071889)
2017-05-05 08:35:36 -07:00
f57d7bb016 Fixes #23285 (#24291)
Makes subversion module --check fail when modified files are in
repository.
(cherry picked from commit 4bd04c299b)
2017-05-04 10:09:16 -07:00
4a7230aa3c adjusted descriptions in DOCUMENTATION, and fixed type in RETURN
(cherry picked from commit 2a7ce1059d)
2017-05-04 07:39:06 -07:00
228553f931 Switch last remaining decode to to_text (#24269) 2017-05-03 16:51:51 -05:00
77fa3f1598 include_vars to delegated only if delegate_facts (#24259)
* include_vars to delegated only if delegate_facts

fixes #24172

* since code is now same, simplified

(cherry picked from commit b731c2d809)
2017-05-03 16:30:25 -04:00
5c8e11ac9f Add ansible-vault encrypt_string doc (#24147)
* Add documentation on 'ansible-vault encrypt_string'
2017-05-03 12:20:39 -04:00
c249662e10 Fix junos_rpc and junos_user broken issues (#24238) (#24246)
* Fix junos_rpc and junos_user broken issues

Add persistent connection related changes.

* Fix CI issues

(cherry picked from commit a42b892f70)
2017-05-03 19:58:24 +05:30
ec3a5b0e17 Fix netconf port validation and minor doc change (#24210) (#24239)
* Fix netconf port validation and minor doc change

Add check to confirm if `validate_*` funcion is
callable.

Add `config_format` in `junos_facts` documentation

* Fix review comments

(cherry picked from commit 73c24001d9)
2017-05-03 16:02:21 +05:30
af018b75f0 Add integration test that modules are loaded from the expected locations (#24170)
* Add integration test that modules are loaded from the expected locations
* Fix ping module to pass PEP8

(cherry picked from commit 3428f42120)
2017-05-01 08:57:31 -07:00
778173ec07 Fix password prompt matching (#24081)
* Fix password prompt matching

* Add some tests for check_password_prompt

* Prevent pep8 line ends with a space error

(cherry picked from commit 040fb4435a)
2017-05-01 11:18:38 -04:00
8a604185fd make 2.4 compatible
fixes #24148
2017-05-01 11:18:38 -04:00
98d223a51b Facts Timeout was not settable via ansible.cfg
The timeout for gathering facts needs to be settable from three places
(highest precedence to lowest):

* programmatically
* ansible.cfg (equivalent to the user specifying it explicitly when
  calling setup)
* from the default value

The code was changed in b4bd6c80de to
allow programmatically and the default value to work correctly but
setting via ansible.cfg/parameter was broken.

This change should fix setting via ansible.cfg and adds unittests for
all three cases

Fixes #23753

(cherry picked from commit d088030fa6)
2017-05-01 08:00:11 -07:00
0467017a70 Remove provider requirement from nxos_vrf (#24118)
Fixes #23920
(cherry picked from commit dce2d5eea9)
2017-05-01 09:33:32 -04:00
776551afa5 Fix ClearLinux pretty name
ClearLinux has changed its pretty name in os-release file
from: 'Clear Linux Software for Intel Architecture'
to: 'Clear Linux OS for Intel Architecture'

This patch makes the SEARCH_STRING 'Clear Linux' rather than
the full name to make it compatible with the old and new name.

Signed-off-by: Alberto Murillo Silva <alberto.murillo.silva@intel.com>
(cherry picked from commit bb234b9206)
2017-05-01 08:53:23 -04:00
cf224ab31b Minor typo correction varibles -> variables
No impact as variable wasn't used.
(cherry picked from commit 403c142750)
2017-05-01 08:45:01 -04:00
41a70bf9ca Print specific error for BadHostKeyException (#24120)
(cherry picked from commit f9ec06d1dc)
2017-04-28 14:00:53 -04:00
6915e026ed Fix exception in junos_package (#24107) (#24116)
(cherry picked from commit 06732acd4c)
2017-04-28 19:49:00 +05:30
20c5aee565 Rename fact returned by docker_network to avoid restricted prefix (#23919)
This fixes #23918
2017-04-28 08:47:07 -05:00
e509122aad Remove idle ShellError exception and get_exception() method from nxos modules (#24091)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit aa1f922606)
2017-04-28 10:50:38 +05:30
ab79e96c3c Fix exception issue in junos_config (#24066)
ParseError execption is added to ElementTree
in py2.7. Prior to py2.7 need catch ExpatError
execption
(cherry picked from commit 7d710882a8)

* Fix python version check issue (#24063)

Fix python version check issue
(cherry picked from commit 1f7c2c63c2)
2017-04-27 20:52:26 +05:30
b4380432f6 Run save inside config mode. (#23977)
* Run `save` before exiting config mode.

* Fix unit tests for `save`

* Allow `save` to be on its own again and introspect success

* Introspecting `compare running` makes this a lot harder.

Move `save` tests to integration tests

(cherry picked from commit fc0bf87c20)
2017-04-27 11:09:38 -04:00
126878488f Fix bugs in ansible-test units command. (#24044)
* Handle old versions of coverage.
* Handle old versions of setuptools.
* Detect python version for docker/remote units.
* Add sanity override for test constraints.

(cherry picked from commit d662f6f0db)
2017-04-27 11:22:44 +08:00
4b2d80f662 Add changelog entry for fetch parameter change 2017-04-26 09:28:29 -07:00
9b00648f21 Set validate_checksum default yes of fetch to match the doc
(cherry picked from commit 98e7d4b49d)
2017-04-26 09:27:34 -07:00
456ec66b0a asa_command: set default_output to text (#23979)
(cherry picked from commit 9a0a7f78d7)
2017-04-26 09:47:35 -04:00
19c4e1a992 Use Shippable image: drydock/u16pytall:master
* Use Shippable image: drydock/u16pytall:master
* Do not install python 3.6 on Shippable.
2017-04-26 15:49:21 +08:00
c60b3166b1 Change wait_for time to utc (#23987)
(cherry picked from commit 8466c808d9)
2017-04-25 18:05:10 -04:00
d1c14e8aa4 moved to exceptions for basic skip/fails
better handling of checkmode and async
fix test to follow new flow control

(cherry picked from commit e29dc49a49)
2017-04-25 14:51:22 -04:00
6ada5cc074 Fixes #23960 junos_config fail with config in xml (#23962) (#23978)
If config is in xml format append it to <configuration>
tag as a instance of Element class.
(cherry picked from commit 15c19367d6)
2017-04-25 22:50:35 +05:30
f20cd780a4 exoscale: fix TXT type records handling (#23956)
(cherry picked from commit 3959597f7d)
2017-04-25 13:08:02 +02:00
107308f6df Set terminal width for network *_command modules to avoid paging (#23728) (#23952)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit f354bd1eab)
2017-04-25 14:33:59 +05:30
8c6a2a848c pacman: Fail fast when 'rc != 0'
We fail-fast and display 'stderr' in case 'pacman' returns with 'rc != 0'.
There is no point computing 'module._diff' in such case anyway.

Fixes #23910
2017-04-25 02:07:06 +02:00
Kai
58666c0ca4 Fix systemd in chroot (#23904)
* Fix systemd in chroot

The 'request ignored' message is in stderr, not stdout.

* Check both stdout and stderr for systemd message

Some versions of systemd report to stderr, others to stdout. Also check
whether output could be a valid normal response to avoid false positives.

(cherry picked from commit cb13aea88b)
2017-04-24 19:54:50 -04:00
476e8c7136 avoid hosts 'pre templated warnings' (#23878)
* avoid hosts 'pre templated warnings'

fixed is_template failing on undefined
fixes #23057

* py3 compat

(cherry picked from commit a108f0fcd3)
2017-04-24 15:19:50 -04:00
2ca4155f23 Use sys.stdout.buffer to write vault bytes to stdout on py3 (#23760)
* Use sys.stdout.buffer to write vault bytes to stdout on py3

We need sys.stdout.buffer on py3 so we can write bytes to it since the plaintext
of the vaulted object could be anything/binary/etc

Before, attempting to write bytes to stdout on py3 would cause:

  TypeError: write() argument must be str, not bytes

(cherry picked from commit e0a7105c2d)
2017-04-24 10:13:22 -04:00
4b5553c97f fix environment populated detection
fixes #23764

(cherry picked from commit 27185f44b0)
2017-04-21 18:21:17 -04:00
0878f45a6c keep unsafe .. unsafe (#23742)
* keep unsafe .. unsafe

fixes #23734, which was broken in previous fix that allowed non string types to be templated
use new 'is_template' function vs bastardizing others
refactored clean_data to allow for arbitrary data structures to clean
fixed/removed some tests

(cherry picked from commit 4594bee65a)
2017-04-21 16:09:48 -04:00
a71b6041f6 Fix display argument defualt value (#23859) (#23860)
(cherry picked from commit 04ae977f39)
2017-04-21 19:16:13 +05:30
ee19b19984 Remove catch-all regex on IOS terminal plugin (#23858)
We have a list of specific messages that we scree-scrape and flag
them as legit errors.
However, we also have a catch-all regex that matches everything
starting with %.
That can cause issues on commands that return lines with that
character, like for example the 'crypto key generate'.

Fixes #23770
(cherry picked from commit 8517fbf936)
2017-04-21 15:31:17 +02:00
a1c0c1582b Add assertion on test_iosxr_facts (#23852)
We hit bug #23737 due to bad coverage on test_iosxr_facts, we
were not checking memory facts at all.
(cherry picked from commit 60de93c31d)
2017-04-21 11:21:40 +02:00
283f7f9e24 Fix the iosxr_facts mem gathering (#23850)
We were not calling match.group, plus we were lacking a ':' from
the expected output of 'show memory summary'.

Fixes #23737
(cherry picked from commit d0fd8cefaa)
2017-04-21 10:45:18 +02:00
1ea67950e1 Add eos_user module to users parameter (#23847) (#23849)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit 8ec4882ba0)
2017-04-21 13:36:21 +05:30
0d2d9f897c Add doc for display argument of junos_command (#23804)
(cherry picked from commit 01afe12cba)
2017-04-21 02:32:29 -04:00
a021b4bd8b template hostvars for set_host_overrides (#23839)
* fixes #23586
* temporary solution until connection-specific vars are handled by play_context
(cherry picked from commit 02ed223d49)
2017-04-20 20:34:32 -07:00
c05aa93739 Revert "fixes play context connection user (#21776)" (#23830)
* Revert "fixes play context connection user (#21776)"

This reverts commit 58ee661437.
fixes #23530

* preserve original in copy

updated comment to clarify wtf is going on here

(cherry picked from commit eb887b8062)
2017-04-20 18:03:21 -04:00
62811bf134 also skip polling when async failed
(cherry picked from commit 94f0a4edd5dad15f720ec087f04f20bcbef1b97b)
2017-04-20 18:03:21 -04:00
68fff4a4b5 script fails on async
(cherry picked from commit fe9af903f3)
2017-04-20 18:03:21 -04:00
4567527249 fix vars file selection
fixes #17382
alternate to #22979

deal with cases in which group/host have . in name
updated as per feedbck
only be strict about extension when doing dirs
also avoid ~ endings

(cherry picked from commit 602a2bca1b)
2017-04-20 18:03:21 -04:00
1fdeef511c finer grained failed/skipped on async for actions
fixes #23729

(cherry picked from commit 3965689328)
2017-04-20 18:03:21 -04:00
bc990004e1 fix hashing when path is symlink
(cherry picked from commit 631a10745d)
2017-04-20 18:03:21 -04:00
c9b0026cd0 Eos port default values (#23829)
* Hook port back up for eos cli transport

* The default values have moved

* Why not have conditional defaults?
2017-04-20 16:04:47 -04:00
0609b9ded0 EOS default transport (#23824)
* Give a default to eos transport
2017-04-20 16:04:47 -04:00
d74509a235 Use isfile check on package manager paths
(cherry picked from commit 5bbf0d9cb6)
2017-04-20 07:43:25 -07:00
c84a332531 Add guide for Packet host (#21346) (#23807)
* Add guide for Packet host

* incorporate feedback from Packet

* Format headings according to Python doc guide

* fixed rstcheck issues in packet guide

(cherry picked from commit 0b585ec4fd)
2017-04-20 15:01:21 +01:00
cc59d89538 Add eos_banner as module to banner param (#23789) (#23798)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit b2129a7d3a)
2017-04-20 16:34:40 +05:30
b7ba7d40ae Show UUID instead of name when using UUID to select snapshot (#23787) (#23794)
(cherry picked from commit 504a768636)
2017-04-20 11:12:58 +01:00
0347dcda05 Minor typo in vmware_guest_facts (#23791) (#23793)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit cc745b0224)
2017-04-20 11:07:16 +01:00
81efc176f4 Add missing provider to eos_banner basic-motd eapi test (#23396)
Otherwise this stalls and timeouts, it doesn't have creds to run.
(cherry picked from commit 2cc2b8fb4d)
2017-04-20 10:57:54 +02:00
79492a9d2d Check for proper response key on eos_banner map_config_to_obj (#23399)
If we run the task with 'login' banner, the 'show banner' command
will return a dict containing key 'loginBanner'.
However for motd, it will just return 'motd'.
Yay naming consistency!
(cherry picked from commit ba7ba7adc3)
2017-04-20 10:57:22 +02:00
a769f0b0f4 Do not assert session name on idempotent eos banner (#23402)
* Check for proper response key on eos_banner map_config_to_obj

If we run the task with 'login' banner, the 'show banner' command
will return a dict containing key 'loginBanner'.
However for motd, it will just return 'motd'.
Yay naming consistency!

* Do not assert session exists on eos_banner response not changing device

(cherry picked from commit 13b2f11139)
2017-04-20 10:57:05 +02:00
b9ee0c5477 fix ansible galaxy file mangling (#23703)
without this patch, ansible-galaxy will mangle files containing
the archive parent directory name, eg 'owncloud/files/owncloud.cron'
will become 'owncloud/files/.cron'.

The previous code could affect the entire path and even filenames.
If a file path has the top level dir name as a substring, galaxy
replaces it with ''. In one example, the archive top level dir
is 'go', so 'files/go-bin.sh' becomes 'files/-bin.sh'.

Fixes #22572, #23694, #23623
(cherry picked from commit 79943b86a1)
2017-04-19 14:17:18 -04:00
d7c8d8ab4d Fix example fact(ansible_default_ipv4.address) for delegated_facts
(cherry picked from commit d04a5246de)
2017-04-19 11:00:40 -07:00
898650d6bc Remove whitespace from unix group names
(cherry picked from commit d0e3d75381)
2017-04-19 09:43:34 -07:00
27073dd9bd Fix for setting values using gconftool-2 (#23713) (#23740)
Miscallenous fixes added to make gconftool-2 work.

Fixes https://github.com/ansible/ansible/issues/23670

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 27f776f97d)
2017-04-19 14:25:32 +01:00
c92765e26e Make warning logs consistent (#23666) (#23716)
* Make warning logs consistent

Arguments outside provider with default
value should not log as warning in case
it is not mentioned in play.

* Make nxos timeout default consistent and add comments

* Make comments more verbose

(cherry picked from commit bf1a543f06)
2017-04-18 22:57:22 +05:30
db738e0a2d Remove Warning for provider (#23652) (#23714)
(cherry picked from commit b8507b676b)
2017-04-18 22:49:23 +05:30
32be9a9273 Fix vault reading from stdin (avoid realpath() on non-links) (#23583)
* Fix vault reading from stdin (avoid realpath() on non-links)

os.path.realpath() is used to find the target of file paths that
are symlinks so vault operations happen directly on the target.

However, in addition to resolving symlinks, realpath() also returns
a full path. when reading from stdin, vault cli uses '-' as a special
file path so VaultEditor() will replace with stdin.
realpath() was expanding '-' with the CWD to something like
'/home/user/playbooks/-' causing errors like:

        ERROR! [Errno 2] No such file or directory: u'/home/user/ansible/-'

Fix is to specialcase '-' to not use realpath()

Fixes #23567

* to_text decrypt output when writing to stdout

(cherry picked from commit ae3d7fb29e)
2017-04-18 13:08:59 -04:00
8e1b422e4a When become_method is su, self._play_context.prompt is a function. Fixes #23689
(cherry picked from commit f82d95ae28)
2017-04-18 13:02:12 -04:00
82dcaa725f pep8 fix for Shippable 2017-04-18 11:45:43 -04:00
7cd2b8d7a0 tolerate 'batch' systems that mess with stdin (#23596)
* tolerate 'batch' systems taht mess with stdin

fixes #23541

* have pause on windows tolerate devnull

* tuplie

(cherry picked from commit 586fcae398)
2017-04-18 11:39:55 -04:00
c4b6b87344 nxos_vlan tweaks (#23194)
* Remove commented code

Remove a lot of unnecessary output

* Tests

* Sort vlan ids _after_ running set operations, so order is not lost
(cherry picked from commit 0b4cebfb8b)
2017-04-18 10:52:56 -04:00
f66852f1ef Nxos vxlan vtep vni netcfg fix (#23620)
* Code cleanup
Removed 'add' method from CustomNetworkConfig.  It is identical
to the one inherited from NetworkConfig

* Removed unused CustomNetworkConfig import

* Replaced
```
def get_existing(module, args):
    existing = {}
    netcfg = get_config(module)
    config = netcfg.get_section(parents)
```
with
```
netcfg = CustomNetworkConfig(indent=2, contents=get_config(module))
```
get_config returns a string, not an object in 2.3.

* Removed non-functioning get_object method in CustomNetworkConfig in favor of the
inherited method.

Added child_objs property so that expand_selection would work.  The original
verion never worked correctly as it compared NetworkConfig obj's and str's.

* Removed ShellError method in favor or new load_config method.

* Removed ShellError method in favor or new load_config method.
fixes #20260

* nxos requires a "no" statement to change mcase group.  Corrected.
Corrected changed logic.

* Corrected deleted CustomNetworkConfig import
2017-04-17 12:39:21 -04:00
d1d0f382a2 Clean up import statements for nxos_rollback (#23540)
* Clean up import statements for nxos_rollback

* Don't try to deal with pre-2.3 logic
(cherry picked from commit e518b6f5b4)
2017-04-17 08:55:47 -04:00
39c2e4c28b Make logging consistent for network platforms (#23605) (#23648)
(cherry picked from commit 89752cc34f)
2017-04-16 23:38:48 +05:30
b721fa2ef5 Fix documented defaults in the nsupdate module (#23532) (#23637)
Let the documentation reflect what the module actually implements.
(cherry picked from commit 40f9f98f7c)
2017-04-15 17:12:38 +01:00
b8400cd897 Fix #23338 - rabbitmq_queue message ttl can't be 0 (#23448)
(cherry picked from commit 8b4f5ba064)
2017-04-15 00:56:57 +02:00
8b5267f09f fixes issue where network modules would ignore provider host value (#23589) (#23608)
This addresses a problem where the action plugin would ignore the
remote_addr value for the host.  In this case, only the inventory values
for the hostname would be considered and populate the remote host
remote_addr value for the connection plugin.
(cherry picked from commit c2370f14dd)
2017-04-14 17:59:13 +05:30
06be3c56a9 Add rstcheck to ansible-test and correct issues. (#23550)
* Add rstcheck to ansible-test.
* Fix rst code-block languages and syntax errors.
* Fix rst inline literals.
* Update python 2 code block to pass tests on py 3.

(cherry picked from commit cb1f57d4e5)
2017-04-13 13:18:53 -07:00
92bdd13bb1 Fix var precedence check to support python 3. (#23552)
* Fix var precedence check to support python 3.
* Run CI sanity tests using python 3.5.
* Disable pylint non-iterator-returned test to pass on python 3.5.

(cherry picked from commit e7bb508ad6)
2017-04-13 13:15:43 -07:00
69562c5d20 Fix module validator blacklist handling.
Process the blacklist before creating a validator instance.

(cherry picked from commit 442768c45e)
2017-04-13 13:15:36 -07:00
4452429b45 Add Python 3 support for validate-modules test. (#21195)
* Improve PEP8 compatibility

* Fix Python 3 incompatibility

Is prohibited to mutate OrderedDict during iteration through it so
is better to add records with error or warning to empty dictionary
instead of delete records from copy of dictionary during iterating.

* Decode output of subprocess from bytes to unicode.

* Add Python 3 support for validate-modules test.

Fix #18367

(cherry picked from commit 9d41aefd71)
2017-04-13 13:15:29 -07:00
a256745eae fix validate-module sanity error per https://app.shippable.com/github/ansible/ansible/runs/16493/1/console (#22711)
(cherry picked from commit d791665559)
2017-04-13 13:15:21 -07:00
345749884d Fix module validation without base branch.
(cherry picked from commit 672e9a2f61)
2017-04-13 13:15:13 -07:00
5667fe6746 Support module alias and rename validation. (#22675)
Cache git ls-tree output to speed up validation.
(cherry picked from commit 1f337b6421)
2017-04-13 13:14:58 -07:00
c9de302fc6 removed debug print
(cherry picked from commit 313591f8b8)
2017-04-13 15:12:53 -04:00
6883cad07e Temporarily cap pylint version < 1.7.0 in tests.
(cherry picked from commit 4ee96b20a3)
2017-04-13 11:27:30 -07:00
85fa2a9dd4 Make it easier to find network modules (#23576) (#23584)
* Make it easier to find network modules

Feedback has been it's difficult (via Google or directly) to find
modules as some people search for the company name vs product name,
therefore specify both.

* "IOS XR" (not "IOS-XR")

(cherry picked from commit 92a425a532)
2017-04-13 11:27:30 -07:00
5865356e92 network_cli modules don't always return stdout or stdout_lines (#23573) (#23582)
It's possible that if the module has a low-level failure, such as
"unable to open shell", or something else in the action plugin that
stdout and stdout_lines will not be returned.

Update the documentation to clarify this point.
(cherry picked from commit 2bb25d031b)
2017-04-13 11:27:30 -07:00
bc43de7b21 Error string:Regular expression updates (#23426) (#23569)
(cherry picked from commit c86feeaed9)
2017-04-13 11:27:30 -07:00
a574dc7bf1 [WIP] Network return docs (#23441) (#23535)
Network return docs
(cherry picked from commit 902bc58509)
2017-04-13 11:27:30 -07:00
c5fcae130f Add checks to confirm that the output from xfs_info has the expected format.
(cherry picked from commit 57c67f0c08)
2017-04-13 11:27:30 -07:00
45c2887b19 Fix ansible-test handling of import/syntax errors.
(cherry picked from commit 0cf1e8e061)
2017-04-13 11:27:30 -07:00
84d5e6e645 Fix errors reported by pylint. (#23282)
* Fix pylint misplaced-bare-raise errors.
* Fix pylint return-in-init error.
* Fix pylint bad-format-character error.
* Fix pylint too-many-format-args errors.
* Fix pylint too-few-format-args errors.
* Fix pylint truncated-format-string error.

(cherry picked from commit 48eeab8a53)
2017-04-13 11:27:30 -07:00
92c4a3319c Initial pylint support for ansible-test sanity.
(cherry picked from commit 1daa69d685)
2017-04-13 11:27:30 -07:00
1a30df265d Fix Postgres user module always reporting changes (#23488)
(cherry picked from commit 54316f7da0)
2017-04-13 11:27:30 -07:00
ee69fd140b When apt errors, include it's exit code
We invoke /usr/bin/apt inside of the ansible module.  When that command
exits, it doesn't always include a helpful error message.  Include the
exit code so that user's have all the information we can gice them as to
why apt failed.

Addresses #19128

(cherry picked from commit b4f976e9b9)
2017-04-13 11:27:30 -07:00
f57d0bab32 Set IO encoding for ansible-test on Shippable.
(cherry picked from commit eec01e2137)
2017-04-13 11:27:30 -07:00
a491adc425 Fix ansible-test empty diff handling on Shippable.
(cherry picked from commit 92ad9a19b6)
2017-04-13 11:27:30 -07:00
5f53a159a0 rpm_key: Decode bytes to string to work with Python 3 (Fixes #20326) (#20385)
* rpm_key: Decode bytes to string to work with Python 3 (#20326)

The read() method will return bytes we need to then decode() those bytes
to a string before trying to match() it using the re module.

* Make the rpm_key pgp regex more robust on both py2 and py3

(cherry picked from commit cee8cc2a52)
2017-04-13 11:27:30 -07:00
f2cf1dba92 Update the comments around Python 3
[Enterprise Linux 5 is at the end of "End of Production 3 phase"](https://en.wikipedia.org/wiki/Red_Hat_Enterprise_Linux#Product_life_cycle) so that is no longer a reasonable reason to wait.  Also removed the comments about [Python 3 not being mainstream](http://python3wos.mybluemix.net/201).  Perhaps a link to https://docs.ansible.com/ansible/python_3_support.html would also be a useful addition to this question.
(cherry picked from commit 6314169afd)
2017-04-13 11:27:30 -07:00
561d424a0e Open unarchive file in binary mode
Recent Python3 versions require open() to specify binary mode if the data is anything other than text.

Python3: Use int() instead of long() in unarchive

Changes long() to int() for CRC values in the unarchive module. Affects unarchiving of zip files. Since CRC values in zipfile are 32 bits the behaviour should be unchanged even in Python 2.
2017-04-13 11:27:30 -07:00
ba977b7cd7 Open file in binary mode for python3
(cherry picked from commit 1963e506ec)
2017-04-13 11:27:30 -07:00
53b19611e1 Fix a traceback with python3 and diff output
When retrieving file contents for diffing we need to get the contents as
binary.  Otherwise python3 will try to convert the file to text and fail
with non-decodable contents.

Fixes #23171

(cherry picked from commit 2fdb8e7f90)
2017-04-13 11:27:30 -07:00
b8d6f23fb7 Fix a10 pylint issues (#23410) (#23413)
* Fix a10 pylint issues
* Moving imports to standard location

(cherry picked from commit 3934513121)
2017-04-13 11:27:30 -07:00
b96407be86 Extra deps needed for building cryptography
(cherry picked from commit ac61f09203)
2017-04-13 11:27:30 -07:00
bdf46e928f Fallback to old ssl_wrap_socket
(cherry picked from commit 13ac993d25)
2017-04-13 11:27:30 -07:00
9acba3fa68 Update install deps for SNI tests
(cherry picked from commit b4b76bab14)
2017-04-13 11:27:30 -07:00
71e8c841ce Use PyOpenSSLContext instead of deprecated wrap_ssl_context from urllib3.contrib.pyopenssl. Fixes #18528
(cherry picked from commit 33f7a27cba)
2017-04-13 11:27:30 -07:00
701a47c850 Ignores ControlPersist broken pipe errors. Fixes #16731
Ansible will now automatically retry a connection if SSH returns an error:

mux_client_hello_exchange: write packet: Broken pipe

This is probably a bug in SSH, but because it's safe to retry this
connection there is no need for Ansible to fail because of it.

(cherry picked from commit 9f0be5a556)
2017-04-13 11:27:30 -07:00
ffde769567 ini_file 'create' parameter default value should be True
Updated create default value to True to match documentation (and common sense).
2017-04-13 11:08:35 -04:00
3b5a758525 centralize ansible_managed and other template vars
now template lookup supports these again.

(cherry picked from commit 5b7e8a7bd6)
2017-04-13 11:05:19 -04:00
4b10f3c13c removed extra 'changed' from debug output
(cherry picked from commit f7566ef1f1)
2017-04-13 11:03:21 -04:00
e1c1c19a9b added test emulating #23180 use case
(cherry picked from commit 8382ed7200)
2017-04-13 11:01:34 -04:00
690a793aae fix environment validation, make setup exception
removed bare vars
now environment inheritance correclty prepends
this allows more local to override more general

fixes #23180

(cherry picked from commit df5895e585)
2017-04-13 11:01:34 -04:00
d392c493b9 removed unused and erroring cmp import 2017-04-13 11:01:34 -04:00
6799b21124 correctly get all hosts in 'all'
(cherry picked from commit 0d5d5f2bf6)
2017-04-13 11:01:34 -04:00
cac25fa7b0 BUGFIX : using yaml hosts inventory, hosts in groups weren't added to the group 'all'
(cherry picked from commit 283a88444f)
2017-04-13 11:01:34 -04:00
74b6dd7799 Include .yamllint in manifest so yamllint works.
(cherry picked from commit 38eed2dab0)
2017-04-12 11:00:35 -07:00
6b74dca0ff Add .coveragerc to the tarball so unittests will run from the tarball
(cherry picked from commit 0d2d17ade5)
2017-04-12 08:08:30 -07:00
d56ba0945d New release v2.3.0.0-1 2017-04-12 08:56:33 -05:00
8f6c284ccf Updating CHANGELOG with release date for 2.3 2017-04-12 08:52:52 -05:00
9818ca366d New release v2.3.0.0-0.6.rc6 2017-04-10 10:13:54 -05:00
856edfe80c Revert "pacman: Fix package matching pattern in upgraded package list (#23433)"
Not a critical blocker so we'll push this to 2.3.1 instead of trying to
get it into 2.3.0 (Just too late in the development cycle to push it out
now).

This reverts commit 9a850db605.
2017-04-10 07:04:17 -07:00
9a850db605 pacman: Fix package matching pattern in upgraded package list (#23433) 2017-04-09 11:21:55 +02:00
bb5202fa7e Redo #23418 (#23425)
* Check for provider values inside check_args of respective network code

* Partial revert of b9ee5aa

The no_log change is okay, but take out the action result munging

(cherry picked from commit 86c714548f)
2017-04-08 10:56:27 -04:00
d72dbffa23 New release v2.3.0.0-0.5.rc5 2017-04-07 16:13:18 -05:00
b9ee5aae81 Fixes #23388 Network provider masks too much (#23418) (#23424)
* Fixes #23388 Network provider masks too much

* Fix trailing whitespace
2017-04-07 14:39:09 -06:00
0fe53eda86 New release v2.3.0.0-0.4.rc4 2017-04-06 14:10:42 -05:00
c02b89759c fix incorrect parsing of xfs_info
when device name ends with 'data' line matches in :
-                if 'data ' in line:

closes #23352

(cherry picked from commit 3c75808c5c)
2017-04-06 11:11:34 -07:00
69e5f2ae67 fixes return data structure (#22830)
The return was being re-written instead of updated so warnings were
lost.  This patch now updates the result instead of replacing it.
(cherry picked from commit d6787632c9)
2017-04-06 14:01:58 -04:00
3cd89bd8a4 Fix #23360 junos_config set format issue (#23365) (#23373)
(cherry picked from commit 990ba90380)
2017-04-06 23:14:50 +05:30
4f56567963 Unhardcode the port and protocol on eos EAPI (#23350)
We were hard-coding the protocol, port and validate_certs on
eos EAPI via the action plugin.
Put defaults on the eos_argument_spec and pull those values from it.
(cherry picked from commit 3537b24742)
2017-04-06 19:19:22 +02:00
292ee29275 Fixes loginBanner plucking over eapi transport when loginBanner isn't set. (#23368) 2017-04-06 11:02:01 -06:00
ede49d9115 Fix #22880 junos_config update issue (#23333)
For update parameter add 'override' as acceptable value.
'override' name is in sync with junos naming convention.
(cherry picked from commit 0cd50f0706)
2017-04-06 13:00:55 -04:00
e2a1ea09dc Attempt to clear up nxos_mtu tests and documentation (#23361)
nxos_system wasn't added until 2.3, so nxos_mtu should have been deprecated
then.
(cherry picked from commit 98c23a3342)
2017-04-06 12:27:06 -04:00
1a45463725 Nsupdate idempotency fix
(cherry picked from commit 637e9942ff)
2017-04-06 09:20:45 -07:00
c6e9039b23 fix iosxr commands to encode json (#23346) (#23355)
the command dict in the iosxr module_utils wasn't encoding the request
to json.  this patch will fix that problem
(cherry picked from commit f0008248d4)
2017-04-06 16:18:58 +01:00
0da250c9f1 More network_debug_troubleshooting.html (#23335) (#23341)
More "unable to open shell" -> network_debug_troubleshooting.html
(cherry picked from commit 13dc02d49d)
2017-04-06 12:44:24 +01:00
84d09cdf32 ecs_taskdefinition module : Convert environment variables to string (#23297) (#23337)
Before modification, it fails unless it is a string type
(cherry picked from commit dff35bc205)
2017-04-06 11:19:42 +01:00
d6a8f10a70 Pass CSRF token along with Jenkins POST requests (#23250) (#23330)
(cherry picked from commit 4540853a50)
2017-04-06 10:15:20 +01:00
c3e3580baf 'unable to open shell' -> direct to web help (#23267) (#23331)
* 'unable to open shell' -> direct to web help

The "unable to open shell" error is returned for a number of different,
direct people to online docs (we we can update out of band of releases)
to guide them though the various solutions.

* fix pep8 errors

(cherry picked from commit 529df8640b)
2017-04-06 10:14:42 +01:00
beb40dd10e Cleanse CLIXML from win_shell stderr (#23329)
prunes all but Error stream values

cherry-picked from b71b157fb3 (plus fixed merge conflicts due to devel cleanup)
2017-04-06 01:45:04 -07:00
efb717fe73 improve become_method: runas error handling (#23328)
Prescriptive errors for username/password issues and NTLM/Kerb auth failures, cleans up exception noise.
(cherry picked from commit 8d291f91ee)
2017-04-06 01:35:31 -07:00
bfb50df9a7 Check text key exists on eos_banner absent case (#23319)
This can fail if we don't check the key exists.
(cherry picked from commit b9b4e68206)
2017-04-05 21:08:03 +02:00
5e09ddb6a4 Fix eapi basic-login asserts (#23318)
The asserts where not checking the commands sent to the device
(cherry picked from commit 4571ff0b52)
2017-04-05 20:39:59 +02:00
3ba95b8ef7 Fix junos pylint issues (#23292)
* Fix junos rollback id validate issue (#23283)

(cherry picked from commit 0b8ca98c48)

* Fix various junos errors (#23278)

(cherry picked from commit e8538213fa)
2017-04-05 23:39:16 +05:30
55583c71ff Fixes #23308 ios_banner: KeyError: 'text' on state: absen (#23313) (#23314) 2017-04-05 12:06:07 -06:00
ebda0bebfc Fix basic-login eapi tests for eos_banner (#23304)
We should be passing the provider dict, not the transport.
(cherry picked from commit d268471739)
2017-04-05 20:02:37 +02:00
6969bef70a Fix asserts on ios_banner tests (#23315)
The contain assert was broken.
(cherry picked from commit cf30f0f27d)
2017-04-05 20:02:24 +02:00
7941f1ede7 enable ios_facts tests again (#23310) (#23312)
(cherry picked from commit f22702eee2)
2017-04-05 17:58:44 +01:00
fc09da86e1 eapi & nxapi: Document validate_certs (#23305) (#23307)
* Document validate_certs for eapu & nxapi

* formatting

(cherry picked from commit 485affeb12)
2017-04-05 16:51:59 +01:00
50500332ae Fix nxos_facts for nxapi transport (#23302)
* Partial revert of 2e476e64cd

This broke handling of nxos_facts over nxapi

* Fix nxos_facts tests not run in isolation

(cherry picked from commit d890167575)
2017-04-05 11:48:28 -04:00
ac9bb4df8e Fixes pylint errors (#23279) (#23295)
Reported by gundalow, this fixes pylint errors in F5 modules
(cherry picked from commit 780b2f2c84)
2017-04-05 14:49:01 +01:00
dbe83cc099 fortios_ipv4_policy.py state=absent Fix 23239 (#23242) (#23290)
* Resolve #23239:
  - path is missing when state=absent
  - update doc for unclear policy ID
  - required params based on state

* Fix pep8 + doc

* Fix doc

* Another doc problem...

* doc

* Update doc fot policy ID

* Fix doc string

* fix required in doc

* fix required in doc Required when I(state=present).

(cherry picked from commit f74a9abbda)
2017-04-05 13:56:40 +01:00
dc99a7dac2 Only insert notified host if it's not already notified for certain cases
Fixes #18178

(cherry picked from commit a567c5de65)
2017-04-04 16:39:45 -05:00
ac1cb3257f Update the metadata of the proxysql modules to 1.0 final format
(cherry picked from commit 572e9a8959)
2017-04-04 14:20:42 -07:00
5e3979c25d Add proxysql modules to changelog 2017-04-04 13:50:02 -07:00
d6fb616e54 Adding support for ProxySQL (#19872)
* Adding support for ProxySQL
(cherry picked from commit 21ab4343e3)
2017-04-04 13:47:58 -07:00
bf805d1453 junos_config: Remove reliance on ability to output configuration in set format (#23225)
* Remove reliance on ability to output configuration in `set` format
* Support multiple warnings per rpc-reply
2017-04-04 15:01:36 -04:00
ec0cbfac4b win_chocolatey: Perform exact presence check (#23098)
The current implementation matches libreoffice-oldstable when testing for libreoffice.
So uninstalling libreoffice fails when libreoffice-oldstable is installed.

```
PS C:\WINDOWS\system32> choco list --local-only libreoffice
Chocolatey v0.10.3
libreoffice-oldstable 5.2.6
1 packages installed.
PS C:\WINDOWS\system32> choco list --local-only --exact libreoffice
Chocolatey v0.10.3
0 packages installed.
```

The solution is easy, just add `--exact`.
(cherry picked from commit 0715430829)
2017-04-04 09:40:06 -07:00
f0e19d8334 Pull filesystems from dict in case is not string on eos_facts (#23254)
Apparently in some devices the filesystems gathering command can return
a dict containing a 'messages' key with the filesystems, instead of a
plain string.

Fixes #23217
2017-04-04 16:04:45 +02:00
08be1ae562 Fix integration aliases.
(cherry picked from commit b7cc4616b1)
2017-04-03 17:50:18 -07:00
179f6c8f23 Fix deploy_helper join exception on no release.
(cherry picked from commit 64458bc9a1)
2017-04-03 16:55:31 -07:00
d1124359f5 Remove dupe supports_session method from eos module_utils (#23240)
Fixes #23237
2017-04-04 00:47:39 +02:00
5545532328 mark runas become method experimental (#23235)
Due to the number of "real world" caveats in the current runas become method, it was agreed that we'd warn that it's experimental on use. A potential future version based on LogonUser/CreateProcessAsUser will have very different requirements and limitations.
(cherry picked from commit d85f4a443f)
2017-04-03 13:47:30 -07:00
45b56cb081 win_find fix up age parameter (#23195)
(cherry picked from commit 3e1a16c574)
2017-04-03 13:24:33 -07:00
401f6d68d6 win_stat change return islink to islnk to match stat (#23196)
(cherry picked from commit 4d1b97d1ae)
2017-04-03 11:39:33 -07:00
f0cbd32dd1 Update fortios_config.py (#23230) (#23232)
(cherry picked from commit 5918bebd6e)
2017-04-03 19:25:01 +01:00
0dc890fbac Fixes ignoreerrors not working with sysctl_set
(cherry picked from commit 7358bf88e2)
2017-04-03 06:37:42 -07:00
f15e1f25ae New release v2.3.0.0-0.3.rc3 2017-03-31 13:50:42 -05:00
f8cef96c2c Updated the Regex for promt matching (#23186) (#23188)
(cherry picked from commit 632270b913)
2017-03-31 18:38:57 +01:00
1b2411c6d2 Fixes generators and other misc fixes (#22887) (#23172)
fixed itertools.imap busting several things that used to be lists,
profiles not being set correctly, upon create, when it was a separate
method, allowed port having the wrong lowest port (zero is allowed),
empty port value should just be interpreted as None.
(cherry picked from commit 2a576a1999)
2017-03-31 10:39:59 +01:00
131729726f synchronize: Exclude ssh_args from quoting
Makes it possible again to pass more than one argument via ssh_args to the synchronize module.

(cherry picked from commit 3efb11e225)
2017-03-30 19:41:18 -07:00
5744abfe4e Fix eos_banner cli basic_motd integration test (#23158)
A task was lacking the provider variable, causing the test to fail.

Fixes #23130
2017-03-31 00:28:37 +02:00
07ea6a6adf Include '/' & '.' when password_hash generates a new salt
The password_hash filter will generate a salt value if none is supplied.
The character set used by Ansible

(upper & lowercase letters, digits)

did not match that used by libc crypt

(upper & lowercase letters, digits, full stop, forward slash).

This resulted in a slightly smaller key space, and hence hashes would be
slightly easier to attack (e.g. by dictionary, brute force).

(cherry picked from commit f5aa9df1fd)
2017-03-30 12:47:34 -07:00
1ba7e6b6f6 Ansible 2.3 feature support for dellos6. (#23084) (#23147)
* Ansible 2.3 feature support for dellos6.

- With the new Ansible 2.3 infra changes, the dellos modules doesn't work
  (the new infra changes are not backward compatible), so added the below
  changes support it.
- Added the new terminal plugin for DellOS6
- Added the new action plugin for DellOS6
- Modified the modules to work with the new infra.
- with that it adds support for DellOS6 Persistent Connection support.

* Remove pep8 confirming files from dellos6.py and dellos6_config legacy-files

(cherry picked from commit a0344acd78)
2017-03-30 17:42:11 +01:00
7afc9ac899 fixes error parsing lldp neighbors when running nxos_facts (#23134)
(cherry picked from commit 2e476e64cd)
2017-03-30 11:31:53 -04:00
1b188c1fb9 updates log messages in ansible-connection (#23076) (#23125)
(cherry picked from commit 53c52cf65f)
2017-03-30 13:24:47 +01:00
af83d4d4df Fix ios_config return on python 2.4 (#23094) 2017-03-30 00:22:33 +02:00
18dedd985a Do not re.search show configuration stdout if empty (#23087)
If the banner is not set, the stdout of 'show configuration | begin banner <banner>'
returns empty string thus the re.search raises an exception.

Fixes #22216
2017-03-29 23:02:46 +02:00
664b27aaf0 Introspect flag to use on 'show run' when using defaults in ios_config (#22903)
When the ios_config module has 'defaults' param it runs in the device the command
'show running-config all' but 'all' may not be available in older devices.
This change makes introspection by using the help command and run 'full' in case
'all' is not available.

Fixes #22747
2017-03-29 22:53:14 +02:00
3859551eb3 Fall-back to show configuration on old IOSXR devices (#22900)
In old IOSXR versions, 'show commit changes diff' does not work.
Fall-back to 'show configuration' if that command fails so execution
can move forward.

Fixes #22235
2017-03-29 22:52:00 +02:00
53934702ce restores pre 2.3 behavior with respects to keys (#23083)
This removes the requirement to configure look_for_keys=False and
restores the behavior to disable key lookup if no key was provided.
(cherry picked from commit 88ce6fd273)
2017-03-29 15:13:33 -04:00
4a9c5d9574 Split on newlines when searching for become prompt
The fix for leading junk in sudo output: fee6e29 causes problems with
ssh + sudo.  On the initial connection using ControlPersist, the output
that we scan for the prompt contains both the command we're sending to
configure the prompt and the prompt itself.  The code in fee6e29 ends up
sending the password when it sees the line configuring the prompt which
is too early.

Switch to a version that splits on lines and then checks whether the
first or last line starts with the prompt to decide if it's time to send
the password.

Fixes #23054
References #20858

(cherry picked from commit 6f77498700)
2017-03-29 12:11:57 -07:00
c528d8b17d changed parameter name from forest_root_dns_domain to dns_domain_name (to match documentation and other win_domain* modules) and fix example which has win_domain_controller instead of win_domain for module name. (#23081)
(cherry picked from commit 4eba248a8e)
2017-03-29 11:35:23 -07:00
c8dc993fb4 correct examples to match correct _password module parameter names (#23067)
(cherry picked from commit a3e2280e62)
2017-03-29 11:32:59 -07:00
7c84593eb0 Fix #22126 (#22128)
(cherry picked from commit a5da638d34)
2017-03-29 11:30:58 -07:00
657fd1dfd1 Added Virtuozzo distribution support
Virtuozzo Linux is based on CentOS sources. Thus OS family
should be recognized as 'RedHat'.

Signed-off-by: Pavel Glushchak <pglushchak@virtuozzo.com>
(cherry picked from commit 097173c6f5)
2017-03-29 08:47:48 -07:00
4465171e89 Fixed issue #22996 and issue #22955. 2017-03-29 08:29:10 -07:00
9ee2065477 paramiko_ssh: fix crash upon pass prompt in py3
The pass prompt expects an answer and compares a `str` to a binary buffer, thus crashing.

It's an obvious fix to help transitioning towards Python3 and hopes it does not need a specific test.
(cherry picked from commit bc44175d8d)
2017-03-29 07:47:48 -07:00
ca497b43e4 Update requirements for seboolean module (fixes #23028)
(cherry picked from commit b52dbddc17)
2017-03-29 07:25:27 -07:00
bb0b90783c Fix for tests run with no .ssh user dir
When building in automated build systems, there are sometimes cases
where the user doing the building does not have a .ssh directory.  In
this case, we need to mock out some os.path functions so that the
add_host_key() function we're testing won't complain or try to create
one.

(cherry picked from commit ade3fc2893)
2017-03-28 19:28:15 -07:00
d9a6714cb9 win_chocolatey: Fix state=latest when absent (#23041)
When using state=latest with the package not being installled, Ansible complains that the package is not installed and fails the task.
Whereas the expected behaviour is to install the package when it is missing.

This PR fixes this behaviour.
(cherry picked from commit 521fa9b458)
2017-03-28 17:50:17 -07:00
9785d5b2fb Fix synchronize tests for the updated quoting change between action and module
(cherry picked from commit b0d75a0ecb)
2017-03-28 14:15:42 -07:00
da10768b10 Fix a couple issues in synchronize with docker (#23047)
* Fix a couple issues in synchronize with docker

* Make the rsync_opts parse as a list using the same criteria as
  module_utils argumentspec parsing
* Do not quote arguments in the action plugin.  The module will quote as
  it knows whether it will invoke rsync with a shell or via exec.

Fixes #23046
(cherry picked from commit d3a1aea7c5)
2017-03-28 11:39:18 -07:00
48f6af4907 updates sample ansible.cfg (#23045) (#23050)
* adds host_key_auto_add to paramiko section
* adds look_for_keys to paramiko section
* adds terminal_plugins to defaults section
* adds persistent_connection section and key/value enteries
(cherry picked from commit ccfa464464)
2017-03-28 19:08:32 +01:00
0c0d949c47 minor updates to network connection plugins (#23043)
* removes unused log() function in network_cli
* adds method comments to terminal plugin base
(cherry picked from commit 768cb437ab)
2017-03-28 13:00:09 -04:00
7c9c8396d1 cron: don't force changed=True when old crontab was empty
The cron module forces changed=True when there was no real change,
but the original crontab did not contain a final newline, which is
mandatory.

When the user has no crontab or the user does not exist at all,
crontab -l exits with 1 and the cron module correctly interprets
this as "no crontab" and stores the old crontab as "".

However this triggers changed=True, even if we're not going to
change anything, e.g. when removing a crontab entry from a user
who has no crontabs at all.

Let's special-case the fact that the old crontab is empty and not
force changed=True in that case.

(cherry picked from commit 61579aebb2)
2017-03-28 07:45:45 -07:00
f001646f2c New release v2.3.0.0-0.2.rc2 2017-03-27 16:25:02 -05:00
f3c839b35f Ansible 2.3 feature support for dellos9 and dellos10 (#23010) 2017-03-27 20:32:18 +01:00
80c4a02c5f Network module docs 2.3 (#22454) (#22995)
Network module docs 2.3 (#22454)
Cherry pick of https://github.com/ansible/ansible/pull/22454 into stable-2.3

* Tidy up docs for network 2.3 modules

* Use suboptions

* Correct indentation

* more tidyup

* bulk updates

* more tidyup

* Bulk changes

* nxos_mtu is dead

* revert

* NXOS_mtu is dead, also better layout

* rebase

* rebase

(cherry picked from commit f82239e1f7)

* metadata_version - merge error
2017-03-27 13:18:36 +01:00
01abc097ee removes unused code in eos action plugin (#22986)
(cherry picked from commit ab4b8cb104)
2017-03-27 00:51:57 -04:00
63812b0a2c roll up of fixes for sros modules (#22972)
* fixes action handlers for sros
* fixes sros_config module execution to use AnsibleModule
* fixes sros_command module to use socket connection
* adds sros to constants

(cherry picked from commit 3169cbd493)
2017-03-25 10:40:23 -04:00
ba49443532 fixes junos_package module to use junos_pyez (#22973)
This allows junos_package to use junos_pyez directly instead of the
persistent connection.  This is a workaround fix for 2.3
(cherry picked from commit 33624fe96f)
2017-03-25 10:22:59 -04:00
66481d3d2f Fixing module behavior when route_target_both is used (#20076)
(cherry picked from commit 9b2bdf2df6)
2017-03-25 08:02:58 -04:00
d1ed72ad37 fixes issue where nxos module will fail due to KeyError (#22966)
Updates nxos action handler to handle deleting provider key if exists or
silently continuing if a  KeyError is raised.
(cherry picked from commit 6a414371a1)
2017-03-25 07:45:59 -04:00
75d19442e3 fixes log message in junos action handler (#22965)
(cherry picked from commit e93cdecef1)
2017-03-25 00:39:29 -04:00
f0bd79d41b fixes ansible-connection working directory (#22964)
When ansible-connection forks the process, it changed the working
directory to /.  This patch will prevent ansible-connection from
changing the working directory in the forked process.
(cherry picked from commit 77ce83fe22)
2017-03-25 00:36:00 -04:00
15695ea3bc Associate systemd module with service test. (#22847)
(cherry picked from commit 318445fe19)
2017-03-24 13:30:12 -07:00
58f002d8f0 Handle the case where HTTPError.info() returns an object that aren't (#22894)
dict-like enough (can't be used with **).

This should give a better error message for #22872
(cherry picked from commit 29f623571e)
2017-03-24 12:25:45 -07:00
c16622b072 synchronize: Convert cmd to list and fix handling of the copy_links argument (#22573)
* synchronize: Convert cmd to list and fix handling of the copy_links argument

Converting cmd from str to list stops the pain of argument quoting/escaping.

* synchronize: Update imports according to #pullrequestreview-28758614

(cherry picked from commit f7c9f44aab)
2017-03-24 09:26:11 -07:00
422baea136 base64 functions must be given byte strings
The base64 stdlib functions require byte strings.  So we have to
transform the strings into bytes before handing to the stdlib and then
transform them back into text before handing back to ansible.

Fixes #22873

(cherry picked from commit 589e217278)
2017-03-24 09:23:25 -07:00
631eaccc64 force Windows to always use preamble-free UTF8 input encoding (#22934)
* fixes #15770
* When running under the UTF-8 codepage, Powershell subprocesses will fail (eg, Start-Job, others) if the input encoding is using the default BOM preamble. This fix forces it to use no preamble in leaf_exec and win_shell, and includes tests to verify that Start-Job works.
(cherry picked from commit e084e8809e)
2017-03-24 00:03:16 -07:00
43310bb7b7 Fixes#21557-Handled dellos9_facts crash with IPV6 configs (#21652)
(cherry picked from commit cd662efd2b)
2017-03-23 23:07:58 -04:00
7f1a7a4372 win_firewall_rule doesn't fail when profile is "any" or remoteip is IPv4 and the task runs more than once. (#22555)
* Fixed #22554

* Wrote tests for win_firewall_rule module

* Fixed #22786

* Fixed review comments

* Fixed #22799

* Added test when RemoteIP containt a netmask

* Revert comment

(cherry picked from commit f4b34a4c3b)
2017-03-23 20:02:16 -07:00
2cfe8b95de fixes a number of issues with nxos_facts (#22923)
* updates command runs to return warning if command fails
* fixes variable issues from recent refactoring
* removes provider from return of module
(cherry picked from commit 866f67e213)
2017-03-23 22:58:57 -04:00
30734d178c Fixing nxos_vrf_interface when interface name is not full (#22769)
(cherry picked from commit d7d76f3aaf)
2017-03-23 22:58:38 -04:00
8b9ccc15f7 win_scheduled_tasks: Improve example test framework (#22833)
Updated as discussed in previous Test Working Group.
(cherry picked from commit ef36d7de68)
2017-03-23 19:44:02 -07:00
9154981684 fix Windows env handling
* fixes #22441
* fixes #22655
* moves all env handling into the exec wrapper; this should work for everything but raw, which is consistent with non-Windows.

(cherry picked from commit cc68212612)
2017-03-23 17:48:55 -07:00
6201f9eb14 fixes issue when host is defined in provider for junos (#22918)
The junos action handler was not honoring the host value in the provider
argument.  This patch will now use the provider host entry if it exists
and falls back to the inventory hostname
(cherry picked from commit cda3e001c6)
2017-03-23 19:05:29 -04:00
5eae522d94 win_reg_stat change the module parameters for standardisation (#22732)
(cherry picked from commit f1ab879bb6)
2017-03-23 15:16:11 -07:00
4d3e5a14e6 win_share: tweaks after the caching mode changes (#22763)
* win_share: tweaks after the caching mode changes

* Re-added the Unknown option back in

(cherry picked from commit 89b78cb5e8)
2017-03-23 15:10:03 -07:00
0edc943c68 Make yum's state=list obey disablerepo and enablerepo
Fixes #22876

(cherry picked from commit d0712b1ec7)
2017-03-23 12:12:51 -07:00
2551b53a9a win_iis_webapppool: Use Get-AnsibleParam to retrieve parameter
- Fixes #22805

(cherry picked from commit 78de05e58d)
2017-03-23 07:43:09 -07:00
7d79105cf4 Overhaul ansible-test import analysis. (#22888)
- Add support for module_utils packages for better organization.
- Add support for "virtual" module_utils packages such as `six`.

(cherry picked from commit 4fdeade389)
2017-03-22 23:02:44 -07:00
aafb5bb168 synchronize: explicitly set the executable for localhost
Otherwise the executable for the destination is also used on the local
machine and this might not exist.

Fixes: #22867
(cherry picked from commit 7a00f28804)
2017-03-22 21:28:17 -07:00
223fc34ab9 Import camel_dict_to_snake_dict method to fix error when executing get_nat_gateways() method 2017-03-22 16:25:48 -07:00
dc61ea999a Missing purge_subnets parameter on function call
purge_subnets|routes were introduced recently.
ensure_subnet_associations now takes purge_subnets as a parameter.  A
call to this function was missed when introducing this feature.  With
out, results in a "got 5 expected 6" error.

(cherry picked from commit cd24bbbc9c)
2017-03-22 16:24:06 -07:00
2152bd8da2 fix for loosing ungrouped hosts in ini
fixes #22861

(cherry picked from commit 052be86605)
2017-03-22 12:48:17 -04:00
4e6cdf8989 better handling of parsed
updated tests to match new result output

(cherry picked from commit 5e98be2e62)
2017-03-22 12:03:34 -04:00
4f8a2d3806 prevent failure for meta: reset_connection
now plugins that don't explicitly support it give a warning.

(cherry picked from commit 9ad62a48ab)
2017-03-22 11:00:45 -04:00
3db0bbe76c Fallback to show-run on ios_banner for devices where show banner does not work (#22793)
On switches 'show banner' command doesn't work, fallback to show run|begin banner
and extract the banner text in case that fails.
2017-03-22 11:07:49 +01:00
9bafde67a8 Fix stderr false return value (#22845)
* ensure exit_json does not fail from stderr=False

- do a little bit of safety-checking in exit_json to not try to .splitlines() on a boolean
- remove the stderr=boolean from uri.py, this is the only spot that uses it (at least so obviously)
- add unit tests that call exit_json. These are useless because the stderr parsing is in _execute_module and is difficult to mock; deleting these tests after the commit.

* remove added unit tests per prev commit

exit_json doesn't do the param parsing, that is buried deep inside _execute_module.

(cherry picked from commit 887456ab8e)
2017-03-21 18:11:08 -04:00
566ef91e26 fixed passwordstore lookup examples
plugin was renamed before acceptance, but examples kept original name
fixes #22735

(cherry picked from commit 6a2985dd3c)
2017-03-21 15:42:09 -04:00
8f6fd60fe2 fixes exception raised from ansible-connection logging (#22836)
updates ansible-connection logging functions to use display instead of
log.
(cherry picked from commit 4a8f2dde20)
2017-03-21 12:16:07 -04:00
116ba9196d Fix get_s3_connection (fixes #22317) (#22318) (#22831)
* Fix get_s3_connection (fixes #22317)

Override aws_connect_kwargs rather than prepending to them. Should fix an issue in which `calling_format` is set twice in the kwargs passed to `boto.connect_s3` or `S3Connection` if a bucket name contains a `.`

* Revert "Fix get_s3_connection (fixes #22317)"

This reverts commit 7f61b8bebd.

* implements alternative way of fixing issue with aws_connect_kwargs for rgw and fakes3 (fixes 22317)

* add comment to explain why the keys are being removed from aws_connect_kwargs

* remove trailing whitespace on comment line
2017-03-21 10:09:24 -04:00
89a2d1d6ad Add ios_banner module (#22687)
With unit and integration tests.
2017-03-21 12:29:45 +01:00
e4f052c1a9 replaces logging with display for network connection plugins (#22819)
* updates network_cli and netconf connection plugins
* updates ansible-connection
(cherry picked from commit e20ed8bc0c)
2017-03-20 23:08:49 -04:00
c093d14697 implements python logging for network connection plugin (#22817)
* enables logging for network_cli and paramiko
* enables logging for ansible-connection
* enabled logging for netconf connection
(cherry picked from commit ed7cace425)
2017-03-20 22:32:25 -04:00
acd9303b7b cherry pick changes to modules and docs for 2.3 rc (#22815)
* Dropped openwrt module from curated to community (#22657)

* changed supported_by from curated to community (#22656)

* Changed supported_by from curated to community (#22654)

* Updates to docs for metadata. (#22667)

* Updates to docs for metadata.

* Update developing_modules_documenting.rst
2017-03-20 19:21:26 -07:00
0c2c19edb4 Fix metadata handling for shell command. (#22801)
(cherry picked from commit 042e387f27)
2017-03-20 15:32:35 -07:00
3f8e8a3390 Add missing needs/root alias to file test. (#22800)
(cherry picked from commit 3585d3d368)
2017-03-20 14:14:16 -07:00
115d91069c CLI: unfrack --private-key path
Relative paths can break the synchronize plugin when the playbook
is not in the current working directory.

Fixes: ansible/ansible#22695
(cherry picked from commit ed15ba1b3c)
2017-03-20 11:41:00 -07:00
b73a1be03a Disable failing MySQL tests on FreeBSD. (#22798)
(cherry picked from commit b7c80dbb7e)
2017-03-20 09:54:16 -07:00
169b5dfaec added 'existing' back
fixes #22785

(cherry picked from commit 07d9366ed8)
2017-03-20 12:29:05 -04:00
8a563047e6 Fixing nxos_facts (#22783) 2017-03-20 06:54:15 -07:00
1799376ab7 cloudstack: fix load balancer idempotency if no zone given
get_zone() is special, as it always returns a zone (default zone) even
if no zone param is given. This makes sense for many use cases.

(cherry picked from commit d1e8ef79ea)
2017-03-19 10:09:07 +01:00
5ae1967aea Fix ansible-test base branch handling on merge. (#22759)
(cherry picked from commit 991bf0a1c3)
2017-03-17 23:34:27 -07:00
0e864fd81b Fix uri options test to work again.
(cherry picked from commit 93d9b04f1d)
2017-03-17 22:31:22 -07:00
0ca10bf3d5 Fix ansible-test base branch usage on Shippable.
(cherry picked from commit 47887a2edd)
2017-03-17 17:36:16 -07:00
7ba4f43be4 Add Missing default param for caching_mode (#22753)
Add Missing default param for caching_mode and Usage of new Ansible-Param Commant with default Value
(cherry picked from commit 634d6894e3)
2017-03-17 14:46:32 -07:00
c935d2f038 Do not run win_chocolatey in CI tests.
The test is failing repeatedly.

(cherry picked from commit 011b324638)
2017-03-17 09:01:31 -07:00
923c9ef17c Windows CHANGELOG updates
(cherry picked from commit e3dfa62abc)
2017-03-16 15:02:36 -07:00
8857a80109 Cast syslogport value from getenv as int (#22664)
SysLogHandler requires an int for port, but getenv produces a string.
Cast return from getenv as int to overcome this mismatch.
(cherry picked from commit 5334814396)
2017-03-16 10:39:51 -07:00
dc8ad50eaa Fix ansible-test PR diff handling.
Permits use of PRs on branches other than devel.

(cherry picked from commit f7c83ccdc0)
2017-03-16 10:37:10 -07:00
3f276c5def readded !vault-encrypted for backwards compat
even though this was never documented someone might be using it

(cherry picked from commit 6a4039e169)
2017-03-16 13:24:43 -04:00
ac92218e38 updated release 2017-03-16 13:24:43 -04:00
ec05cd6336 better 'role detection' for dwim (#22513)
* better 'role detection' for dwim

possible fix for #21735

* fixed unmatched paren

* pep does not like the denting

(cherry picked from commit 517cdbe22a)
2017-03-16 13:24:43 -04:00
e9439c54f6 cloud: docker: Fixes #22638 load image to memory when archive_path provided (#22642)
(cherry picked from commit dba8edf735)
2017-03-16 10:07:30 -07:00
c72ac9b230 Add test verification to ansible-test. (#22636)
* Add unified git diff parser.
* Add metadata and diff handling.
* Add test confidence/verification to bot output.

(cherry picked from commit 869449e288)
2017-03-15 14:48:53 -07:00
e4494f85b6 New release v2.3.0.0-0.1.rc1 2017-03-15 14:13:52 -05:00
8283fd51c3 corrected host group ancestor management
(cherry picked from commit 3d5bc49a06)
2017-03-15 14:58:53 -04:00
eccfcf020c simplified pattern matching, fixed ungrouped (#22523)
* simplified pattern matching, fixed ungrouped

ungrouped was ignored for patterns, now it is usable again

* even simpler

(cherry picked from commit 273786d0bd)
2017-03-15 14:58:53 -04:00
c9ea993c88 Verify SHA in Shippable change detection.
(cherry picked from commit 5e9a2b8528)
2017-03-15 11:32:41 -07:00
d86e2e2aa9 Updating packaging release version yaml 2017-03-15 11:37:59 -05:00
5624 changed files with 111215 additions and 434917 deletions

View File

@ -20,6 +20,5 @@ data_file = test/results/coverage/coverage
omit =
*/python*/dist-packages/*
*/python*/site-packages/*
*/python*/distutils/*
*/pyshared/*
*/python*/distutils
*/pytest

3
.gitattributes vendored
View File

@ -1,4 +1 @@
CHANGELOG.md merge=union
.github/ export-ignore
hacking/ export-ignore
ticket-stubs/ export-ignore

1117
.github/BOTMETA.yml vendored

File diff suppressed because it is too large Load Diff

View File

@ -13,26 +13,21 @@ Also test if the latest release, and master branch are affected too.
<!--- Name of the module/plugin/task/feature -->
##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
```
##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
managing, or say “N/A” for anything that is not platform-specific.
-->
##### SUMMARY

View File

@ -18,7 +18,7 @@ the change does.
<!--- Name of the module/plugin/module/task -->
##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
```

48
.gitignore vendored
View File

@ -20,37 +20,30 @@ rpm-build
# Mac OS X stuff...
.DS_Store
# manpage build stuff...
docs/man/man1/ansible*.1
docs/man/man1/ansible*.1.asciidoc.in
docs/man/man1/ansible.1
docs/man/man1/ansible-doc.1
docs/man/man1/ansible-galaxy.1
docs/man/man1/ansible-playbook.1
docs/man/man1/ansible-pull.1
docs/man/man1/ansible-vault.1
docs/man/man3/*
# Sublime stuff
*.sublime-project
*.sublime-workspace
# docsite stuff...
docs/api/_build/
docs/api/rst/
docs/docsite/rst/modules_by_category.rst
docs/docsite/rst/playbooks_directives.rst
docs/docsite/rst/list_of_*.rst
docs/docsite/rst/*_module.rst
docs/docsite/*.html
docs/docsite/_build
docs/docsite/_static/*.gif
docs/docsite/_static/*.png
docs/docsite/_static/websupport.js
docs/docsite/htmlout
docs/docsite/searchindex.js
docs/docsite/rst_warnings
docs/docsite/rst/*_module.rst
docs/docsite/rst/ansible.rst
docs/docsite/rst/ansible-*.rst
docs/docsite/rst/community_maintained.rst
docs/docsite/rst/config.rst
docs/docsite/rst/core_maintained.rst
docs/docsite/rst/list_of_*.rst
docs/docsite/rst/modules_by_category.rst
docs/docsite/rst/network_maintained.rst
docs/docsite/rst/plugins_by_category.rst
docs/docsite/rst/partner_maintained.rst
docs/docsite/rst/playbook_keywords.rst
docs/docsite/rst/playbooks_directives.rst
docs/docsite/rst/plugins/*/*.rst
docs/docsite/htmlout
docs/docsite/_build
docs/api/rst/
docs/api/_build/
# deb building stuff...
/debian/
deb-build
@ -74,23 +67,21 @@ Vagrantfile
.vagrant
ansible.egg-info/
/shippable/
/test/integration/cloud-config-*.*
!/test/integration/cloud-config-*.*.template
# Release directory
packaging/release/ansible_release
/.cache/
/test/results/coverage/*=coverage.*
/test/results/coverage/coverage*
/test/results/reports/coverage*.xml
/test/results/reports/coverage*/
/test/results/reports/coverage.xml
/test/results/reports/coverage/
/test/results/bot/*.json
/test/results/junit/*.xml
/test/results/logs/*.log
/test/results/data/*.json
/test/integration/inventory.remote
/test/integration/inventory.networking
/test/integration/inventory.winrm
/test/integration/cloud-config-aws.yml
# old submodule dirs
lib/ansible/modules/core
lib/ansible/modules/extras
# python 'rope' stuff
.ropeproject
# local 'ack' config files
@ -101,4 +92,3 @@ htmlcov/
.coverage
# ansible-test coverage results
test/units/.coverage.*
/test/integration/cloud-config-azure.yml

View File

@ -32,5 +32,5 @@ Will Thames <will@thames.id.au> Will Thames <will.thames@xvt.com.au>
nitzmahone <mdavis@ansible.com> Matt Davis <nitzmahone@users.noreply.github.com>
Dag Wieers <dag@wieers.com> Dag Wieërs <dag@wieers.com>
Dag Wieers <dag@wieers.com> Dag Wieers <dag.wieers@gmail.com>
Rene Moser <mail@renemoser.net> René Moser <mail@renemoser.net>
Rene Moser <mail@renemoser.net> Rene Moser <rene.moser@swisstxt.ch>

View File

@ -1,621 +1,26 @@
Ansible Changes By Release
==========================
<a id="2.5"></a>
<a id="2.3.4"></a>
## 2.5 "TBD" - ACTIVE DEVELOPMENT
## 2.3.4 "Ramble On" - TBD
* Flush stdin when passing the become password. Fixes some cases of timeout on
Python3 with the ssh connection plugin: https://github.com/ansible/ansible/pull/35049
### Major Changes
* Removed the previously deprecated 'accelerate' mode and all associated keywords and code.
### Bugfixes
* Fix setting of environment in a task that uses a loop:
https://github.com/ansible/ansible/issues/32685
* Fix https retrieval with TLSv1.2: https://github.com/ansible/ansible/pull/32053
### Deprecations
#### Deprecated Modules (to be removed in 2.9):
#### Removed Modules (previously deprecated):
* accelerate
### Minor Changes
* added a few new magic vars corresponding to configuration/command line options:
`ansible_diff_mode`, `ansible_inventory_sources`, `ansible_limit`, `ansible_run_tags` , `ansible_forks` and `ansible_skip_tags`
* Updated the bundled copy of the six library to 1.11.0
### New Modules
#### Windows
* win_scheduled_task_stat
<a id="2.4"></a>
## 2.4 "Dancing Days" - 2017/09/18
### Major Changes
* Support for Python-2.4 and Python-2.5 on the managed system's side was dropped. If you need to manage a system that ships with Python-2.4 or Python-2.5, you'll need to install Python-2.6 or better on the managed system or run Ansible-2.3 until you can upgrade the system.
* New import/include keywords to replace the old bare `include` directives. The use of `static: {yes|no}` on such includes is now deprecated.
- Using `import_*` (`import_playbook`, `import_tasks`, `import_role`) directives are static.
- Using `include_*` (`include_tasks`, `include_role`) directives are dynamic.
This is done to avoid collisions and possible security issues as facts come from the remote targets and they might be compromised.
* New `order` play level keyword that allows the user to change the order in which Ansible processes hosts when dispatching tasks.
* Users can now set group merge priority for groups of the same depth (parent child relationship), using the new `ansible_group_priority` variable, when values are the same or don't exist it will fallback to the previous sorting by name'.
* Inventory has been revamped:
- Inventory classes have been split to allow for better management and deduplication
- Logic that each inventory source duplicated is now common and pushed up to reconciliation
- VariableManager has been updated for better interaction with inventory
- Updated CLI with helper method to initialize base objects for plays
- New inventory plugins for creating inventory
- Old inventory formats are still supported via plugins
- Inline host_list is also an inventory plugin, an example alternative `advanced_host_list` is also provided (it supports ranges)
- New configuration option to list enabled plugins and precedence order `[inventory]enable_plugins` in ansible.cfg
- vars_plugins have been reworked, they are now run from Vars manager and API has changed (need docs)
- Loading group_vars/host_vars is now a vars plugin and can be overridden
- It is now possible to specify mulitple inventory sources in the command line (-i /etc/hosts1 -i /opt/hosts2)
- Inventory plugins can use the cache plugin (i.e. virtualbox) and is affected by `meta: refresh_inventory`
- Group variable precedence is now configurable via new 'precedence' option in ansible.cfg (needs docs)
- Improved warnings and error messages across the board
* Configuration has been changed from a hardcoded listing in the constants module to dynamically loaded from yaml definitions
- Also added an ansible-config CLI to allow for listing config options and dumping current config (including origin)
- TODO: build upon this to add many features detailed in ansible-config proposal https://github.com/ansible/proposals/issues/35
* Windows modules now support the use of multiple shared module_utils files in the form of Powershell modules (.psm1), via `#Requires -Module Ansible.ModuleUtils.Whatever.psm1`
* Python module argument_spec now supports custom validation logic by accepting a callable as the `type` argument.
* Windows become_method: runas now works across all authtypes and will auto-elevate under UAC if WinRM user has "Act as part of the operating system" privilege
### Deprecations
* The behaviour when specifying `--tags` (or `--skip-tags`) multiple times on the command line
has changed so that the tags are merged together by default. See the
documentation for how to temporarily use the old behaviour if needed:
https://docs.ansible.com/ansible/intro_configuration.html#merge-multiple-cli-tags
* The `fetch` module's `validate_md5` parameter has been deprecated and will be
removed in 2.8. If you wish to disable post-validation of the downloaded
file, use validate_checksum instead.
* Those using ansible as a library should note that the `ansible.vars.unsafe_proxy`
module is deprecated and slated to go away in 2.8. The functionality has been
moved to `ansible.utils.unsafe_proxy` to avoid a circular import.
* The win_get_url module has the dictionary 'win_get_url' in its results deprecated,
its content is now also available directly in the resulting output, like other modules.
* previouslly deprecated 'hostfile' config settings have been 're-deprecated' as before the code did not warn about deprecated configuration settings, but it does now.
#### Deprecated Modules (to be removed in 2.8):
* azure: use M(azure_rm_virtualmachine) instead
* cs_nic: replaced by cs_instance_nic_secondaryip, also see new module cs_instance_nic for managing nics
* ec2_facts: replaced by ec2_metadata_facts
* ec2_remote_facts: replaced by ec2_instance_facts
* panos_address: use M(panos_object) instead
* panos_nat_policy: use M(panos_nat_rule) instead
* panos_security_policy: use M(panos_security_rule) instead
* panos_service: use M(panos_object) instead
* s3: replaced by aws_s3
* win_msi: use M(win_package) instead
#### Removed Modules (previouslly deprecated):
* eos_template: use eos_config instead
* ios_template: use ios_config instead
* iosxr_template: use iosxr_config instead
* junos_template: use junos_config instead
* nxos_template: use nxos_config instead
* openswitch
* ops_template: use ops_config instead
### Minor Changes
* Now deprecated configuration options issue warnings when set.
* Removed unused and deprecated config option `pattern`
* Updated the copy of six bundled for modules to use from 1.4.1 to 1.10.0
* The `include_dir` var is not a global anymore, as we now allow multiple inventory sources, it is now host dependant.
This means it cannot be used wherever host vars are not permitted, for example in task/handler names.
* Fixed a cornercase with ini inventory vars. Previously, if an inventory var
was a quoted string with hash marks ("#") in it then the parsed string
included the quotes. Now the string will not be quoted. Previously, if the
quoting ended before the string finished and then the hash mark appeared, the
hash mark was included as part of the string. Now it is treated as
a trailing comment:
# Before:
var1="string#comment" ===> var1: "\"string#comment\""
var1="string" #comment ===> var1: "\"string\" #comment"
# After:
var1="string#comment" ===> var1: "string#comment"
var1="string" #comment ===> var1: "string"
The new behaviour mirrors how the variables would appear if there was no hash
mark in the string.
* As of 2.4.0, the fetch module fails if there are errors reading the remote file.
Use `ignore_errors` or `failed_when` in playbooks if you wish to ignore errors.
* Experimentally added pmrun become method.
* Enable the docker connection plugin to use su as a become method
* Add an encoding parameter for the replace module so that it can operate on non-utf-8 files
* By default, Ansible now uses the cryptography module to implement vault instead of the older pycrypto module.
* Changed task state resulting from both `rc` and `failed` fields returned, 'rc' no longer overrides 'failed'. Test plugins have also been updated accordingly.
* The win_unzip module no longer includes dictionary 'win_unzip' in its results,
the content is now directly in the resulting output, like pretty much every other module.
* Rewrite of the copy module so that it handles cornercases with symbolic links
and empty directories. The copy module has a new parameter, `local_follow`
which controls how links on the source system are treated. (The older
parameter, follow is for links on the remote system.)
* Update the handling of symbolic file permissions in file-related mode
parameters to deal with multiple operators. For instance, `mode='u=rw+x-X'` to
set the execute bit on directories, remove it from filea, and set read-write
on both is now supported
* Added better cookie parsing to fetch_url/open_url. Cookies are now in a dictionary named `cookies`
in the fetch_url result. Anything using `open_url` directly can pass a cookie object as a named arg
(`cookies`), and then parse/format the cookies in the result.
* The bundled copy of six in lib/ansible/module_utils/six is now used
unconditionally. The code to fallback on a system six interfered with static
analysis of the code so the cost of using the fallback code became too high.
Distributions which wish to unbundle may do so by replacing the bundled six
in ansible/module_utils/six/__init__.py. Six is tricky to unbundle, however,
so they may want to base their efforts off the code we were using:
* https://github.com/ansible/ansible/blob/2fff690caab6a1c6a81973f704be3fbd0bde2c2f/lib/ansible/module_utils/six/__init__.py
* Update ipaddr Jinja filters to replace existing non RFC compliant ones. Added additional filters for easier use
of handling IP addresses. (PR# 26566)
* datetime filter updated to use default format of datetime.datetime (ISO8601)
* The junit plugin now has an option to report a junit test failure on changes for idempotent testing.
* New 'diff' keyword allows setting diff mode on playbook objects, overriding command line option and config.
* New config settings for inventory to:
- control inventory plugins used
- extensions of files to ignore when using inventory directory
- patterns of flies to ignore when using inventory directory
- option to toggle failed inventory source parsing between an error or a warning
* More fixes for Python 3 across the code base.
* win_shell and win_command modules now properly preserve quoted arguments passed on the command-line. Tasks that attempted to work around the issue by adding extra quotes/escaping may need to be reworked. See https://github.com/ansible/ansible/issues/23019 for additional detail.
* All configuration paths are now relative to the `ansible.cfg` file used.
* By user request, a 'configuration macro' (``CWD``) is available to force configured paths to be relative to the current working directory. Please note that this is unsafe and not recommended.
#### New Callbacks:
- full_skip
- profile_roles
- stderr
#### New Filters:
- parse_cli
- parse_cli_textfsm
#### New Inventory Plugins:
- advanced_host_list
- constructed
- host_list
- ini
- script
- virtualbox
- yaml
#### New Inventory scripts:
- lxd
#### New: Tests
- any : true if any element is true
- all: true if all elements are true
### Module Notes
- The docker_container module has gained a new option, `working_dir` which allows
specifying the working directory for the command being run in the image.
- The ec2_win_password module now requires the cryptography python module be installed to run
- The stat module added a field, lnk_target. When the file being stated is
a symlink, lnk_target will contain the target of the link. This differs from
lnk_source when the target is specified relative to the symlink. In this
case, lnk_target will remain relative while lnk_source will be expanded to an
absolute path.
- The archive module has a new parameter exclude_path which lists paths to exclude from the archive
- The yum module has a new parameter security which limits state=latest to security updates
- The template module gained a follow parameter to match with copy and file.
Like those modules, template defaults this parameter to False. Previously,
template hardcoded this to true.
- Added a new parameter to command module that lets users specify data to pipe
into the command's stdin.
- The azure_rm modules now accept a `cloud_environment` arg to access regional and private clouds.
- The azure_rm modules and inventory script now require at least version 2.0.0 of the Azure Python SDK.
### New Modules
#### Cloud
- amazon
* aws_api_gateway
* aws_direct_connect_connection
* aws_direct_connect_link_aggregation_group
* aws_s3
* aws_s3_bucket_facts
* aws_waf_facts
* data_pipeline
* dynamodb_ttl
* ec2_instance_facts
* ec2_metadata_facts
* ec2_vpc_dhcp_option_facts
* ec2_vpc_endpoint
* ec2_vpc_endpoint_facts
* ec2_vpc_peering_facts
* ecs_attribute
* elb_application_lb
* elb_application_lb_facts
* elb_target_group
* elb_target_group_facts
* iam_group
* iam_managed_policy
* lightsail
* redshift_facts
- azure
* azure_rm_acs
* azure_rm_availabilityset
* azure_rm_availabilityset_facts
* azure_rm_dnsrecordset
* azure_rm_dnsrecordset_facts
* azure_rm_dnszone
* azure_rm_dnszone_facts
* azure_rm_functionapp
* azure_rm_functionapp_facts
* azure_rm_loadbalancer
* azure_rm_loadbalancer_facts
* azure_rm_managed_disk
* azure_rm_managed_disk_facts
* azure_rm_virtualmachine_extension
* azure_rm_virtualmachine_scaleset
* azure_rm_virtualmachine_scaleset_facts
- atomic
* atomic_container
- cloudstack
* cs_instance_nic
* cs_instance_nic_secondaryip
* cs_network_acl
* cs_network_acl_rule
* cs_storage_pool
* cs_vpn_gateway
- digital_ocean
* digital_ocean_floating_ip
- docker
* docker_secret
* docker_volume
- google
* gce_labels
* gcp_backend_service
* gcp_forwarding_rule
* gcp_healthcheck
* gcp_target_proxy
* gcp_url_map
- misc
* helm
- ovirt
* ovirt_host_storage_facts
* ovirt_scheduling_policies_facts
* ovirt_storage_connections
- vmware
* vcenter_license
* vmware_guest_find
* vmware_guest_tools_wait
* vmware_resource_pool
#### Commands
* telnet
#### Crypto
* openssl_certificate
* openssl_csr
#### Files
* xml
#### Identity
- cyberark
* cyberark_authentication
* cyberark_user
- ipa
* ipa_dnsrecord
#### Monitoring
* sensu_client
* sensu_handler
* sensu_silence
#### Network
- aci
* aci_aep
* aci_ap
* aci_bd
* aci_bd_subnet
* aci_bd_to_l3out
* aci_contract
* aci_contract_subject_to_filter
* aci_epg
* aci_epg_monitoring_policy
* aci_epg_to_contract
* aci_epg_to_domain
* aci_filter
* aci_filter_entry
* aci_intf_policy_fc
* aci_intf_policy_l2
* aci_intf_policy_lldp
* aci_intf_policy_mcp
* aci_intf_policy_port_channel
* aci_intf_policy_port_security
* aci_l3out_route_tag_policy
* aci_rest
* aci_taboo_contract
* aci_tenant
* aci_tenant_action_rule_profile
* aci_tenant_span_dst_group
* aci_vrf
- aireos
* aireos_command
* aireos_config
- aruba
* aruba_command
* aruba_config
- avi
* avi_actiongroupconfig
* avi_alertconfig
* avi_alertemailconfig
* avi_alertscriptconfig
* avi_alertsyslogconfig
* avi_authprofile
* avi_backup
* avi_backupconfiguration
* avi_cloud
* avi_cloudconnectoruser
* avi_cloudproperties
* avi_cluster
* avi_controllerproperties
* avi_dnspolicy
* avi_gslb
* avi_gslbapplicationpersistenceprofile
* avi_gslbgeodbprofile
* avi_gslbhealthmonitor
* avi_gslbservice
* avi_hardwaresecuritymodulegroup
* avi_httppolicyset
* avi_ipaddrgroup
* avi_ipamdnsproviderprofile
* avi_microservicegroup
* avi_network
* avi_networksecuritypolicy
* avi_poolgroupdeploymentpolicy
* avi_prioritylabels
* avi_scheduler
* avi_seproperties
* avi_serverautoscalepolicy
* avi_serviceengine
* avi_serviceenginegroup
* avi_snmptrapprofile
* avi_stringgroup
* avi_trafficcloneprofile
* avi_useraccountprofile
* avi_vrfcontext
* avi_vsdatascriptset
* avi_vsvip
* avi_webhook
- bigswitch
* bcf_switch
- cloudengine
* ce_aaa_server
* ce_aaa_server_host
* ce_acl
* ce_acl_advance
* ce_acl_interface
* ce_bfd_global
* ce_bfd_session
* ce_bfd_view
* ce_bgp
* ce_bgp_af
* ce_bgp_neighbor
* ce_bgp_neighbor_af
* ce_config
* ce_dldp
* ce_dldp_interface
* ce_eth_trunk
* ce_evpn_bd_vni
* ce_evpn_bgp
* ce_evpn_bgp_rr
* ce_evpn_global
* ce_facts
* ce_file_copy
* ce_info_center_debug
* ce_info_center_global
* ce_info_center_log
* ce_info_center_trap
* ce_interface
* ce_interface_ospf
* ce_ip_interface
* ce_link_status
* ce_mlag_config
* ce_mlag_interface
* ce_mtu
* ce_netconf
* ce_netstream_aging
* ce_netstream_export
* ce_netstream_global
* ce_netstream_template
* ce_ntp
* ce_ntp_auth
* ce_ospf
* ce_ospf_vrf
* ce_reboot
* ce_rollback
* ce_sflow
* ce_snmp_community
* ce_snmp_contact
* ce_snmp_location
* ce_snmp_target_host
* ce_snmp_traps
* ce_snmp_user
* ce_startup
* ce_static_route
* ce_stp
* ce_switchport
* ce_vlan
* ce_vrf
* ce_vrf_af
* ce_vrf_interface
* ce_vrrp
* ce_vxlan_arp
* ce_vxlan_gateway
* ce_vxlan_global
* ce_vxlan_tunnel
* ce_vxlan_vap
- cloudvision
* cv_server_provision
- eos
* eos_logging
* eos_vlan
* eos_vrf
- f5
* bigip_command
* bigip_config
* bigip_configsync_actions
* bigip_gtm_pool
* bigip_iapp_service
* bigip_iapp_template
* bigip_monitor_tcp_echo
* bigip_monitor_tcp_half_open
* bigip_provision
* bigip_qkview
* bigip_snmp
* bigip_snmp_trap
* bigip_ucs
* bigip_user
* bigip_virtual_address
- fortios
* fortios_address
- interface
* net_interface
* net_linkagg
* net_lldp_interface
- ios
* ios_interface
* ios_logging
* ios_static_route
* ios_user
- iosxr
* iosxr_banner
* iosxr_interface
* iosxr_logging
* iosxr_user
- junos
* junos_banner
* junos_interface
* junos_l3_interface
* junos_linkagg
* junos_lldp
* junos_lldp_interface
* junos_logging
* junos_static_route
* junos_system
* junos_vlan
* junos_vrf
- layer2
* net_l2_interface
* net_vlan
- layer3
* net_l3_interface
* net_vrf
- netscaler
* netscaler_cs_action
* netscaler_cs_policy
* netscaler_cs_vserver
* netscaler_gslb_service
* netscaler_gslb_site
* netscaler_gslb_vserver
* netscaler_lb_monitor
* netscaler_lb_vserver
* netscaler_save_config
* netscaler_server
* netscaler_service
* netscaler_servicegroup
* netscaler_ssl_certkey
- nuage
* nuage_vspk
- nxos
* nxos_banner
* nxos_logging
- panos
* panos_nat_rule
* panos_object
* panos_security_rule
- protocol
* net_lldp
- routing
* net_static_route
- system
* net_banner
* net_logging
* net_system
* net_user
- vyos
* vyos_banner
* vyos_interface
* vyos_l3_interface
* vyos_linkagg
* vyos_lldp
* vyos_lldp_interface
* vyos_logging
* vyos_static_route
* vyos_user
#### Notification
* bearychat
* catapult
* office_365_connector_card
#### Remote Management
- hpe
* oneview_fc_network
- imc
* imc_rest
- manageiq
* manageiq_user
#### Source Control
* github_deploy_key
* github_issue
#### Storage
* nuage_vpsk
- panos
* panos_sag
- purestorage
* purefa_hg
* purefa_host
* purefa_pg
* purefa_snap
* purefa_volume
#### System
* aix_lvol
* awall
* dconf
* interfaces_file
#### Web Infrastructure
* gunicorn
* rundeck_acl_policy
* rundeck_project
#### Windows
* win_defrag
* win_domain_group
* win_domain_user
* win_dsc
* win_eventlog
* win_eventlog_entry
* win_firewall
* win_group_membership
* win_hotfix
* win_mapped_drive
* win_pagefile
* win_power_plan
* win_psmodule
* win_rabbitmq_plugin
* win_route
* win_security_policy
* win_toast
* win_user_right
* win_wait_for
* win_wakeonlan
<a id="2.3.3"></a>
## 2.3.3 "Ramble On" - TBD
### Bugfixes
* Security fix for CVE-2017-7550 the jenkins_plugin module was logging the jenkins
server password if the url_password was passed via the params field:
https://github.com/ansible/ansible/pull/30875
* Fix alternatives module handlling of non existing options
* Fix synchronize traceback with the docker connection plugin
* Do not escape backslashes in the template lookup plugin to mirror what the template module does
@ -656,8 +61,17 @@ Ansible Changes By Release
* Fixed check mode for enable on Solaris for service module
* Fix cloudtrail module to allow AWS profiles other than the default
* Fix an encoding issue with secret (password) vars_prompts
* Fix for Windows become to show the stdout and stderr strings on a failure
* Fix the issue SSL verification can not be disabled for Tower modules
* Use safe_load instead on load to read a yaml document
* Fix for win_file to respect check mode when deleting directories
* Include_role now complains about invalid arguments
* Added socket conditions to ignore for wait_for, no need to error for closing already closed connection
* Updated hostname module to work on newer RHEL7 releases
* Security fix to avoid provider password leaking in logs for network modules
<a id="2.3.2"></a>
* Python3 fixes for azure modules
## 2.3.2 "Ramble On" - 2017-08-04
@ -810,7 +224,6 @@ Moving to Ansible 2.3 guide http://docs.ansible.com/ansible/porting_guide_2.3.ht
#### New: lookups
- keyring: allows getting password from the 'controller' system's keyrings
- chef_databag: allows querying Chef Databags via pychef library
#### New: cache
@ -856,8 +269,6 @@ Moving to Ansible 2.3 guide http://docs.ansible.com/ansible/porting_guide_2.3.ht
- bigswitch:
* bigmon_chain
* bigmon_policy
- cisco
* cisco_spark
- cloudengine:
* ce_command
- cloudscale_server
@ -1435,7 +846,7 @@ Notice given that the following will be removed in Ansible 2.4:
* Security fix for CVE-2016-8628 - Command injection by compromised server via fact variables. In some situations, facts returned by modules could overwrite connection-based facts or some other special variables, leading to injected commands running on the Ansible controller as the user running Ansible (or via escalated permissions).
* Security fix for CVE-2016-8614 - apt_key module not properly validating keys in some situations.
### Minor Changes:
###Minor Changes:
* The subversion module from core now marks its password parameter as no_log so
the password is obscured when logging.
* The postgresql_lang and postgresql_ext modules from extras now mark
@ -1515,7 +926,7 @@ Module fixes:
## 2.1 "The Song Remains the Same"
### Major Changes:
###Major Changes:
* Official support for the networking modules, originally available in 2.0 as a tech preview.
* Refactored and expanded support for Docker with new modules and many improvements to existing modules, as well as a new Kubernetes module.
@ -1673,12 +1084,12 @@ Module fixes:
* issubset
* issuperset
#### New Inventory scripts:
####New Inventory scripts:
* brook
* rackhd
* azure_rm
### Minor Changes:
###Minor Changes:
* Added support for pipelining mode to more connection plugins, which helps prevent
module data from being written to disk.
@ -1693,7 +1104,7 @@ Module fixes:
10-first-callback.py and 20-second-callback.py.
* Added (alpha) Centirfy's dzdo as another become meethod (privilege escalation)
### Deprecations:
###Deprecations:
* Deprecated the use of "bare" variables in loops (ie. `with_items: foo`, where `foo` is a variable).
The full jinja2 variable syntax of `{{foo}}` should always be used instead. This warning will be removed
@ -1794,7 +1205,7 @@ Module fixes:
## 2.0 "Over the Hills and Far Away" - Jan 12, 2016
### Major Changes:
###Major Changes:
* Releases are now named after Led Zeppelin songs, 1.9 will be the last Van Halen named release.
* The new block/rescue/always directives allow for making task blocks and exception-like semantics
@ -1817,7 +1228,7 @@ Module fixes:
This re-executes inventory scripts, but does not force them to ignore any cache they might use.
* New delegate_facts directive, a boolean that allows you to apply facts to the delegated host (true/yes) instead of the inventory_hostname (no/false) which is the default and previous behaviour.
* local connections now work with 'su' as a privilege escalation method
* Ansible 2.0 has deprecated the "ssh" from ansible_ssh_user, ansible_ssh_host, and ansible_ssh_port to become ansible_user, ansible_host, and ansible_port.
* Ansible 2.0 has deprecated the “ssh” from ansible_ssh_user, ansible_ssh_host, and ansible_ssh_port to become ansible_user, ansible_host, and ansible_port.
* New ssh configuration variables (`ansible_ssh_common_args`, `ansible_ssh_extra_args`) can be used to configure a
per-group or per-host ssh ProxyCommand or set any other ssh options.
`ansible_ssh_extra_args` is used to set options that are accepted only by ssh (not sftp or scp, which have their own analogous settings).
@ -1825,7 +1236,7 @@ Module fixes:
* Backslashes used when specifying parameters in jinja2 expressions in YAML dicts sometimes needed to be escaped twice.
This has been fixed so that escaping once works. Here's an example of how playbooks need to be modified:
```yaml
```
# Syntax in 1.9.x
- debug:
msg: "{{ 'test1_junk 1\\\\3' | regex_replace('(.*)_junk (.*)', '\\\\1 \\\\2') }}"
@ -1843,7 +1254,7 @@ format the trailing newlines were kept. In v2, both methods of specifying the
string will keep the trailing newlines. If you relied on the trailing
newline being stripped you can change your playbook like this:
```yaml
```
# Syntax in 1.9.2
vars:
message: >
@ -1870,7 +1281,7 @@ variable syntax ('{{var_name}}') - bare variable names there are no longer accep
In fact, even specifying args with variables has been deprecated, and will not be
allowed in future versions:
```yaml
```
---
- hosts: localhost
connection: local
@ -1885,13 +1296,13 @@ allowed in future versions:
with_items: my_dirs
```
### Plugins
###Plugins
* Rewritten dnf module that should be faster and less prone to encountering bugs in cornercases
* WinRM connection plugin passes all vars named `ansible_winrm_*` to the underlying pywinrm client. This allows, for instance, `ansible_winrm_server_cert_validation=ignore` to be used with newer versions of pywinrm to disable certificate validation on Python 2.7.9+.
* WinRM connection plugin put_file is significantly faster and no longer has file size limitations.
#### Deprecated Modules (new ones in parens):
####Deprecated Modules (new ones in parens):
* ec2_ami_search (ec2_ami_find)
* quantum_network (os_network)
@ -1902,7 +1313,7 @@ allowed in future versions:
* quantum_router_gateway (os_router)
* quantum_router_interface (os_router)
#### New Modules:
####New Modules:
- amazon
* ec2_ami_copy
@ -2118,7 +1529,7 @@ allowed in future versions:
* zabbix_screen
- znode
#### New Inventory scripts:
####New Inventory scripts:
* cloudstack
* fleetctl
@ -2129,27 +1540,27 @@ allowed in future versions:
* rudder
* serf
#### New Lookups:
####New Lookups:
* credstash
* hashi_vault
* ini
* shelvefile
#### New Filters:
####New Filters:
* combine
#### New Connection:
####New Connection:
* docker: for talking to docker containers on the ansible controller machine without using ssh.
#### New Callbacks:
####New Callbacks:
* logentries: plugin to send play data to logentries service
* skippy: same as default but does not display skip messages
### Minor changes:
###Minor changes:
* Many more tests. The new API makes things more testable and we took advantage of it.
* big_ip modules now support turning off ssl certificate validation (use only for self-signed certificates).
@ -3291,7 +2702,7 @@ the variable is still registered for the host, with the attribute skipped: True.
* added basename and dirname as Jinja2 filters available to all templates
* pip works better when sudoing from unprivileged users
* fix for user creation with groups specification reporting 'changed' incorrectly in some cases
* fix for some unicode encoding errors in outputting some data in verbose mode
* fix for some unicode encoding errors in outputing some data in verbose mode
* improved FreeBSD, NetBSD and Solaris facts
* debug module always outputs data without having to specify -v
* fix for sysctl module creating new keys (must specify checks=none)
@ -3665,7 +3076,7 @@ New Modules:
* new LSB facts (release, distro, etc)
* pause module -- (pause seconds=10) (pause minutes=1) (pause prompt=foo) -- it's an action plugin
* a module for adding entries to the main crontab (though you may still wish to just drop template files into cron.d)
* debug module can be used for outputting messages without using 'shell echo'
* debug module can be used for outputing messages without using 'shell echo'
* a fail module is now available for causing errors, you might want to use it with only_if to fail in certain conditions
Other module Changes, Upgrades, and Fixes:

View File

@ -14,15 +14,15 @@ Language
* While not all components of Ansible must be in Python, core contributions to the Ansible repo must be written in Python. This is to maximize the ability of everyone to contribute.
* If you want to write non-Python ansible modules or inventory scripts, that's fine, but they are not going to get merged in most likely. Sorry!!
PEP 8 and basic style checks
PEP8 and basic style checks
===========================
* [PEP 8](https://www.python.org/dev/peps/pep-0008/) is a great Python style guide, which you should read.
* PEP 8 must not be strictly followed in all aspects, but most of it is good advice
* PEP8 is a great Python style guide, which you should read.
* PEP8 must not be strictly followed in all aspects, but most of it is good advice
* In particular, we don't really care about line lengths. Buy a bigger monitor!
* To run checks for things we care about, use [ansible-test](http://docs.ansible.com/ansible/dev_guide/testing_pep8.html#running-locally).
* To run checks for things we care about, run "make pep8"
* Similarly, additional checks can be made with "make pyflakes"
* There is no need to submit code changes for PEP 8 and pyflakes fixes, as these break attribution history. Project leadership will make these periodically.
* There is no need to submit code changes for pep8 and pyflake fixes, as these break attribution history. Project leadership will make these periodically.
* Do not submit pull requests that simply adjust whitespace in the code
Testing
@ -101,22 +101,22 @@ Use the dict constructor where possible when allocating dictionaries:
# this:
foo = dict(
a=12,
b=34,
a = 12,
b = 34
)
Do not line up variables
Line up variables
# not this
a = 12
foosball = 34
xyz = 'dog'
# this
a = 12
foosball = 34
xyz = 'dog'
# this
a = 12
foosball = 34
xyz = 'dog'
Don't use line continuations:
# no
@ -131,13 +131,13 @@ Don't use line continuations:
Spacing:
# no
x = [1,2,3]
x=[1,2,3]
# no
x = [ 1, 2, 3 ]
x = [1,2,3]
# yes
x = [1, 2, 3]
x = [ 1, 2, 3 ]
Spacing continued:
@ -277,7 +277,7 @@ To test if something is a string, consider that it may be unicode.
if type(x) == str:
# yes
from ansible.module_utils.six import string_types
from ansible.compat.six import string_types
if isinstance(x, string_types):
Cleverness
@ -314,3 +314,7 @@ This was not meant to be a scary document, so we hope it wasn't, but we also hop
If you have questions about this document, please ask on the ansible-devel mailing list.
Thank you!

View File

@ -1,16 +1,18 @@
prune ticket_stubs
prune hacking
include README.md COPYING
include SYMLINK_CACHE.json
include requirements.txt
include .coveragerc
include .yamllint
include examples/hosts
include examples/ansible.cfg
recursive-include lib/ansible/module_utils/powershell *
include lib/ansible/module_utils/powershell.ps1
recursive-include lib/ansible/modules *
recursive-include lib/ansible/galaxy/data *
recursive-include docs *
include hacking/module_formatter.py
include hacking/dump_playbook_attributes.py
recursive-include hacking/templates *
recursive-include packaging *
recursive-include test *
include Makefile

View File

@ -47,9 +47,9 @@ A detailed explanation of the PR workflow can be seen here: https://github.com/a
***
# Maintainers list
# Extras maintainers list
The full list of maintainers for modules is located here: https://github.com/ansible/ansible/blob/devel/.github/BOTMETA.yml
The full list of maintainers for modules is located here: https://github.com/ansible/ansibullbot
## Changing Maintainership

View File

@ -9,7 +9,7 @@
# make deb-src -------------- produce a DEB source
# make deb ------------------ produce a DEB
# make docs ----------------- rebuild the manpages (results are checked in)
# make tests ---------------- run the tests (see https://docs.ansible.com/ansible/dev_guide/testing_units.html for requirements)
# make tests ---------------- run the tests (see test/README.md for requirements)
# make pyflakes, make pep8 -- source code checks
########################################################
@ -21,15 +21,13 @@ OS = $(shell uname -s)
# Manpages are currently built with asciidoc -- would like to move to markdown
# This doesn't evaluate until it's called. The -D argument is the
# directory of the target file ($@), kinda like `dirname`.
MANPAGES ?= $(patsubst %.asciidoc.in,%,$(wildcard ./docs/man/man1/ansible*.1.asciidoc.in))
MANPAGES := docs/man/man1/ansible.1 docs/man/man1/ansible-playbook.1 docs/man/man1/ansible-pull.1 docs/man/man1/ansible-doc.1 docs/man/man1/ansible-galaxy.1 docs/man/man1/ansible-vault.1 docs/man/man1/ansible-console.1
ifneq ($(shell which a2x 2>/dev/null),)
ASCII2MAN = a2x -L -D $(dir $@) -d manpage -f manpage $<
ASCII2HTMLMAN = a2x -L -D docs/html/man/ -d manpage -f xhtml
else
ASCII2MAN = @echo "ERROR: AsciiDoc 'a2x' command is not installed but is required to build $(MANPAGES)" && exit 1
endif
GENERATE_CLI = docs/bin/generate_man.py
PYTHON=python
SITELIB = $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
@ -118,26 +116,17 @@ TARGET ?=
########################################################
.PHONY: all
all: clean python
.PHONY: tests
tests:
$(ANSIBLE_TEST) units -v --python $(PYTHON_VERSION) $(TEST_FLAGS)
.PHONY: tests-py3
tests-py3:
$(ANSIBLE_TEST) units -v --python $(PYTHON3_VERSION) $(TEST_FLAGS)
.PHONY: tests-nonet
tests-nonet:
$(ANSIBLE_TEST) units -v --python $(PYTHON_VERSION) $(TEST_FLAGS) --exclude test/units/modules/network/
.PHONY: integration
integration:
$(ANSIBLE_TEST) integration -v --docker $(IMAGE) $(TARGET) $(TEST_FLAGS)
.PHONY: authors
authors:
sh hacking/authors.sh
@ -151,19 +140,15 @@ authors:
%.1: %.1.asciidoc VERSION
$(ASCII2MAN)
.PHONY: loc
loc:
sloccount lib library bin
.PHONY: pep8
pep8:
$(ANSIBLE_TEST) sanity --test pep8 --python $(PYTHON_VERSION) $(TEST_FLAGS)
.PHONY: pyflakes
pyflakes:
pyflakes lib/ansible/*.py lib/ansible/*/*.py bin/*
.PHONY: clean
clean:
@echo "Cleaning up distutils stuff"
rm -rf build
@ -179,15 +164,8 @@ clean:
find ./docs/man -type f -name "*.xml" -delete
find ./docs/man -type f -name "*.asciidoc" -delete
find ./docs/man/man3 -type f -name "*.3" -delete
rm -f ./docs/man/man1/*
@echo "Cleaning up output from test runs"
rm -rf test/test_data
rm -rf shippable/
rm -rf logs/
rm -rf .cache/
rm -f test/units/.coverage*
rm -rf test/results/*/*
find test/ -type f -name '*.retry' -delete
@echo "Cleaning up RPM building stuff"
rm -rf MANIFEST rpm-build
@echo "Cleaning up Debian building stuff"
@ -197,33 +175,30 @@ clean:
rm -rf docs/js
@echo "Cleaning up authors file"
rm -f AUTHORS.TXT
@echo "Cleaning up tests"
rm -f test/units/.coverage*
rm -f test/results/*/*
@echo "Cleaning up docsite"
$(MAKE) -C docs/docsite clean
$(MAKE) -C docs/api clean
.PHONY: python
python:
$(PYTHON) setup.py build
.PHONY: install
install:
$(PYTHON) setup.py install
.PHONY: sdist
sdist: clean docs
$(PYTHON) setup.py sdist
.PHONY: sdist_upload
sdist_upload: clean docs
$(PYTHON) setup.py sdist upload 2>&1 |tee upload.log
.PHONY: rpmcommon
rpmcommon: sdist
rpmcommon: $(MANPAGES) sdist
@mkdir -p rpm-build
@cp dist/*.gz rpm-build/
@sed -e 's#^Version:.*#Version: $(VERSION)#' -e 's#^Release:.*#Release: $(RPMRELEASE)%{?dist}$(REPOTAG)#' $(RPMSPEC) >rpm-build/$(NAME).spec
.PHONY: mock-srpm
mock-srpm: /etc/mock/$(MOCK_CFG).cfg rpmcommon
$(MOCK_BIN) -r $(MOCK_CFG) $(MOCK_ARGS) --resultdir rpm-build/ --buildsrpm --spec rpm-build/$(NAME).spec --sources rpm-build/
@echo "#############################################"
@ -231,7 +206,6 @@ mock-srpm: /etc/mock/$(MOCK_CFG).cfg rpmcommon
@echo rpm-build/*.src.rpm
@echo "#############################################"
.PHONY: mock-rpm
mock-rpm: /etc/mock/$(MOCK_CFG).cfg mock-srpm
$(MOCK_BIN) -r $(MOCK_CFG) $(MOCK_ARGS) --resultdir rpm-build/ --rebuild rpm-build/$(NAME)-*.src.rpm
@echo "#############################################"
@ -239,7 +213,6 @@ mock-rpm: /etc/mock/$(MOCK_CFG).cfg mock-srpm
@echo rpm-build/*.noarch.rpm
@echo "#############################################"
.PHONY: srpm
srpm: rpmcommon
@rpmbuild --define "_topdir %(pwd)/rpm-build" \
--define "_builddir %{_topdir}" \
@ -254,7 +227,6 @@ srpm: rpmcommon
@echo " rpm-build/$(RPMNVR).src.rpm"
@echo "#############################################"
.PHONY: rpm
rpm: rpmcommon
@rpmbuild --define "_topdir %(pwd)/rpm-build" \
--define "_builddir %{_topdir}" \
@ -271,7 +243,6 @@ rpm: rpmcommon
@echo " rpm-build/$(RPMNVR).noarch.rpm"
@echo "#############################################"
.PHONY: debian
debian: sdist
@for DIST in $(DEB_DIST) ; do \
mkdir -p deb-build/$${DIST} ; \
@ -280,7 +251,6 @@ debian: sdist
sed -ie "s|%VERSION%|$(VERSION)|g;s|%RELEASE%|$(DEB_RELEASE)|;s|%DIST%|$${DIST}|g;s|%DATE%|$(DEB_DATE)|g" deb-build/$${DIST}/$(NAME)-$(VERSION)/debian/changelog ; \
done
.PHONY: deb
deb: deb-src
@for DIST in $(DEB_DIST) ; do \
PBUILDER_OPTS="$(PBUILDER_OPTS) --distribution $${DIST} --basetgz $(PBUILDER_CACHE_DIR)/$${DIST}-$(PBUILDER_ARCH)-base.tgz --buildresult $(CURDIR)/deb-build/$${DIST}" ; \
@ -297,7 +267,6 @@ deb: deb-src
# Build package outside of pbuilder, with locally installed dependencies.
# Install BuildRequires as noted in packaging/debian/control.
.PHONY: local_deb
local_deb: debian
@for DIST in $(DEB_DIST) ; do \
(cd deb-build/$${DIST}/$(NAME)-$(VERSION)/ && $(DEBUILD) -b) ; \
@ -309,7 +278,6 @@ local_deb: debian
done
@echo "#############################################"
.PHONY: deb-src
deb-src: debian
@for DIST in $(DEB_DIST) ; do \
(cd deb-build/$${DIST}/$(NAME)-$(VERSION)/ && $(DEBUILD) -S) ; \
@ -321,37 +289,23 @@ deb-src: debian
done
@echo "#############################################"
.PHONY: deb-upload
deb-upload: deb
@for DIST in $(DEB_DIST) ; do \
$(DPUT_BIN) $(DPUT_OPTS) $(DEB_PPA) deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_amd64.changes ; \
done
.PHONY: deb-src-upload
deb-src-upload: deb-src
@for DIST in $(DEB_DIST) ; do \
$(DPUT_BIN) $(DPUT_OPTS) $(DEB_PPA) deb-build/$${DIST}/$(NAME)_$(VERSION)-$(DEB_RELEASE)~$${DIST}_source.changes ; \
done
.PHONY: epub
epub:
(cd docs/docsite/; CPUS=$(CPUS) make epub)
# for arch or gentoo, read instructions in the appropriate 'packaging' subdirectory directory
.PHONY: webdocs
webdocs:
(cd docs/docsite/; CPUS=$(CPUS) make docs)
.PHONY: generate_asciidoc
generate_asciidoc: lib/ansible/cli/*.py
mkdir -p ./docs/man/man1/ ; \
PYTHONPATH=./lib $(GENERATE_CLI) --template-file=docs/templates/man.j2 --output-dir=docs/man/man1/ --output-format man lib/ansible/cli/*.py
docs: $(MANPAGES)
docs: generate_asciidoc
make $(MANPAGES)
.PHONY: alldocs
alldocs: docs webdocs
version:

View File

@ -9,7 +9,11 @@ Ansible is a radically simple IT automation system. It handles configuration-ma
Read the documentation and more at https://ansible.com/
You can find installation instructions [here](https://docs.ansible.com/ansible/intro_installation.html) for a variety of platforms. Most users should probably install a released version of Ansible from `pip`, a package manager or our [release repository](https://releases.ansible.com/ansible/). [Officially supported](https://www.ansible.com/ansible-engine) builds of Ansible are also available. Some power users run directly from the development branch - while significant efforts are made to ensure that `devel` is reasonably stable, you're more likely to encounter breaking changes when running Ansible this way.
Many users run straight from the development branch (it's generally fine to do so), but you might also wish to consume a release.
You can find instructions [here](https://docs.ansible.com/intro_getting_started.html) for a variety of platforms.
If you want to download a tarball of a release, go to [releases.ansible.com](https://releases.ansible.com/ansible), though most users use `yum` (using the EPEL instructions linked above), `apt` (using the PPA instructions linked above), or `pip install ansible`.
Design Principles
=================
@ -39,6 +43,7 @@ Branch Info
* Releases are named after Led Zeppelin songs. (Releases prior to 2.0 were named after Van Halen songs.)
* The devel branch corresponds to the release actively under development.
* For releases 1.8 - 2.2, modules are kept in different repos, you'll want to follow [core](https://github.com/ansible/ansible-modules-core) and [extras](https://github.com/ansible/ansible-modules-extras)
* Various release-X.Y branches exist for previous releases.
* We'd love to have your contributions, read [Community Information](https://docs.ansible.com/community.html) for notes on how to get started.
@ -49,8 +54,9 @@ Ansible was created by [Michael DeHaan](https://github.com/mpdehaan) (michael.de
Ansible is sponsored by [Ansible, Inc](https://ansible.com)
License
Licence
=======
GNU General Public License v3.0
GNU
Click on the [Link](COPYING) to see the full text.
See [COPYING](COPYING) to see the full text.

View File

@ -4,80 +4,84 @@ Ansible Releases at a Glance
VERSION RELEASE CODE NAME
++++++++++++++++++++++++++++++
2.4.0 TBD "Dancing Days"
2.3.2 2017-08-04 "Ramble On"
2.3.1 2017-06-01 "Ramble On"
2.3.0 2017-04-12 "Ramble On"
2.2.3 2017-05-09 "The Battle of Evermore"
2.2.2 2017-03-27 "The Battle of Evermore"
2.2.1 2017-01-16 "The Battle of Evermore"
2.2.0 2016-11-01 "The Battle of Evermore"
2.1.6 2017-06-01 "The Song Remains the Same"
2.1.5 2017-03-27 "The Song Remains the Same"
2.1.4 2017-01-16 "The Song Remains the Same"
2.1.3 2016-11-04 "The Song Remains the Same"
2.1.2 2016-09-29 "The Song Remains the Same"
2.1.1 2016-07-28 "The Song Remains the Same"
2.1.0 2016-05-25 "The Song Remains the Same"
2.0.2 2016-04-19 "Over the Hills and Far Away"
2.0.1 2016-02-24 "Over the Hills and Far Away"
2.0.0 2016-01-12 "Over the Hills and Far Away"
1.9.6 2016-04-15 "Dancing In the Streets"
1.9.5 2016-03-21 "Dancing In the Streets"
1.9.4 2015-10-09 "Dancing In the Streets"
1.9.3 2015-09-03 "Dancing In the Streets"
1.9.2 2015-06-24 "Dancing In the Streets"
1.9.1 2015-04-27 "Dancing In the Streets"
1.9.0 2015-03-25 "Dancing In the Streets"
1.8.4 2015-02-19 "You Really Got Me"
1.8.3 2015-02-17 "You Really Got Me"
1.8.2 2014-12-04 "You Really Got Me"
1.8.1 2014-11-26 "You Really Got Me"
1.8.0 2014-11-25 "You Really Got Me"
1.7.2 2014-09-24 "Summer Nights"
1.7.1 2014-08-14 "Summer Nights"
1.7.0 2014-08-06 "Summer Nights"
1.6.10 2014-07-25 "The Cradle Will Rock"
1.6.9 2014-07-24 "The Cradle Will Rock"
1.6.8 2014-07-22 "The Cradle Will Rock"
1.6.7 2014-07-21 "The Cradle Will Rock"
1.6.6 2014-07-01 "The Cradle Will Rock"
1.6.5 2014-06-25 "The Cradle Will Rock"
1.6.4 2014-06-25 "The Cradle Will Rock"
1.6.3 2014-06-09 "The Cradle Will Rock"
1.6.2 2014-05-23 "The Cradle Will Rock"
1.6.1 2014-05-07 "The Cradle Will Rock"
1.6.0 2014-05-05 "The Cradle Will Rock"
1.5.5 2014-04-18 "Love Walks In"
1.5.4 2014-04-01 "Love Walks In"
1.5.3 2014-03-13 "Love Walks In"
1.5.2 2014-03-11 "Love Walks In"
1.5.1 2014-03-10 "Love Walks In"
1.5.0 2014-02-28 "Love Walks In"
1.4.5 2014-02-12 "Could This Be Magic?"
1.4.4 2014-01-06 "Could This Be Magic?"
1.4.3 2013-12-20 "Could This Be Magic?"
1.4.2 2013-12-18 "Could This Be Magic?"
1.4.1 2013-11-27 "Could This Be Magic?"
1.4.0 2013-11-21 "Could This Be Magic?"
1.3.4 2013-10-29 "Top of the World"
1.3.3 2013-10-09 "Top of the World"
1.3.2 2013-09-19 "Top of the World"
1.3.1 2013-09-16 "Top of the World"
1.3.0 2013-09-13 "Top of the World"
1.2.3 2013-08-21 "Right Now"
1.2.2 2013-07-05 "Right Now"
1.2.1 2013-07-04 "Right Now"
1.2.0 2013-06-10 "Right Now"
1.1.0 2013-04-02 "Mean Street"
1.0.0 2013-02-01 "Eruption"
0.9.0 2012-11-30 "Dreams"
0.8.0 2012-10-19 "Cathedral"
0.7.0 2012-09-06 "Panama"
0.6.0 2012-08-06 "Cabo"
0.5.0 2012-07-04 "Amsterdam"
0.4.0 2012-05-23 "Unchained"
0.3.0 2012-04-23 "Baluchitherium"
2.5.0 TBD "Kashmir"
2.4.2 11-29-2017 "Dancing Days"
2.4.1 10-25-2017 "Dancing Days"
2.4.0 09-19-2017 "Dancing Days"
2.3.3 12-20-2017 "Ramble On"
2.3.2 08-04-2017 "Ramble On"
2.3.1 06-01-2017 "Ramble On"
2.3.0 04-12-2017 "Ramble On"
2.2.3 05-09-2017 "The Battle of Evermore"
2.2.2 03-27-2017 "The Battle of Evermore"
2.2.1 01-16-2017 "The Battle of Evermore"
2.2.0 11-01-2016 "The Battle of Evermore"
2.1.6 06-01-2017 "The Song Remains the Same"
2.1.5 03-27-2017 "The Song Remains the Same"
2.1.4 01-16-2017 "The Song Remains the Same"
2.1.3 11-04-2016 "The Song Remains the Same"
2.1.2 09-29-2016 "The Song Remains the Same"
2.1.1 07-28-2016 "The Song Remains the Same"
2.1.0 05-25-2016 "The Song Remains the Same"
2.0.2 04-19-2016 "Over the Hills and Far Away"
2.0.1 02-24-2016 "Over the Hills and Far Away"
2.0.0 01-12-2016 "Over the Hills and Far Away"
1.9.6 04-15-2016 "Dancing In the Streets"
1.9.5 03-21-2016 "Dancing In the Streets"
1.9.4 10-09-2015 "Dancing In the Streets"
1.9.3 09-03-2015 "Dancing In the Streets"
1.9.2 06-24-2015 "Dancing In the Streets"
1.9.1 04-27-2015 "Dancing In the Streets"
1.9.0 03-25-2015 "Dancing In the Streets"
1.8.4 02-19-2015 "You Really Got Me"
1.8.3 02-17-2015 "You Really Got Me"
1.8.2 12-04-2014 "You Really Got Me"
1.8.1 11-26-2014 "You Really Got Me"
1.8.0 11-25-2014 "You Really Got Me"
1.7.2 09-24-2014 "Summer Nights"
1.7.1 08-14-2014 "Summer Nights"
1.7.0 08-06-2014 "Summer Nights"
1.6.10 07-25-2014 "The Cradle Will Rock"
1.6.9 07-24-2014 "The Cradle Will Rock"
1.6.8 07-22-2014 "The Cradle Will Rock"
1.6.7 07-21-2014 "The Cradle Will Rock"
1.6.6 07-01-2014 "The Cradle Will Rock"
1.6.5 06-25-2014 "The Cradle Will Rock"
1.6.4 06-25-2014 "The Cradle Will Rock"
1.6.3 06-09-2014 "The Cradle Will Rock"
1.6.2 05-23-2014 "The Cradle Will Rock"
1.6.1 05-07-2014 "The Cradle Will Rock"
1.6.0 05-05-2014 "The Cradle Will Rock"
1.5.5 04-18-2014 "Love Walks In"
1.5.4 04-01-2014 "Love Walks In"
1.5.3 03-13-2014 "Love Walks In"
1.5.2 03-11-2014 "Love Walks In"
1.5.1 03-10-2014 "Love Walks In"
1.5.0 02-28-2014 "Love Walks In"
1.4.5 02-12-2014 "Could This Be Magic?"
1.4.4 01-06-2014 "Could This Be Magic?"
1.4.3 12-20-2013 "Could This Be Magic?"
1.4.2 12-18-2013 "Could This Be Magic?"
1.4.1 11-27-2013 "Could This Be Magic?"
1.4.0 11-21-2013 "Could This Be Magic?"
1.3.4 10-29-2013 "Top of the World"
1.3.3 10-09-2013 "Top of the World"
1.3.2 09-19-2013 "Top of the World"
1.3.1 09-16-2013 "Top of the World"
1.3.0 09-13-2013 "Top of the World"
1.2.3 08-21-2013 "Right Now"
1.2.2 07-05-2013 "Right Now"
1.2.1 07-04-2013 "Right Now"
1.2.0 06-10-2013 "Right Now"
1.1.0 04-02-2013 "Mean Street"
1.0.0 02-01-2013 "Eruption"
0.9.0 11-30-2012 "Dreams"
0.8.0 10-19-2012 "Cathedral"
0.7.0 09-06-2012 "Panama"
0.6.0 08-06-2012 "Cabo"
0.5.0 07-04-2012 "Amsterdam"
0.4.0 05-23-2012 "Unchained"
0.3.0 04-23-2012 "Baluchitherium"
0.2.0 ? "Untitled"
0.1.0 ? "Untitled"
0.0.2 ? "Untitled"

View File

@ -1 +1 @@
2.5.0 0.0.devel
2.3.4.0 0.1.rc1

View File

@ -37,30 +37,30 @@ import shutil
import sys
import traceback
# for debug
from multiprocessing import Lock
import ansible.constants as C
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
from ansible.utils.display import Display
from ansible.module_utils._text import to_text
########################################
### OUTPUT OF LAST RESORT ###
class LastResort(object):
# OUTPUT OF LAST RESORT
def display(self, msg, log_only=None):
def display(self, msg):
print(msg, file=sys.stderr)
def error(self, msg, wrap_text=None):
print(msg, file=sys.stderr)
########################################
if __name__ == '__main__':
display = LastResort()
try: # bad ANSIBLE_CONFIG or config options can force ugly stacktrace
import ansible.constants as C
from ansible.utils.display import Display
except AnsibleOptionsError as e:
display.error(to_text(e), wrap_text=False)
sys.exit(5)
cli = None
me = os.path.basename(sys.argv[0])
@ -71,7 +71,7 @@ if __name__ == '__main__':
sub = None
target = me.split('-')
if target[-1][0].isdigit():
# Remove any version or python version info as downstreams
# Remove any version or pthon version info as downstreams
# sometimes add that
target = target[:-1]
@ -130,7 +130,7 @@ if __name__ == '__main__':
exit_code = 99
except Exception as e:
have_cli_options = cli is not None and cli.options is not None
display.error("Unexpected Exception, this is probably a bug: %s" % to_text(e), wrap_text=False)
display.error("Unexpected Exception: %s" % to_text(e), wrap_text=False)
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
log_only = False
else:

View File

@ -1 +0,0 @@
ansible

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# (c) 2017, Ansible, Inc. <support@ansible.com>
# (c) 2016, Ansible, Inc. <support@ansible.com>
#
# This file is part of Ansible
#
@ -33,19 +33,21 @@ import os
import shlex
import signal
import socket
import struct
import sys
import time
import traceback
import syslog
import datetime
import errno
import logging
from io import BytesIO
from ansible import constants as C
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.six import PY3
from ansible.module_utils.six.moves import cPickle
from ansible.module_utils.connection import send_data, recv_data
from ansible.module_utils._text import to_bytes, to_native
from ansible.module_utils.six.moves import cPickle, StringIO
from ansible.playbook.play_context import PlayContext
from ansible.plugins.loader import connection_loader
from ansible.plugins import connection_loader
from ansible.utils.path import unfrackpath, makedirs_safe
from ansible.errors import AnsibleConnectionFailure
from ansible.utils.display import Display
@ -60,9 +62,8 @@ def do_fork():
pid = os.fork()
if pid > 0:
return pid
# This is done as a 'good practice' for daemons, but we need to keep the cwd
# leaving it here as a note that we KNOW its good practice but are not doing it on purpose.
# os.chdir("/")
#os.chdir("/")
os.setsid()
os.umask(0)
@ -72,11 +73,11 @@ def do_fork():
sys.exit(0)
if C.DEFAULT_LOG_PATH != '':
out_file = open(C.DEFAULT_LOG_PATH, 'ab+')
err_file = open(C.DEFAULT_LOG_PATH, 'ab+', 0)
out_file = file(C.DEFAULT_LOG_PATH, 'a+')
err_file = file(C.DEFAULT_LOG_PATH, 'a+', 0)
else:
out_file = open('/dev/null', 'ab+')
err_file = open('/dev/null', 'ab+', 0)
out_file = file('/dev/null', 'a+')
err_file = file('/dev/null', 'a+', 0)
os.dup2(out_file.fileno(), sys.stdout.fileno())
os.dup2(err_file.fileno(), sys.stderr.fileno())
@ -88,11 +89,33 @@ def do_fork():
except OSError as e:
sys.exit(1)
def send_data(s, data):
packed_len = struct.pack('!Q',len(data))
return s.sendall(packed_len + data)
def recv_data(s):
header_len = 8 # size of a packed unsigned long long
data = b""
while len(data) < header_len:
d = s.recv(header_len - len(data))
if not d:
return None
data += d
data_len = struct.unpack('!Q',data[:header_len])[0]
data = data[header_len:]
while len(data) < data_len:
d = s.recv(data_len - len(data))
if not d:
return None
data += d
return data
class Server():
def __init__(self, socket_path, play_context):
self.socket_path = socket_path
def __init__(self, path, play_context):
self.path = path
self.play_context = play_context
display.display(
@ -101,219 +124,178 @@ class Server():
log_only=True
)
display.display('control socket path is %s' % socket_path, log_only=True)
display.display('control socket path is %s' % path, log_only=True)
display.display('current working directory is %s' % os.getcwd(), log_only=True)
self._start_time = datetime.datetime.now()
display.display("using connection plugin %s" % self.play_context.connection, log_only=True)
self.connection = connection_loader.get(play_context.connection, play_context, sys.stdin)
self.connection._connect()
if not self.connection.connected:
self.conn = connection_loader.get(play_context.connection, play_context, sys.stdin)
self.conn._connect()
if not self.conn.connected:
raise AnsibleConnectionFailure('unable to connect to remote host %s' % self._play_context.remote_addr)
connection_time = datetime.datetime.now() - self._start_time
display.display('connection established to %s in %s' % (play_context.remote_addr, connection_time), log_only=True)
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.socket.bind(self.socket_path)
self.socket.bind(path)
self.socket.listen(1)
display.display('local socket is set to listening', log_only=True)
signal.signal(signal.SIGALRM, self.alarm_handler)
def dispatch(self, obj, name, *args, **kwargs):
meth = getattr(obj, name, None)
if meth:
return meth(*args, **kwargs)
def alarm_handler(self, signum, frame):
'''
Alarm handler
'''
# FIXME: this should also set internal flags for other
# areas of code to check, so they can terminate
# earlier than the socket going back to the accept
# call and failing there.
#
# hooks the connection plugin to handle any cleanup
self.dispatch(self.conn, 'alarm_handler', signum, frame)
self.socket.close()
def run(self):
try:
while True:
signal.signal(signal.SIGALRM, self.connect_timeout)
signal.signal(signal.SIGTERM, self.handler)
# set the alarm, if we don't get an accept before it
# goes off we exit (via an exception caused by the socket
# getting closed while waiting on accept())
# FIXME: is this the best way to exit? as noted above in the
# handler we should probably be setting a flag to check
# here and in other parts of the code
signal.alarm(C.PERSISTENT_CONNECT_TIMEOUT)
(s, addr) = self.socket.accept()
display.display('incoming request accepted on persistent socket', log_only=True)
signal.alarm(0)
try:
(s, addr) = self.socket.accept()
display.display('incoming request accepted on persistent socket', log_only=True)
# clear the alarm
# FIXME: potential race condition here between the accept and
# time to this call.
signal.alarm(0)
except:
break
while True:
data = recv_data(s)
if not data:
break
signal.signal(signal.SIGALRM, self.command_timeout)
signal.alarm(self.play_context.timeout)
op = to_text(data.split(b':')[0])
display.display('socket operation is %s' % op, log_only=True)
method = getattr(self, 'do_%s' % op, None)
rc = 255
stdout = stderr = ''
try:
if data.startswith(b'EXEC: '):
display.display("socket operation is EXEC", log_only=True)
cmd = data.split(b'EXEC: ')[1]
(rc, stdout, stderr) = self.conn.exec_command(cmd)
elif data.startswith(b'PUT: ') or data.startswith(b'FETCH: '):
(op, src, dst) = shlex.split(to_native(data))
stdout = stderr = ''
try:
if op == 'FETCH:':
display.display("socket operation is FETCH", log_only=True)
self.conn.fetch_file(src, dst)
elif op == 'PUT:':
display.display("socket operation is PUT", log_only=True)
self.conn.put_file(src, dst)
rc = 0
except:
pass
elif data.startswith(b'CONTEXT: '):
display.display("socket operation is CONTEXT", log_only=True)
pc_data = data.split(b'CONTEXT: ')[1]
if not method:
stderr = 'Invalid action specified'
else:
rc, stdout, stderr = method(data)
src = StringIO(pc_data)
pc_data = cPickle.load(src)
src.close()
pc = PlayContext()
pc.deserialize(pc_data)
self.dispatch(self.conn, 'update_play_context', pc)
continue
else:
display.display("socket operation is UNKNOWN", log_only=True)
stdout = ''
stderr = 'Invalid action specified'
except:
stdout = ''
stderr = traceback.format_exc()
signal.alarm(0)
display.display('socket operation completed with rc %s' % rc, log_only=True)
display.display("socket operation completed with rc %s" % rc, log_only=True)
send_data(s, to_bytes(rc))
send_data(s, to_bytes(str(rc)))
send_data(s, to_bytes(stdout))
send_data(s, to_bytes(stderr))
s.close()
except Exception as e:
# socket.accept() will raise EINTR if the socket.close() is called
if e.errno != errno.EINTR:
display.display(traceback.format_exc(), log_only=True)
display.display(traceback.format_exec(), log_only=True)
finally:
# when done, close the connection properly and cleanup
# the socket file so it can be recreated
self.shutdown()
end_time = datetime.datetime.now()
delta = end_time - self._start_time
display.display('shutdown local socket, connection was active for %s secs' % delta, log_only=True)
def connect_timeout(self, signum, frame):
display.display('persistent connection idle timeout triggered, timeout value is %s secs' % C.PERSISTENT_CONNECT_TIMEOUT, log_only=True)
self.shutdown()
def command_timeout(self, signum, frame):
display.display('command timeout triggered, timeout value is %s secs' % self.play_context.timeout, log_only=True)
self.shutdown()
def handler(self, signum, frame):
display.display('signal handler called with signal %s' % signum, log_only=True)
self.shutdown()
def shutdown(self):
display.display('shutdown persistent connection requested', log_only=True)
if not os.path.exists(self.socket_path):
display.display('persistent connection is not active', log_only=True)
return
try:
if self.socket:
display.display('closing local listener', log_only=True)
display.display('shutting down control socket, connection was active for %s secs' % delta, log_only=True)
try:
self.conn.close()
self.socket.close()
if self.connection:
display.display('closing the connection', log_only=True)
self.connection.close()
except:
pass
finally:
if os.path.exists(self.socket_path):
display.display('removing the local control socket', log_only=True)
os.remove(self.socket_path)
display.display('shutdown complete', log_only=True)
def do_EXEC(self, data):
cmd = data.split(b'EXEC: ')[1]
display.display('Command executed: %s' % cmd, log_only=True)
return self.connection.exec_command(cmd)
def do_PUT(self, data):
(op, src, dst) = shlex.split(to_native(data))
return self.connection.fetch_file(src, dst)
def do_FETCH(self, data):
(op, src, dst) = shlex.split(to_native(data))
return self.connection.put_file(src, dst)
def do_CONTEXT(self, data):
pc_data = data.split(b'CONTEXT: ', 1)[1]
if PY3:
pc_data = cPickle.loads(pc_data, encoding='bytes')
else:
pc_data = cPickle.loads(pc_data)
pc = PlayContext()
pc.deserialize(pc_data)
try:
self.connection.update_play_context(pc)
except AttributeError:
pass
return (0, 'ok', '')
def do_RUN(self, data):
timeout = self.play_context.timeout
while bool(timeout):
if os.path.exists(self.socket_path):
break
time.sleep(1)
timeout -= 1
socket_bytes = to_bytes(self.socket_path, errors='surrogate_or_strict')
return 0, b'\n#SOCKET_PATH#: %s\n' % socket_bytes, ''
def communicate(sock, data):
send_data(sock, data)
rc = int(recv_data(sock), 10)
stdout = recv_data(sock)
stderr = recv_data(sock)
return (rc, stdout, stderr)
except Exception as e:
pass
os.remove(self.path)
def main():
# Need stdin as a byte stream
if PY3:
stdin = sys.stdin.buffer
else:
stdin = sys.stdin
try:
# read the play context data via stdin, which means depickling it
# FIXME: as noted above, we will probably need to deserialize the
# connection loader here as well at some point, otherwise this
# won't find role- or playbook-based connection plugins
cur_line = stdin.readline()
init_data = b''
while cur_line.strip() != b'#END_INIT#':
if cur_line == b'':
raise Exception("EOF found before init data was complete")
cur_line = sys.stdin.readline()
init_data = ''
while cur_line.strip() != '#END_INIT#':
if cur_line == '':
raise Exception("EOL found before init data was complete")
init_data += cur_line
cur_line = stdin.readline()
if PY3:
pc_data = cPickle.loads(init_data, encoding='bytes')
else:
pc_data = cPickle.loads(init_data)
cur_line = sys.stdin.readline()
src = BytesIO(to_bytes(init_data))
pc_data = cPickle.load(src)
pc = PlayContext()
pc.deserialize(pc_data)
except Exception as e:
# FIXME: better error message/handling/logging
sys.stderr.write(traceback.format_exc())
sys.exit("FAIL: %s" % e)
ssh = connection_loader.get('ssh', class_only=True)
cp = ssh._create_control_path(pc.remote_addr, pc.port, pc.remote_user, pc.connection)
m = ssh._create_control_path(pc.remote_addr, pc.port, pc.remote_user)
# create the persistent connection dir if need be and create the paths
# which we will be using later
tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR)
tmp_path = unfrackpath("$HOME/.ansible/pc")
makedirs_safe(tmp_path)
lock_path = unfrackpath("%s/.ansible_pc_lock" % tmp_path)
socket_path = unfrackpath(cp % dict(directory=tmp_path))
lk_path = unfrackpath("%s/.ansible_pc_lock" % tmp_path)
sf_path = unfrackpath(m % dict(directory=tmp_path))
# if the socket file doesn't exist, spin up the daemon process
lock_fd = os.open(lock_path, os.O_RDWR | os.O_CREAT, 0o600)
lock_fd = os.open(lk_path, os.O_RDWR|os.O_CREAT, 0o600)
fcntl.lockf(lock_fd, fcntl.LOCK_EX)
if not os.path.exists(socket_path):
if not os.path.exists(sf_path):
pid = do_fork()
if pid == 0:
rc = 0
try:
server = Server(socket_path, pc)
server = Server(sf_path, pc)
except AnsibleConnectionFailure as exc:
display.display('connecting to host %s returned an error' % pc.remote_addr, log_only=True)
display.display(str(exc), log_only=True)
@ -329,57 +311,51 @@ def main():
sys.exit(rc)
else:
display.display('re-using existing socket for %s@%s:%s' % (pc.remote_user, pc.remote_addr, pc.port), log_only=True)
fcntl.lockf(lock_fd, fcntl.LOCK_UN)
os.close(lock_fd)
timeout = pc.timeout
while bool(timeout):
if os.path.exists(socket_path):
display.vvvv('connected to local socket in %s' % (pc.timeout - timeout), pc.remote_addr)
break
time.sleep(1)
timeout -= 1
else:
raise AnsibleConnectionFailure('timeout waiting for local socket', pc.remote_addr)
# now connect to the daemon process
# FIXME: if the socket file existed but the daemonized process was killed,
# the connection will timeout here. Need to make this more resilient.
while True:
data = stdin.readline()
if data == b'':
rc = 0
while rc == 0:
data = sys.stdin.readline()
if data == '':
break
if data.strip() == b'':
if data.strip() == '':
continue
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
connect_retry_timeout = C.PERSISTENT_CONNECT_RETRY_TIMEOUT
while bool(connect_retry_timeout):
sf = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
attempts = 1
while True:
try:
sock.connect(socket_path)
sf.connect(sf_path)
break
except socket.error:
time.sleep(1)
connect_retry_timeout -= 1
else:
display.display('connect retry timeout expired, unable to connect to control socket', pc.remote_addr, pc.remote_user, log_only=True)
display.display('persistent_connect_retry_timeout is %s secs' % (C.PERSISTENT_CONNECT_RETRY_TIMEOUT), pc.remote_addr, pc.remote_user, log_only=True)
sys.stderr.write('failed to connect to control socket')
sys.exit(255)
# FIXME: better error handling/logging/message here
time.sleep(C.PERSISTENT_CONNECT_INTERVAL)
attempts += 1
if attempts > C.PERSISTENT_CONNECT_RETRIES:
display.display('number of connection attempts exceeded, unable to connect to control socket', pc.remote_addr, pc.remote_user, log_only=True)
display.display('persistent_connect_interval=%s, persistent_connect_retries=%s' % (C.PERSISTENT_CONNECT_INTERVAL, C.PERSISTENT_CONNECT_RETRIES), pc.remote_addr, pc.remote_user, log_only=True)
sys.stderr.write('failed to connect to control socket')
sys.exit(255)
# send the play_context back into the connection so the connection
# can handle any privilege escalation activities
pc_data = b'CONTEXT: %s' % init_data
communicate(sock, pc_data)
pc_data = 'CONTEXT: %s' % src.getvalue()
send_data(sf, to_bytes(pc_data))
src.close()
rc, stdout, stderr = communicate(sock, data.strip())
send_data(sf, to_bytes(data.strip()))
rc = int(recv_data(sf), 10)
stdout = recv_data(sf)
stderr = recv_data(sf)
sys.stdout.write(to_native(stdout))
sys.stderr.write(to_native(stderr))
sock.close()
sf.close()
break
sys.exit(rc)

View File

@ -1 +0,0 @@
ansible

View File

@ -1,26 +1,16 @@
contrib
-------
Files here provide an extension mechanism for Ansible similar to plugins. They are not maintained by the Ansible core team or installed with Ansible.
inventory
=========
Before 2.4 introduced inventory plugins, inventory scripts were the only way to provide sources that were not built into Ansible. Inventory scripts allow you to store your hosts, groups, and variables in any way you like.
Inventory scripts allow you to store your hosts, groups, and variables in any way
you like. Examples include discovering inventory from EC2 or pulling it from
Cobbler. These could also be used to interface with LDAP or database.
Starting with Ansible version 2.4, they are enabled via the 'script' inventory plugin.
Examples of use include discovering inventory from EC2 or pulling it from Cobbler. These could also be used to interface with LDAP or the database.
`chmod +x` an inventory plugin and either name it `/etc/ansible/hosts` or use `ansible -i /path/to/inventory/script`. You might also need to copy a configuration file with the same name and/or set environment variables. The scripts or configuration files can provide more details.
vault
=====
If the file passed to `--vault-password-file` has the executable bit set, Ansible will execute it and use the stdout of that execution as 'the secret'.
Vault scripts provided here use this facility to retrieve the vault secret from a number of sources.
`chmod +x` an inventory plugin and either name it `/etc/ansible/hosts` or use `ansible -i /path/to/inventory/script`. You might also need to copy a configuration
file with the same name and/or set environment variables, the scripts or configuration
files have more details.
contributions welcome
=====================
Send in pull requests to add scripts of your own. The sky is the limit!
Send in pull requests to add plugins of your own. The sky is the limit!

View File

@ -53,68 +53,64 @@ except ImportError:
from ansible.module_utils.urls import open_url
def api_get(link, config):
try:
if link is None:
url = config.get('api', 'uri') + config.get('api', 'login_path')
headers = {"Accept": config.get('api', 'login_type')}
url = config.get('api','uri') + config.get('api','login_path')
headers = {"Accept": config.get('api','login_type')}
else:
url = link['href'] + '?limit=0'
headers = {"Accept": link['type']}
result = open_url(url, headers=headers, url_username=config.get('auth', 'apiuser').replace('\n', ''),
url_password=config.get('auth', 'apipass').replace('\n', ''))
result = open_url(url, headers=headers, url_username=config.get('auth','apiuser').replace('\n', ''),
url_password=config.get('auth','apipass').replace('\n', ''))
return json.loads(result.read())
except:
return None
def save_cache(data, config):
''' saves item to cache '''
dpath = config.get('cache', 'cache_dir')
dpath = config.get('cache','cache_dir')
try:
cache = open('/'.join([dpath, 'inventory']), 'w')
cache = open('/'.join([dpath,'inventory']), 'w')
cache.write(json.dumps(data))
cache.close()
except IOError as e:
pass # not really sure what to do here
pass # not really sure what to do here
def get_cache(cache_item, config):
''' returns cached item '''
dpath = config.get('cache', 'cache_dir')
dpath = config.get('cache','cache_dir')
inv = {}
try:
cache = open('/'.join([dpath, 'inventory']), 'r')
cache = open('/'.join([dpath,'inventory']), 'r')
inv = cache.read()
cache.close()
except IOError as e:
pass # not really sure what to do here
pass # not really sure what to do here
return inv
def cache_available(config):
''' checks if we have a 'fresh' cache available for item requested '''
if config.has_option('cache', 'cache_dir'):
dpath = config.get('cache', 'cache_dir')
if config.has_option('cache','cache_dir'):
dpath = config.get('cache','cache_dir')
try:
existing = os.stat('/'.join([dpath, 'inventory']))
existing = os.stat( '/'.join([dpath,'inventory']))
except:
# cache doesn't exist or isn't accessible
return False
if config.has_option('cache', 'cache_max_age'):
maxage = config.get('cache', 'cache_max_age')
if (int(time.time()) - int(existing.st_mtime)) <= int(maxage):
if ((int(time.time()) - int(existing.st_mtime)) <= int(maxage)):
return True
return False
def generate_inv_from_api(enterprise_entity, config):
def generate_inv_from_api(enterprise_entity,config):
try:
inventory['all'] = {}
inventory['all']['children'] = []
@ -122,22 +118,22 @@ def generate_inv_from_api(enterprise_entity, config):
inventory['_meta'] = {}
inventory['_meta']['hostvars'] = {}
enterprise = api_get(enterprise_entity, config)
vms_entity = next(link for link in enterprise['links'] if link['rel'] == 'virtualmachines')
vms = api_get(vms_entity, config)
enterprise = api_get(enterprise_entity,config)
vms_entity = next(link for link in (enterprise['links']) if (link['rel']=='virtualmachines'))
vms = api_get(vms_entity,config)
for vmcollection in vms['collection']:
for link in vmcollection['links']:
if link['rel'] == 'virtualappliance':
vm_vapp = link['title'].replace('[', '').replace(']', '').replace(' ', '_')
vm_vapp = link['title'].replace('[','').replace(']','').replace(' ','_')
elif link['rel'] == 'virtualdatacenter':
vm_vdc = link['title'].replace('[', '').replace(']', '').replace(' ', '_')
vm_vdc = link['title'].replace('[','').replace(']','').replace(' ','_')
elif link['rel'] == 'virtualmachinetemplate':
vm_template = link['title'].replace('[', '').replace(']', '').replace(' ', '_')
vm_template = link['title'].replace('[','').replace(']','').replace(' ','_')
# From abiquo.ini: Only adding to inventory VMs with public IP
if config.getboolean('defaults', 'public_ip_only') is True:
for link in vmcollection['links']:
if link['type'] == 'application/vnd.abiquo.publicip+json' and link['rel'] == 'ip':
if (link['type']=='application/vnd.abiquo.publicip+json' and link['rel']=='ip'):
vm_nic = link['title']
break
else:
@ -170,10 +166,10 @@ def generate_inv_from_api(enterprise_entity, config):
inventory[vm_template]['children'] = []
inventory[vm_template]['hosts'] = []
if config.getboolean('defaults', 'get_metadata') is True:
meta_entity = next(link for link in vmcollection['links'] if link['rel'] == 'metadata')
meta_entity = next(link for link in (vmcollection['links']) if (link['rel']=='metadata'))
try:
metadata = api_get(meta_entity, config)
if (config.getfloat("api", "version") >= 3.0):
metadata = api_get(meta_entity,config)
if (config.getfloat("api","version") >= 3.0):
vm_metadata = metadata['metadata']
else:
vm_metadata = metadata['metadata']['metadata']
@ -191,8 +187,7 @@ def generate_inv_from_api(enterprise_entity, config):
return inventory
except Exception as e:
# Return empty hosts output
return {'all': {'hosts': []}, '_meta': {'hostvars': {}}}
return { 'all': {'hosts': []}, '_meta': { 'hostvars': {} } }
def get_inventory(enterprise, config):
''' Reads the inventory from cache or Abiquo api '''
@ -202,12 +197,11 @@ def get_inventory(enterprise, config):
else:
default_group = os.path.basename(sys.argv[0]).rstrip('.py')
# MAKE ABIQUO API CALLS #
inv = generate_inv_from_api(enterprise, config)
inv = generate_inv_from_api(enterprise,config)
save_cache(inv, config)
return json.dumps(inv)
if __name__ == '__main__':
inventory = {}
enterprise = {}
@ -220,8 +214,8 @@ if __name__ == '__main__':
break
try:
login = api_get(None, config)
enterprise = next(link for link in login['links'] if link['rel'] == 'enterprise')
login = api_get(None,config)
enterprise = next(link for link in (login['links']) if (link['rel']=='enterprise'))
except Exception as e:
enterprise = None

View File

@ -82,6 +82,7 @@ class LibcloudInventory(object):
print(data_to_print)
def is_cache_valid(self):
''' Determines if the cache files have expired, or if it is still valid '''
@ -94,6 +95,7 @@ class LibcloudInventory(object):
return False
def read_settings(self):
''' Reads the settings from the libcloud.ini file '''
@ -106,17 +108,17 @@ class LibcloudInventory(object):
raise ValueError('libcloud.ini file must contain a [driver] section')
if config.has_option('driver', 'provider'):
self.provider = config.get('driver', 'provider')
self.provider = config.get('driver','provider')
else:
raise ValueError('libcloud.ini does not have a provider defined')
if config.has_option('driver', 'key'):
self.key = config.get('driver', 'key')
self.key = config.get('driver','key')
else:
raise ValueError('libcloud.ini does not have a key defined')
if config.has_option('driver', 'secret'):
self.secret = config.get('driver', 'secret')
self.secret = config.get('driver','secret')
else:
raise ValueError('libcloud.ini does not have a secret defined')
@ -144,6 +146,7 @@ class LibcloudInventory(object):
self.cache_path_index = cache_path + "/ansible-libcloud.index"
self.cache_max_age = config.getint('cache', 'cache_max_age')
def parse_cli_args(self):
'''
Command line argument processing
@ -151,13 +154,14 @@ class LibcloudInventory(object):
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on libcloud supported providers')
parser.add_argument('--list', action='store_true', default=True,
help='List instances (default: True)')
help='List instances (default: True)')
parser.add_argument('--host', action='store',
help='Get all the variables about a specific instance')
help='Get all the variables about a specific instance')
parser.add_argument('--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests to libcloud supported providers (default: False - use cache files)')
help='Force refresh of cache by making API requests to libcloud supported providers (default: False - use cache files)')
self.args = parser.parse_args()
def do_api_calls_update_cache(self):
'''
Do API calls to a location, and save data in cache files
@ -168,6 +172,7 @@ class LibcloudInventory(object):
self.write_to_cache(self.inventory, self.cache_path_cache)
self.write_to_cache(self.index, self.cache_path_index)
def get_nodes(self):
'''
Gets the list of all nodes
@ -176,6 +181,7 @@ class LibcloudInventory(object):
for node in self.conn.list_nodes():
self.add_node(node)
def get_node(self, node_id):
'''
Gets details about a specific node
@ -183,6 +189,7 @@ class LibcloudInventory(object):
return [node for node in self.conn.list_nodes() if node.id == node_id][0]
def add_node(self, node):
'''
Adds a node to the inventory and index, as long as it is
@ -237,10 +244,10 @@ class LibcloudInventory(object):
# Need to load index from cache
self.load_index_from_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# try updating the cache
self.do_api_calls_update_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# host migh not exist anymore
return self.json_format_dict({}, True)
@ -248,7 +255,8 @@ class LibcloudInventory(object):
node = self.get_node(node_id)
instance_vars = {}
for key, value in vars(node).items():
for key in vars(instance):
value = getattr(instance, key)
key = self.to_safe('ec2_' + key)
# Handle complex types
@ -275,12 +283,13 @@ class LibcloudInventory(object):
else:
pass
# TODO Product codes if someone finds them useful
# print(key)
# print(type(value))
# print(value)
#print(key)
#print(type(value))
#print(value)
return self.json_format_dict(instance_vars, True)
def push(self, my_dict, key, element):
'''
Pushed an element onto an array that may not have been defined in
@ -292,6 +301,7 @@ class LibcloudInventory(object):
else:
my_dict[key] = [element]
def get_inventory_from_cache(self):
'''
Reads the inventory from the cache file and returns it as a JSON
@ -302,6 +312,7 @@ class LibcloudInventory(object):
json_inventory = cache.read()
return json_inventory
def load_index_from_cache(self):
'''
Reads the index from the cache file sets self.index
@ -311,6 +322,7 @@ class LibcloudInventory(object):
json_index = cache.read()
self.index = json.loads(json_index)
def write_to_cache(self, data, filename):
'''
Writes data in JSON format to a file
@ -321,6 +333,7 @@ class LibcloudInventory(object):
cache.write(json_data)
cache.close()
def to_safe(self, word):
'''
Converts 'bad' characters in a string to underscores so they can be
@ -329,6 +342,7 @@ class LibcloudInventory(object):
return re.sub("[^A-Za-z0-9\-]", "_", word)
def json_format_dict(self, data, pretty=False):
'''
Converts a dict to a JSON object and dumps it as a formatted
@ -340,7 +354,6 @@ class LibcloudInventory(object):
else:
return json.dumps(data)
def main():
LibcloudInventory()

View File

@ -27,7 +27,7 @@ of hosts, groups the hosts are in, and even variables to assign to each host.
To use this:
- copy this file over /etc/ansible/hosts and chmod +x the file.
- Copy both files (.py and .ini) in your preferred directory
- Copy both files (.py and .ini) in your prefered directory
More information about Ansible Dynamic Inventory here
http://unix.stackexchange.com/questions/205479/in-ansible-dynamic-inventory-json-can-i-render-hostvars-based-on-the-hostname
@ -49,25 +49,23 @@ This script has been inspired by the cobbler.py inventory. thanks
Author: Damien Garros (@dgarros)
Version: 0.2.0
"""
import json
import os
import argparse
import re
import sys
try:
import argparse
HAS_ARGPARSE = True
except ImportError:
HAS_ARGPARSE = False
from ansible.compat.six.moves import configparser
try:
from apstra.aosom.session import Session
HAS_AOS_PYEZ = True
except ImportError:
HAS_AOS_PYEZ = False
from ansible.module_utils.six.moves import configparser
try:
import json
except ImportError:
import simplejson as json
"""
##
@ -280,12 +278,10 @@ Expected output format in Device mode
}
"""
def fail(msg):
sys.stderr.write("%s\n" % msg)
sys.exit(1)
class AosInventory(object):
def __init__(self):
@ -294,8 +290,6 @@ class AosInventory(object):
if not HAS_AOS_PYEZ:
raise Exception('aos-pyez is not installed. Please see details here: https://github.com/Apstra/aos-pyez')
if not HAS_ARGPARSE:
raise Exception('argparse is not installed. Please install the argparse library or upgrade to python-2.7')
# Initialize inventory
self.inventory = dict() # A list of groups and the hosts in that group
@ -309,10 +303,10 @@ class AosInventory(object):
# ----------------------------------------------------
# Open session to AOS
# ----------------------------------------------------
aos = Session(server=self.aos_server,
port=self.aos_server_port,
user=self.aos_username,
passwd=self.aos_password)
aos = Session( server=self.aos_server,
port=self.aos_server_port,
user=self.aos_username,
passwd=self.aos_password)
aos.login()
@ -320,10 +314,10 @@ class AosInventory(object):
self.add_var_to_group('all', 'aos_session', aos.session)
# Add the AOS server itself in the inventory
self.add_host_to_group("all", 'aos')
self.add_var_to_host("aos", "ansible_ssh_host", self.aos_server)
self.add_var_to_host("aos", "ansible_ssh_pass", self.aos_password)
self.add_var_to_host("aos", "ansible_ssh_user", self.aos_username)
self.add_host_to_group("all", 'aos' )
self.add_var_to_host("aos", "ansible_ssh_host", self.aos_server )
self.add_var_to_host("aos", "ansible_ssh_pass", self.aos_password )
self.add_var_to_host("aos", "ansible_ssh_user", self.aos_username )
# ----------------------------------------------------
# Build the inventory
@ -342,7 +336,7 @@ class AosInventory(object):
for dev_name, dev_id in bp.params['devices'].value.items():
self.add_host_to_group('all', dev_name)
device = aos.Devices.find(uid=dev_id)
device = aos.Devices.find( uid=dev_id)
if 'facts' in device.value.keys():
self.add_device_facts_to_var(dev_name, device)
@ -350,7 +344,7 @@ class AosInventory(object):
# Define admin State and Status
if 'user_config' in device.value.keys():
if 'admin_state' in device.value['user_config'].keys():
self.add_var_to_host(dev_name, 'admin_state', device.value['user_config']['admin_state'])
self.add_var_to_host(dev_name, 'admin_state', device.value['user_config']['admin_state'] )
self.add_device_status_to_var(dev_name, device)
@ -466,30 +460,35 @@ class AosInventory(object):
except:
if 'AOS_SERVER' in os.environ.keys():
self.aos_server = os.environ['AOS_SERVER']
pass
try:
self.aos_server_port = config.get('aos', 'port')
except:
if 'AOS_PORT' in os.environ.keys():
self.aos_server_port = os.environ['AOS_PORT']
pass
try:
self.aos_username = config.get('aos', 'username')
except:
if 'AOS_USERNAME' in os.environ.keys():
self.aos_username = os.environ['AOS_USERNAME']
pass
try:
self.aos_password = config.get('aos', 'password')
except:
if 'AOS_PASSWORD' in os.environ.keys():
self.aos_password = os.environ['AOS_PASSWORD']
pass
try:
self.aos_blueprint = config.get('aos', 'blueprint')
except:
if 'AOS_BLUEPRINT' in os.environ.keys():
self.aos_blueprint = os.environ['AOS_BLUEPRINT']
pass
try:
if config.get('aos', 'blueprint_interface') in ['false', 'no']:
@ -497,6 +496,7 @@ class AosInventory(object):
except:
pass
def parse_cli_args(self):
""" Command line argument processing """
@ -554,7 +554,7 @@ class AosInventory(object):
'ansible_ssh_host',
device.value['facts']['mgmt_ipaddr'])
self.add_var_to_host(device_name, 'id', device.id)
self.add_var_to_host(device_name,'id', device.id)
# self.add_host_to_group('all', device.name)
for key, value in device.value['facts'].items():

View File

@ -49,7 +49,6 @@ Command line arguments:
- tenant
- ad_user
- password
- cloud_environment
Environment variables:
- AZURE_PROFILE
@ -59,7 +58,6 @@ Environment variables:
- AZURE_TENANT
- AZURE_AD_USER
- AZURE_PASSWORD
- AZURE_CLOUD_ENVIRONMENT
Run for Specific Host
-----------------------
@ -192,27 +190,22 @@ import json
import os
import re
import sys
import inspect
import traceback
from packaging.version import Version
from os.path import expanduser
import ansible.module_utils.six.moves.urllib.parse as urlparse
HAS_AZURE = True
HAS_AZURE_EXC = None
try:
from msrestazure.azure_exceptions import CloudError
from msrestazure import azure_cloud
from azure.mgmt.compute import __version__ as azure_compute_version
from azure.common import AzureMissingResourceHttpError, AzureHttpError
from azure.common.credentials import ServicePrincipalCredentials, UserPassCredentials
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.resource.resources import ResourceManagementClient
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.network.network_management_client import NetworkManagementClient
from azure.mgmt.resource.resources.resource_management_client import ResourceManagementClient
from azure.mgmt.compute.compute_management_client import ComputeManagementClient
except ImportError as exc:
HAS_AZURE_EXC = exc
HAS_AZURE = False
@ -225,8 +218,7 @@ AZURE_CREDENTIAL_ENV_MAPPING = dict(
secret='AZURE_SECRET',
tenant='AZURE_TENANT',
ad_user='AZURE_AD_USER',
password='AZURE_PASSWORD',
cloud_environment='AZURE_CLOUD_ENVIRONMENT',
password='AZURE_PASSWORD'
)
AZURE_CONFIG_SETTINGS = dict(
@ -240,7 +232,7 @@ AZURE_CONFIG_SETTINGS = dict(
group_by_tag='AZURE_GROUP_BY_TAG'
)
AZURE_MIN_VERSION = "2.0.0"
AZURE_MIN_VERSION = "0.30.0rc5"
def azure_id_to_dict(id):
@ -257,7 +249,6 @@ class AzureRM(object):
def __init__(self, args):
self._args = args
self._cloud_environment = None
self._compute_client = None
self._resource_client = None
self._network_client = None
@ -271,26 +262,6 @@ class AzureRM(object):
self.fail("Failed to get credentials. Either pass as parameters, set environment variables, "
"or define a profile in ~/.azure/credentials.")
# if cloud_environment specified, look up/build Cloud object
raw_cloud_env = self.credentials.get('cloud_environment')
if not raw_cloud_env:
self._cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD # SDK default
else:
# try to look up "well-known" values via the name attribute on azure_cloud members
all_clouds = [x[1] for x in inspect.getmembers(azure_cloud) if isinstance(x[1], azure_cloud.Cloud)]
matched_clouds = [x for x in all_clouds if x.name == raw_cloud_env]
if len(matched_clouds) == 1:
self._cloud_environment = matched_clouds[0]
elif len(matched_clouds) > 1:
self.fail("Azure SDK failure: more than one cloud matched for cloud_environment name '{0}'".format(raw_cloud_env))
else:
if not urlparse.urlparse(raw_cloud_env).scheme:
self.fail("cloud_environment must be an endpoint discovery URL or one of {0}".format([x.name for x in all_clouds]))
try:
self._cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(raw_cloud_env)
except Exception as e:
self.fail("cloud_environment {0} could not be resolved: {1}".format(raw_cloud_env, e.message))
if self.credentials.get('subscription_id', None) is None:
self.fail("Credentials did not include a subscription_id value.")
self.log("setting subscription_id")
@ -301,23 +272,16 @@ class AzureRM(object):
self.credentials.get('tenant') is not None:
self.azure_credentials = ServicePrincipalCredentials(client_id=self.credentials['client_id'],
secret=self.credentials['secret'],
tenant=self.credentials['tenant'],
cloud_environment=self._cloud_environment)
tenant=self.credentials['tenant'])
elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
tenant = self.credentials.get('tenant')
if not tenant:
tenant = 'common'
self.azure_credentials = UserPassCredentials(self.credentials['ad_user'],
self.credentials['password'],
tenant=tenant,
cloud_environment=self._cloud_environment)
self.azure_credentials = UserPassCredentials(self.credentials['ad_user'], self.credentials['password'])
else:
self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
"Credentials must include client_id, secret and tenant or ad_user and password.")
def log(self, msg):
if self.debug:
print(msg + u'\n')
print (msg + u'\n')
def fail(self, msg):
raise Exception(msg)
@ -377,10 +341,6 @@ class AzureRM(object):
self.log('Received credentials from parameters.')
return arg_credentials
if arg_credentials['ad_user'] is not None:
self.log('Received credentials from parameters.')
return arg_credentials
# try environment
env_credentials = self._get_env_credentials()
if env_credentials:
@ -412,12 +372,7 @@ class AzureRM(object):
def network_client(self):
self.log('Getting network client')
if not self._network_client:
self._network_client = NetworkManagementClient(
self.azure_credentials,
self.subscription_id,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2017-06-01'
)
self._network_client = NetworkManagementClient(self.azure_credentials, self.subscription_id)
self._register('Microsoft.Network')
return self._network_client
@ -425,24 +380,14 @@ class AzureRM(object):
def rm_client(self):
self.log('Getting resource manager client')
if not self._resource_client:
self._resource_client = ResourceManagementClient(
self.azure_credentials,
self.subscription_id,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2017-05-10'
)
self._resource_client = ResourceManagementClient(self.azure_credentials, self.subscription_id)
return self._resource_client
@property
def compute_client(self):
self.log('Getting compute client')
if not self._compute_client:
self._compute_client = ComputeManagementClient(
self.azure_credentials,
self.subscription_id,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2017-03-30'
)
self._compute_client = ComputeManagementClient(self.azure_credentials, self.subscription_id)
self._register('Microsoft.Compute')
return self._compute_client
@ -495,7 +440,7 @@ class AzureInventory(object):
self.include_powerstate = False
self.get_inventory()
print(self._json_format_dict(pretty=self._args.pretty))
print (self._json_format_dict(pretty=self._args.pretty))
sys.exit(0)
def _parse_cli_args(self):
@ -503,13 +448,13 @@ class AzureInventory(object):
parser = argparse.ArgumentParser(
description='Produce an Ansible Inventory file for an Azure subscription')
parser.add_argument('--list', action='store_true', default=True,
help='List instances (default: True)')
help='List instances (default: True)')
parser.add_argument('--debug', action='store_true', default=False,
help='Send debug messages to STDOUT')
help='Send debug messages to STDOUT')
parser.add_argument('--host', action='store',
help='Get all information about an instance')
help='Get all information about an instance')
parser.add_argument('--pretty', action='store_true', default=False,
help='Pretty print JSON output(default: False)')
help='Pretty print JSON output(default: False)')
parser.add_argument('--profile', action='store',
help='Azure profile contained in ~/.azure/credentials')
parser.add_argument('--subscription_id', action='store',
@ -520,12 +465,10 @@ class AzureInventory(object):
help='Azure Client Secret')
parser.add_argument('--tenant', action='store',
help='Azure Tenant Id')
parser.add_argument('--ad_user', action='store',
parser.add_argument('--ad-user', action='store',
help='Active Directory User')
parser.add_argument('--password', action='store',
help='password')
parser.add_argument('--cloud_environment', action='store',
help='Azure Cloud Environment name or metadata discovery URL')
parser.add_argument('--resource-groups', action='store',
help='Return inventory for comma separated list of resource group names')
parser.add_argument('--tags', action='store',
@ -543,7 +486,8 @@ class AzureInventory(object):
try:
virtual_machines = self._compute_client.virtual_machines.list(resource_group)
except Exception as exc:
sys.exit("Error: fetching virtual machines for resource group {0} - {1}".format(resource_group, str(exc)))
sys.exit("Error: fetching virtual machines for resource group {0} - {1}".format(resource_group,
str(exc)))
if self._args.host or self.tags:
selected_machines = self._selected_machines(virtual_machines)
self._load_machines(selected_machines)
@ -566,7 +510,7 @@ class AzureInventory(object):
for machine in machines:
id_dict = azure_id_to_dict(machine.id)
# TODO - The API is returning an ID value containing resource group name in ALL CAPS. If/when it gets
#TODO - The API is returning an ID value containing resource group name in ALL CAPS. If/when it gets
# fixed, we should remove the .lower(). Opened Issue
# #574: https://github.com/Azure/azure-sdk-for-python/issues/574
resource_group = id_dict['resourceGroups'].lower()
@ -594,7 +538,7 @@ class AzureInventory(object):
mac_address=None,
plan=(machine.plan.name if machine.plan else None),
virtual_machine_size=machine.hardware_profile.vm_size,
computer_name=(machine.os_profile.computer_name if machine.os_profile else None),
computer_name=machine.os_profile.computer_name,
provisioning_state=machine.provisioning_state,
)
@ -615,7 +559,7 @@ class AzureInventory(object):
)
# Add windows details
if machine.os_profile is not None and machine.os_profile.windows_configuration is not None:
if machine.os_profile.windows_configuration is not None:
host_vars['windows_auto_updates_enabled'] = \
machine.os_profile.windows_configuration.enable_automatic_updates
host_vars['windows_timezone'] = machine.os_profile.windows_configuration.time_zone
@ -846,10 +790,13 @@ class AzureInventory(object):
def main():
if not HAS_AZURE:
sys.exit("The Azure python sdk is not installed (try `pip install 'azure>={0}' --upgrade`) - {1}".format(AZURE_MIN_VERSION, HAS_AZURE_EXC))
sys.exit("The Azure python sdk is not installed (try `pip install 'azure>=2.0.0rc5' --upgrade`) - {0}".format(HAS_AZURE_EXC))
if Version(azure_compute_version) < Version(AZURE_MIN_VERSION):
sys.exit("Expecting azure.mgmt.compute.__version__ to be {0}. Found version {1} "
"Do you have Azure >= 2.0.0rc5 installed? (try `pip install 'azure>=2.0.0rc5' --upgrade`)".format(AZURE_MIN_VERSION, azure_compute_version))
AzureInventory()
if __name__ == '__main__':
main()

View File

@ -32,13 +32,11 @@ included, provided the requesting user belongs to it.
The following variables are established for every host. They can be retrieved from the hostvars
dictionary.
- brook_pid: str
- brook_name: str
- brook_description: str
- brook_project: str
- brook_template: str
- brook_region: str
- brook_zone: str
- brook_status: str
- brook_tags: list(str)
- brook_internal_ips: list(str)
@ -72,7 +70,7 @@ Support:
This script is tested on Python 2.7 and 3.4. It may work on other versions though.
Author: Francisco Ros <fjros@doalitic.com>
Version: 0.2
Version: 0.1
"""
@ -124,8 +122,9 @@ class BrookInventory:
self.project_id = config.get('brook', 'project_id')
if not self.api_token:
sys.exit('You must provide (at least) your Brook.io API token to generate the dynamic '
'inventory.')
print('You must provide (at least) your Brook.io API token to generate the dynamic '
'inventory.')
sys.exit(1)
def get_api_client(self):
"""Authenticate user via the provided credentials and return the corresponding API client.
@ -169,8 +168,8 @@ class BrookInventory:
for project_id in projects:
project = projects_api.show_project(project_id=project_id)
for instance in instances_api.index_instances(project_id=project_id):
# Get template used for this instance if known
template = templates_api.show_template(template_id=instance.template) if instance.template else None
# Get template used for this instance
template = templates_api.show_template(template_id=instance.template)
# Update hostvars
try:
@ -213,13 +212,11 @@ class BrookInventory:
"""
hostvars = instance.to_dict()
hostvars['brook_pid'] = hostvars.pop('pid')
hostvars['brook_name'] = hostvars.pop('name')
hostvars['brook_description'] = hostvars.pop('description')
hostvars['brook_project'] = hostvars.pop('project')
hostvars['brook_template'] = hostvars.pop('template')
hostvars['brook_region'] = hostvars.pop('region')
hostvars['brook_zone'] = hostvars.pop('zone')
hostvars['brook_created_at'] = hostvars.pop('created_at')
hostvars['brook_updated_at'] = hostvars.pop('updated_at')
del hostvars['id']
@ -230,7 +227,7 @@ class BrookInventory:
# Substitute identifiers for names
#
hostvars['brook_project'] = project.name
hostvars['brook_template'] = template.name if template else None
hostvars['brook_template'] = template.name
# Retrieve instance state
#

View File

@ -110,9 +110,9 @@ class CobblerInventory(object):
if self.args.host:
data_to_print += self.get_host_info()
else:
self.inventory['_meta'] = {'hostvars': {}}
self.inventory['_meta'] = { 'hostvars': {} }
for hostname in self.cache:
self.inventory['_meta']['hostvars'][hostname] = {'cobbler': self.cache[hostname]}
self.inventory['_meta']['hostvars'][hostname] = {'cobbler': self.cache[hostname] }
data_to_print += self.json_format_dict(self.inventory, True)
print(data_to_print)
@ -179,7 +179,7 @@ class CobblerInventory(object):
for host in data:
# Get the FQDN for the host and add it to the right groups
dns_name = host['hostname'] # None
dns_name = host['hostname'] #None
ksmeta = None
interfaces = host['interfaces']
# hostname is often empty for non-static IP hosts
@ -190,7 +190,7 @@ class CobblerInventory(object):
if this_dns_name is not None and this_dns_name is not "":
dns_name = this_dns_name
if dns_name == '' or dns_name is None:
if dns_name == '':
continue
status = host['status']
@ -229,11 +229,11 @@ class CobblerInventory(object):
# Need to load index from cache
self.load_cache_from_cache()
if self.args.host not in self.cache:
if not self.args.host in self.cache:
# try updating the cache
self.update_cache()
if self.args.host not in self.cache:
if not self.args.host in self.cache:
# host might not exist anymore
return self.json_format_dict({}, True)

View File

@ -74,6 +74,7 @@ import re
import sys
from time import time
import traceback
import urllib
try:
import json
@ -81,11 +82,9 @@ except ImportError:
import simplejson as json
from six import iteritems
from six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import open_url
class CollinsDefaults(object):
ASSETS_API_ENDPOINT = '%s/api/assets'
SPECIAL_ATTRIBUTES = set([
@ -118,7 +117,7 @@ class CollinsInventory(object):
self.parse_cli_args()
logging.basicConfig(format=CollinsDefaults.LOG_FORMAT,
filename=self.log_location)
filename=self.log_location)
self.log = logging.getLogger('CollinsInventory')
def _asset_get_attribute(self, asset, attrib):
@ -169,14 +168,14 @@ class CollinsInventory(object):
print(data_to_print)
return successful
def find_assets(self, attributes=None, operation='AND'):
def find_assets(self, attributes = {}, operation = 'AND'):
""" Obtains Collins assets matching the provided attributes. """
attributes = {} if attributes is None else attributes
# Formats asset search query to locate assets matching attributes, using
# the CQL search feature as described here:
# http://tumblr.github.io/collins/recipes.html
attributes_query = ['='.join(attr_pair) for attr_pair in iteritems(attributes)]
attributes_query = [ '='.join(attr_pair)
for attr_pair in iteritems(attributes) ]
query_parameters = {
'details': ['True'],
'operation': [operation],
@ -191,18 +190,19 @@ class CollinsInventory(object):
# Locates all assets matching the provided query, exhausting pagination.
while True:
if num_retries == self.collins_max_retries:
raise MaxRetriesError("Maximum of %s retries reached; giving up" % self.collins_max_retries)
raise MaxRetriesError("Maximum of %s retries reached; giving up" % \
self.collins_max_retries)
query_parameters['page'] = cur_page
query_url = "%s?%s" % (
(CollinsDefaults.ASSETS_API_ENDPOINT % self.collins_host),
urlencode(query_parameters, doseq=True)
urllib.urlencode(query_parameters, doseq=True)
)
try:
response = open_url(query_url,
timeout=self.collins_timeout_secs,
url_username=self.collins_username,
url_password=self.collins_password,
force_basic_auth=True)
timeout=self.collins_timeout_secs,
url_username=self.collins_username,
url_password=self.collins_password,
force_basic_auth=True)
json_response = json.loads(response.read())
# Adds any assets found to the array of assets.
assets += json_response['data']['Data']
@ -212,7 +212,8 @@ class CollinsInventory(object):
cur_page += 1
num_retries = 0
except:
self.log.error("Error while communicating with Collins, retrying:\n%s", traceback.format_exc())
self.log.error("Error while communicating with Collins, retrying:\n%s",
traceback.format_exc())
num_retries += 1
return assets
@ -231,15 +232,19 @@ class CollinsInventory(object):
def read_settings(self):
""" Reads the settings from the collins.ini file """
config_loc = os.getenv('COLLINS_CONFIG', os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
config_loc = os.getenv('COLLINS_CONFIG',
os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
config = ConfigParser.SafeConfigParser()
config.read(os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
self.collins_host = config.get('collins', 'host')
self.collins_username = os.getenv('COLLINS_USERNAME', config.get('collins', 'username'))
self.collins_password = os.getenv('COLLINS_PASSWORD', config.get('collins', 'password'))
self.collins_asset_type = os.getenv('COLLINS_ASSET_TYPE', config.get('collins', 'asset_type'))
self.collins_username = os.getenv('COLLINS_USERNAME',
config.get('collins', 'username'))
self.collins_password = os.getenv('COLLINS_PASSWORD',
config.get('collins', 'password'))
self.collins_asset_type = os.getenv('COLLINS_ASSET_TYPE',
config.get('collins', 'asset_type'))
self.collins_timeout_secs = config.getint('collins', 'timeout_secs')
self.collins_max_retries = config.getint('collins', 'max_retries')
@ -263,12 +268,16 @@ class CollinsInventory(object):
parser = argparse.ArgumentParser(
description='Produces an Ansible Inventory file based on Collins')
parser.add_argument('--list', action='store_true', default=True, help='List instances (default: True)')
parser.add_argument('--host', action='store', help='Get all the variables about a specific instance')
parser.add_argument('--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests to Collins '
'(default: False - use cache files)')
parser.add_argument('--pretty', action='store_true', default=False, help='Pretty print all JSON output')
parser.add_argument('--list',
action='store_true', default=True, help='List instances (default: True)')
parser.add_argument('--host',
action='store', help='Get all the variables about a specific instance')
parser.add_argument('--refresh-cache',
action='store_true', default=False,
help='Force refresh of cache by making API requests to Collins ' \
'(default: False - use cache files)')
parser.add_argument('--pretty',
action='store_true', default=False, help='Pretty print all JSON output')
self.args = parser.parse_args()
def update_cache(self):
@ -281,7 +290,8 @@ class CollinsInventory(object):
try:
server_assets = self.find_assets()
except:
self.log.error("Error while locating assets from Collins:\n%s", traceback.format_exc())
self.log.error("Error while locating assets from Collins:\n%s",
traceback.format_exc())
return False
for asset in server_assets:
@ -305,7 +315,8 @@ class CollinsInventory(object):
if self.prefer_hostnames and self._asset_has_attribute(asset, 'HOSTNAME'):
asset_identifier = self._asset_get_attribute(asset, 'HOSTNAME')
elif 'ADDRESSES' not in asset:
self.log.warning("No IP addresses found for asset '%s', skipping", asset)
self.log.warning("No IP addresses found for asset '%s', skipping",
asset)
continue
elif len(asset['ADDRESSES']) < ip_index + 1:
self.log.warning(
@ -373,11 +384,11 @@ class CollinsInventory(object):
# Need to load index from cache
self.load_cache_from_cache()
if self.args.host not in self.cache:
if not self.args.host in self.cache:
# try updating the cache
self.update_cache()
if self.args.host not in self.cache:
if not self.args.host in self.cache:
# host might not exist anymore
return self.json_format_dict({}, self.args.pretty)
@ -393,7 +404,7 @@ class CollinsInventory(object):
return True
except:
self.log.error("Error while loading inventory:\n%s",
traceback.format_exc())
traceback.format_exc())
self.inventory = {}
return False
@ -407,7 +418,7 @@ class CollinsInventory(object):
return True
except:
self.log.error("Error while loading host cache:\n%s",
traceback.format_exc())
traceback.format_exc())
self.cache = {}
return False

View File

@ -0,0 +1,37 @@
# Ansible Consul external inventory script settings.
[consul]
# restrict included nodes to those from this datacenter
#datacenter = nyc1
# url of the the consul cluster to query
#url = http://demo.consul.io
url = http://localhost:8500
# suffix added to each service to create a group name e.g Service of 'redis' and
# a suffix of '_servers' will add each address to the group name 'redis_servers'
servers_suffix = _servers
# if specified then the inventory will generate domain names that will resolve
# via Consul's inbuilt DNS.
#domain=consul
# make groups from service tags. the name of the group is derived from the
# service name and the tag name e.g. a service named nginx with tags ['master', 'v1']
# will create groups nginx_master and nginx_v1
tags = true
# looks up the node name at the given path for a list of groups to which the
# node should be added.
kv_groups=ansible/groups
# looks up the node name at the given path for a json dictionary of metadata that
# should be attached as metadata for the node
kv_metadata=ansible/metadata
# looks up the health of each service and adds the node to 'up' and 'down' groups
# based on the service availibility
availability = true
available_suffix = _up
unavailable_suffix = _down

View File

@ -1,37 +0,0 @@
# Ansible Consul external inventory script settings.
[consul]
# restrict included nodes to those from this datacenter
#datacenter = nyc1
# url of the consul cluster to query
#url = http://demo.consul.io
url = http://localhost:8500
# suffix added to each service to create a group name e.g Service of 'redis' and
# a suffix of '_servers' will add each address to the group name 'redis_servers'
servers_suffix = _servers
# if specified then the inventory will generate domain names that will resolve
# via Consul's inbuilt DNS.
#domain=consul
# make groups from service tags. the name of the group is derived from the
# service name and the tag name e.g. a service named nginx with tags ['master', 'v1']
# will create groups nginx_master and nginx_v1
tags = true
# looks up the node name at the given path for a list of groups to which the
# node should be added.
kv_groups=ansible/groups
# looks up the node name at the given path for a json dictionary of metadata that
# should be attached as metadata for the node
kv_metadata=ansible/metadata
# looks up the health of each service and adds the node to 'up' and 'down' groups
# based on the service availibility
availability = true
available_suffix = _up
unavailable_suffix = _down

View File

@ -37,7 +37,7 @@ This script can be run with the switches
--datacenter, to restrict the nodes to a single datacenter
--host to restrict the inventory to a single named node. (requires datacenter config)
The configuration for this plugin is read from a consul_io.ini file located in the
The configuration for this plugin is read from a consul.ini file located in the
same directory as this inventory script. All config options in the config file
are optional except the host and port, which must point to a valid agent or
server running the http api. For more information on enabling the endpoint see.
@ -133,11 +133,7 @@ import os
import re
import argparse
import sys
try:
import configparser
except ImportError:
import ConfigParser as configparser
import ConfigParser
def get_log_filename():
@ -243,6 +239,7 @@ class ConsulInventory(object):
self.current_dc = datacenter
self.load_data_for_datacenter(datacenter)
def load_availability_groups(self, node, datacenter):
'''check the health of each service on a node and add add the node to either
an 'available' or 'unavailable' grouping. The suffix for each group can be
@ -260,7 +257,8 @@ class ConsulInventory(object):
suffix = self.config.get_availability_suffix(
'unavailable_suffix', '_unavailable')
self.add_node_to_map(self.nodes_by_availability,
service_name + suffix, node['Node'])
service_name + suffix, node['Node'])
def load_data_for_datacenter(self, datacenter):
'''processes all the nodes in a particular datacenter'''
@ -288,7 +286,7 @@ class ConsulInventory(object):
def load_node_metadata_from_kv(self, node_data):
''' load the json dict at the metadata path defined by the kv_metadata value
and the node name add each entry in the dictionary to the node's
and the node name add each entry in the dictionary to the the node's
metadata '''
node = node_data['Node']
if self.config.has_config('kv_metadata'):
@ -297,7 +295,7 @@ class ConsulInventory(object):
if metadata and metadata['Value']:
try:
metadata = json.loads(metadata['Value'])
for k, v in metadata.items():
for k,v in metadata.items():
self.add_metadata(node_data, k, v)
except:
pass
@ -339,19 +337,19 @@ class ConsulInventory(object):
tags = service['Tags']
self.add_metadata(node_data, "consul_%s_tags" % service_name, tags)
for tag in service['Tags']:
tagname = service_name + '_' + tag
tagname = service_name +'_'+tag
self.add_node_to_map(self.nodes_by_tag, tagname, node_data['Node'])
def combine_all_results(self):
'''prunes and sorts all groupings for combination into the final map'''
self.inventory = {"_meta": {"hostvars": self.node_metadata}}
self.inventory = {"_meta": { "hostvars" : self.node_metadata}}
groupings = [self.nodes, self.nodes_by_datacenter, self.nodes_by_service,
self.nodes_by_tag, self.nodes_by_kv, self.nodes_by_availability]
self.nodes_by_tag, self.nodes_by_kv, self.nodes_by_availability]
for grouping in groupings:
for name, addresses in grouping.items():
self.inventory[name] = sorted(list(set(addresses)))
def add_metadata(self, node_data, key, value, is_list=False):
def add_metadata(self, node_data, key, value, is_list = False):
''' Pushed an element onto a metadata dict for the node, creating
the dict if it doesn't exist '''
key = self.to_safe(key)
@ -373,15 +371,16 @@ class ConsulInventory(object):
if domain:
node_name = node_data['Node']
if self.current_dc:
return '%s.node.%s.%s' % (node_name, self.current_dc, domain)
return '%s.node.%s.%s' % ( node_name, self.current_dc, domain)
else:
return '%s.node.%s' % (node_name, domain)
return '%s.node.%s' % ( node_name, domain)
else:
return node_data['Address']
def add_node_to_map(self, map, name, node):
self.push(map, name, self.get_inventory_name(node))
def push(self, my_dict, key, element):
''' Pushed an element onto an array that may not have been defined in the
dict '''
@ -424,12 +423,9 @@ class ConsulConfig(dict):
return False
def read_settings(self):
''' Reads the settings from the consul_io.ini file (or consul.ini for backwards compatibility)'''
config = configparser.SafeConfigParser()
if os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + '/consul_io.ini'):
config.read(os.path.dirname(os.path.realpath(__file__)) + '/consul_io.ini')
else:
config.read(os.path.dirname(os.path.realpath(__file__)) + '/consul.ini')
''' Reads the settings from the consul.ini file '''
config = ConfigParser.SafeConfigParser()
config.read(os.path.dirname(os.path.realpath(__file__)) + '/consul.ini')
config_options = ['host', 'token', 'datacenter', 'servers_suffix',
'tags', 'kv_metadata', 'kv_groups', 'availability',
@ -443,15 +439,16 @@ class ConsulConfig(dict):
def read_cli_args(self):
''' Command line argument processing '''
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based nodes in a Consul cluster')
parser = argparse.ArgumentParser(description=
'Produce an Ansible Inventory file based nodes in a Consul cluster')
parser.add_argument('--list', action='store_true',
help='Get all inventory variables from all nodes in the consul cluster')
help='Get all inventory variables from all nodes in the consul cluster')
parser.add_argument('--host', action='store',
help='Get all inventory variables about a specific consul node,'
'requires datacenter set in consul.ini.')
help='Get all inventory variables about a specific consul node, \
requires datacenter set in consul.ini.')
parser.add_argument('--datacenter', action='store',
help='Get all inventory about a specific consul datacenter')
help='Get all inventory about a specific consul datacenter')
args = parser.parse_args()
arg_names = ['host', 'datacenter']
@ -465,18 +462,16 @@ class ConsulConfig(dict):
return self.has_config(suffix)
return default
def get_consul_api(self):
'''get an instance of the api based on the supplied configuration'''
host = 'localhost'
port = 8500
port = 8500
token = None
scheme = 'http'
if hasattr(self, 'url'):
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
from urlparse import urlparse
o = urlparse(self.url)
if o.hostname:
host = o.hostname

View File

@ -22,7 +22,7 @@ found. You can force this script to use the cache with --force-cache.
----
Configuration is read from `digital_ocean.ini`, then from environment variables,
and then from command-line arguments.
then and command-line arguments.
Most notably, the DigitalOcean API Token must be specified. It can be specified
in the INI file or with the following environment variables:
@ -153,7 +153,8 @@ except ImportError:
try:
from dopy.manager import DoManager
except ImportError as e:
sys.exit("failed=True msg={}".format(e.message))
sys.exit("failed=True msg='`dopy` library required for this script'")
class DigitalOceanInventory(object):
@ -166,8 +167,8 @@ class DigitalOceanInventory(object):
''' Main execution path '''
# DigitalOceanInventory data
self.data = {} # All DigitalOcean data
self.inventory = {} # Ansible Inventory
self.data = {} # All DigitalOcean data
self.inventory = {} # Ansible Inventory
# Define defaults
self.cache_path = '.'
@ -196,7 +197,7 @@ or environment variables (DO_API_TOKEN)\n''')
self.cache_filename = self.cache_path + "/ansible-digital_ocean.cache"
self.cache_refreshed = False
if self.is_cache_valid():
if self.is_cache_valid:
self.load_from_cache()
if len(self.data) == 0:
if self.args.force_cache:
@ -243,6 +244,7 @@ or environment variables (DO_API_TOKEN)\n''')
print(json.dumps(json_data))
# That's all she wrote...
###########################################################################
# Script configuration
###########################################################################
@ -278,6 +280,7 @@ or environment variables (DO_API_TOKEN)\n''')
if os.getenv("DO_API_KEY"):
self.api_token = os.getenv("DO_API_KEY")
def read_cli_args(self):
''' Command line argument processing '''
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on DigitalOcean credentials')
@ -286,23 +289,23 @@ or environment variables (DO_API_TOKEN)\n''')
parser.add_argument('--host', action='store', help='Get all Ansible inventory variables about a specific Droplet')
parser.add_argument('--all', action='store_true', help='List all DigitalOcean information as JSON')
parser.add_argument('--droplets', '-d', action='store_true', help='List Droplets as JSON')
parser.add_argument('--droplets','-d', action='store_true', help='List Droplets as JSON')
parser.add_argument('--regions', action='store_true', help='List Regions as JSON')
parser.add_argument('--images', action='store_true', help='List Images as JSON')
parser.add_argument('--sizes', action='store_true', help='List Sizes as JSON')
parser.add_argument('--ssh-keys', action='store_true', help='List SSH keys as JSON')
parser.add_argument('--domains', action='store_true', help='List Domains as JSON')
parser.add_argument('--domains', action='store_true',help='List Domains as JSON')
parser.add_argument('--pretty', '-p', action='store_true', help='Pretty-print results')
parser.add_argument('--pretty','-p', action='store_true', help='Pretty-print results')
parser.add_argument('--cache-path', action='store', help='Path to the cache files (default: .)')
parser.add_argument('--cache-max_age', action='store', help='Maximum age of the cached items (default: 0)')
parser.add_argument('--force-cache', action='store_true', default=False, help='Only use data from the cache')
parser.add_argument('--refresh-cache', '-r', action='store_true', default=False,
parser.add_argument('--refresh-cache','-r', action='store_true', default=False,
help='Force refresh of cache by making API requests to DigitalOcean (default: False - use cache files)')
parser.add_argument('--env', '-e', action='store_true', help='Display DO_API_TOKEN')
parser.add_argument('--api-token', '-a', action='store', help='DigitalOcean API Token')
parser.add_argument('--env','-e', action='store_true', help='Display DO_API_TOKEN')
parser.add_argument('--api-token','-a', action='store', help='DigitalOcean API Token')
self.args = parser.parse_args()
@ -316,19 +319,20 @@ or environment variables (DO_API_TOKEN)\n''')
not self.args.all and not self.args.host):
self.args.list = True
###########################################################################
# Data Management
###########################################################################
def load_from_digital_ocean(self, resource=None):
'''Get JSON from DigitalOcean API'''
if self.args.force_cache and os.path.isfile(self.cache_filename):
if self.args.force_cache:
return
# We always get fresh droplets
if self.is_cache_valid() and not (resource == 'droplets' or resource is None):
if self.is_cache_valid() and not (resource=='droplets' or resource is None):
return
if self.args.refresh_cache:
resource = None
resource=None
if resource == 'droplets' or resource is None:
self.data['droplets'] = self.manager.all_active_droplets()
@ -349,23 +353,24 @@ or environment variables (DO_API_TOKEN)\n''')
self.data['domains'] = self.manager.all_domains()
self.cache_refreshed = True
def build_inventory(self):
'''Build Ansible inventory of droplets'''
self.inventory = {
'all': {
'hosts': [],
'vars': self.group_variables
},
},
'_meta': {'hostvars': {}}
}
}
# add all droplets by id and name
for droplet in self.data['droplets']:
# when using private_networking, the API reports the private one in "ip_address".
#when using private_networking, the API reports the private one in "ip_address".
if 'private_networking' in droplet['features'] and not self.use_private_network:
for net in droplet['networks']['v4']:
if net['type'] == 'public':
dest = net['ip_address']
if net['type']=='public':
dest=net['ip_address']
else:
continue
else:
@ -383,7 +388,7 @@ or environment variables (DO_API_TOKEN)\n''')
'distro_' + self.to_safe(droplet['image']['distribution']),
'status_' + droplet['status']):
if group not in self.inventory:
self.inventory[group] = {'hosts': [], 'vars': {}}
self.inventory[group] = { 'hosts': [ ], 'vars': {} }
self.inventory[group]['hosts'].append(dest)
# groups that are not always present
@ -392,19 +397,20 @@ or environment variables (DO_API_TOKEN)\n''')
if group:
image = 'image_' + self.to_safe(group)
if image not in self.inventory:
self.inventory[image] = {'hosts': [], 'vars': {}}
self.inventory[image] = { 'hosts': [ ], 'vars': {} }
self.inventory[image]['hosts'].append(dest)
if droplet['tags']:
for tag in droplet['tags']:
if tag not in self.inventory:
self.inventory[tag] = {'hosts': [], 'vars': {}}
self.inventory[tag] = { 'hosts': [ ], 'vars': {} }
self.inventory[tag]['hosts'].append(dest)
# hostvars
info = self.do_namespace(droplet)
self.inventory['_meta']['hostvars'][dest] = info
def load_droplet_variables_for_host(self):
'''Generate a JSON response to a --host call'''
host = int(self.args.host)
@ -412,6 +418,8 @@ or environment variables (DO_API_TOKEN)\n''')
info = self.do_namespace(droplet)
return {'droplet': info}
###########################################################################
# Cache Management
###########################################################################
@ -425,6 +433,7 @@ or environment variables (DO_API_TOKEN)\n''')
return True
return False
def load_from_cache(self):
''' Reads the data from the cache file and assigns it to member variables as Python Objects'''
try:
@ -438,15 +447,17 @@ or environment variables (DO_API_TOKEN)\n''')
self.data = data['data']
self.inventory = data['inventory']
def write_to_cache(self):
''' Writes data in JSON format to a file '''
data = {'data': self.data, 'inventory': self.inventory}
data = { 'data': self.data, 'inventory': self.inventory }
json_data = json.dumps(data, sort_keys=True, indent=2)
cache = open(self.cache_filename, 'w')
cache.write(json_data)
cache.close()
###########################################################################
# Utilities
###########################################################################
@ -458,6 +469,7 @@ or environment variables (DO_API_TOKEN)\n''')
else:
my_dict[key] = [element]
def to_safe(self, word):
''' Converts 'bad' characters in a string to underscores so they can be used as Ansible groups '''
return re.sub("[^A-Za-z0-9\-\.]", "_", word)
@ -466,10 +478,11 @@ or environment variables (DO_API_TOKEN)\n''')
''' Returns a copy of the dictionary with all the keys put in a 'do_' namespace '''
info = {}
for k, v in data.items():
info['do_' + k] = v
info['do_'+k] = v
return info
###########################################################################
# Run the script
DigitalOceanInventory()

View File

@ -371,6 +371,7 @@ HAS_DOCKER_PY = True
HAS_DOCKER_ERROR = False
try:
from docker import Client
from docker.errors import APIError, TLSParameterError
from docker.tls import TLSConfig
from docker.constants import DEFAULT_TIMEOUT_SECONDS, DEFAULT_DOCKER_API_VERSION
@ -378,19 +379,6 @@ except ImportError as exc:
HAS_DOCKER_ERROR = str(exc)
HAS_DOCKER_PY = False
# Client has recently been split into DockerClient and APIClient
try:
from docker import Client
except ImportError as exc:
try:
from docker import APIClient as Client
except ImportError as exc:
HAS_DOCKER_ERROR = str(exc)
HAS_DOCKER_PY = False
class Client:
pass
DEFAULT_DOCKER_HOST = 'unix://var/run/docker.sock'
DEFAULT_TLS = False
DEFAULT_TLS_VERIFY = False
@ -791,10 +779,6 @@ class DockerInventory(object):
if config_path:
try:
config_file = os.path.abspath(config_path)
# default config path is docker.yml in same directory as this script
# old behaviour is docker.yml in current directory. Handle both.
if not os.path.exists(config_file):
config_file = os.path.abspath(os.path.basename(config_path))
except:
config_file = None
@ -829,30 +813,30 @@ class DockerInventory(object):
# Parse command line arguments
basename = os.path.splitext(os.path.basename(__file__))[0]
default_config = os.path.join(os.path.dirname(__file__), basename + '.yml')
default_config = basename + '.yml'
parser = argparse.ArgumentParser(
description='Return Ansible inventory for one or more Docker hosts.')
parser.add_argument('--list', action='store_true', default=True,
help='List all containers (default: True)')
help='List all containers (default: True)')
parser.add_argument('--debug', action='store_true', default=False,
help='Send debug messages to STDOUT')
help='Send debug messages to STDOUT')
parser.add_argument('--host', action='store',
help='Only get information for a specific container.')
parser.add_argument('--pretty', action='store_true', default=False,
help='Pretty print JSON output(default: False)')
help='Pretty print JSON output(default: False)')
parser.add_argument('--config-file', action='store', default=default_config,
help="Name of the config file to use. Default is %s" % (default_config))
parser.add_argument('--docker-host', action='store', default=None,
help="The base url or Unix sock path to connect to the docker daemon. Defaults to %s"
% (DEFAULT_DOCKER_HOST))
% (DEFAULT_DOCKER_HOST))
parser.add_argument('--tls-hostname', action='store', default='localhost',
help="Host name to expect in TLS certs. Defaults to 'localhost'")
parser.add_argument('--api-version', action='store', default=None,
help="Docker daemon API version. Defaults to %s" % (DEFAULT_DOCKER_API_VERSION))
parser.add_argument('--timeout', action='store', default=None,
help="Docker connection timeout in seconds. Defaults to %s"
% (DEFAULT_TIMEOUT_SECONDS))
% (DEFAULT_TIMEOUT_SECONDS))
parser.add_argument('--cacert-path', action='store', default=None,
help="Path to the TLS certificate authority pem file.")
parser.add_argument('--cert-path', action='store', default=None,

View File

@ -10,9 +10,8 @@
# AWS regions to make calls to. Set this to 'all' to make request to all regions
# in AWS and merge the results together. Alternatively, set this to a comma
# separated list of regions. E.g. 'us-east-1,us-west-1,us-west-2' and do not
# provide the 'regions_exclude' option. If this is set to 'auto', AWS_REGION or
# AWS_DEFAULT_REGION environment variable will be read to determine the region.
# separated list of regions. E.g. 'us-east-1, us-west-1, us-west-2'
# 'auto' is AWS_REGION or AWS_DEFAULT_REGION environment variable.
regions = all
regions_exclude = us-gov-west-1, cn-north-1
@ -135,7 +134,6 @@ group_by_aws_account = False
group_by_ami_id = True
group_by_instance_type = True
group_by_instance_state = False
group_by_platform = True
group_by_key_pair = True
group_by_vpc_id = True
group_by_security_group = True
@ -159,9 +157,7 @@ group_by_elasticache_replication_group = True
# inventory. For the full list of possible filters, please read the EC2 API
# docs: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html#query-DescribeInstances-filters
# Filters are key/value pairs separated by '=', to list multiple filters use
# a list separated by commas. To "AND" criteria together, use "&". Note that
# the "AND" is not useful along with stack_filters and so such usage is not allowed.
# See examples below.
# a list separated by commas. See examples below.
# If you want to apply multiple filters simultaneously, set stack_filters to
# True. Default behaviour is to combine the results of all filters. Stacking
@ -183,18 +179,6 @@ stack_filters = False
# (ex. webservers15, webservers1a, webservers123 etc)
# instance_filters = tag:Name=webservers1*
# Retrieve only instances of type t1.micro that also have tag env=stage
# instance_filters = instance-type=t1.micro&tag:env=stage
# Retrieve instances of type t1.micro AND tag env=stage, as well as any instance
# that are of type m3.large, regardless of env tag
# instance_filters = instance-type=t1.micro&tag:env=stage,instance-type=m3.large
# An IAM role can be assumed, so all requests are run as that role.
# This can be useful for connecting across different accounts, or to limit user
# access
# iam_role = role-arn
# A boto configuration profile may be used to separate out credentials
# see http://boto.readthedocs.org/en/latest/boto_config_tut.html
# boto_profile = some-boto-profile-name

View File

@ -12,7 +12,7 @@ variables needed for Boto have already been set:
export AWS_ACCESS_KEY_ID='AK123'
export AWS_SECRET_ACCESS_KEY='abc123'
optional region environment variable if region is 'auto'
optional region environement variable if region is 'auto'
This script also assumes there is an ec2.ini file alongside it. To specify a
different path to ec2.ini, define the EC2_INI_PATH environment variable:
@ -132,14 +132,13 @@ from boto import ec2
from boto import rds
from boto import elasticache
from boto import route53
from boto import sts
import six
from ansible.module_utils import ec2 as ec2_utils
HAS_BOTO3 = False
try:
import boto3 # noqa
import boto3
HAS_BOTO3 = True
except ImportError:
pass
@ -152,65 +151,11 @@ try:
except ImportError:
import simplejson as json
DEFAULTS = {
'all_elasticache_clusters': 'False',
'all_elasticache_nodes': 'False',
'all_elasticache_replication_groups': 'False',
'all_instances': 'False',
'all_rds_instances': 'False',
'aws_access_key_id': None,
'aws_secret_access_key': None,
'aws_security_token': None,
'boto_profile': None,
'cache_max_age': '300',
'cache_path': '~/.ansible/tmp',
'destination_variable': 'public_dns_name',
'elasticache': 'True',
'eucalyptus': 'False',
'eucalyptus_host': None,
'expand_csv_tags': 'False',
'group_by_ami_id': 'True',
'group_by_availability_zone': 'True',
'group_by_aws_account': 'False',
'group_by_elasticache_cluster': 'True',
'group_by_elasticache_engine': 'True',
'group_by_elasticache_parameter_group': 'True',
'group_by_elasticache_replication_group': 'True',
'group_by_instance_id': 'True',
'group_by_instance_state': 'False',
'group_by_instance_type': 'True',
'group_by_key_pair': 'True',
'group_by_platform': 'True',
'group_by_rds_engine': 'True',
'group_by_rds_parameter_group': 'True',
'group_by_region': 'True',
'group_by_route53_names': 'True',
'group_by_security_group': 'True',
'group_by_tag_keys': 'True',
'group_by_tag_none': 'True',
'group_by_vpc_id': 'True',
'hostname_variable': None,
'iam_role': None,
'include_rds_clusters': 'False',
'nested_groups': 'False',
'pattern_exclude': None,
'pattern_include': None,
'rds': 'False',
'regions': 'all',
'regions_exclude': 'us-gov-west-1, cn-north-1',
'replace_dash_in_groups': 'True',
'route53': 'False',
'route53_excluded_zones': '',
'route53_hostnames': None,
'stack_filters': 'False',
'vpc_destination_variable': 'ip_address'
}
class Ec2Inventory(object):
def _empty_inventory(self):
return {"_meta": {"hostvars": {}}}
return {"_meta" : {"hostvars" : {}}}
def __init__(self):
''' Main execution path '''
@ -259,6 +204,7 @@ class Ec2Inventory(object):
print(data_to_print)
def is_cache_valid(self):
''' Determines if the cache files have expired, or if it is still valid '''
@ -271,6 +217,7 @@ class Ec2Inventory(object):
return False
def read_settings(self):
''' Reads the settings from the ec2.ini file '''
@ -278,50 +225,35 @@ class Ec2Inventory(object):
scriptbasename = os.path.basename(scriptbasename)
scriptbasename = scriptbasename.replace('.py', '')
defaults = {
'ec2': {
'ini_fallback': os.path.join(os.path.dirname(__file__), 'ec2.ini'),
'ini_path': os.path.join(os.path.dirname(__file__), '%s.ini' % scriptbasename)
defaults = {'ec2': {
'ini_path': os.path.join(os.path.dirname(__file__), '%s.ini' % scriptbasename)
}
}
if six.PY3:
config = configparser.ConfigParser(DEFAULTS)
config = configparser.ConfigParser()
else:
config = configparser.SafeConfigParser(DEFAULTS)
config = configparser.SafeConfigParser()
ec2_ini_path = os.environ.get('EC2_INI_PATH', defaults['ec2']['ini_path'])
ec2_ini_path = os.path.expanduser(os.path.expandvars(ec2_ini_path))
if not os.path.isfile(ec2_ini_path):
ec2_ini_path = os.path.expanduser(defaults['ec2']['ini_fallback'])
if os.path.isfile(ec2_ini_path):
config.read(ec2_ini_path)
# Add empty sections if they don't exist
try:
config.add_section('ec2')
except configparser.DuplicateSectionError:
pass
try:
config.add_section('credentials')
except configparser.DuplicateSectionError:
pass
config.read(ec2_ini_path)
# is eucalyptus?
self.eucalyptus = config.getboolean('ec2', 'eucalyptus')
self.eucalyptus_host = config.get('ec2', 'eucalyptus_host')
self.eucalyptus_host = None
self.eucalyptus = False
if config.has_option('ec2', 'eucalyptus'):
self.eucalyptus = config.getboolean('ec2', 'eucalyptus')
if self.eucalyptus and config.has_option('ec2', 'eucalyptus_host'):
self.eucalyptus_host = config.get('ec2', 'eucalyptus_host')
# Regions
self.regions = []
configRegions = config.get('ec2', 'regions')
configRegions_exclude = config.get('ec2', 'regions_exclude')
if (configRegions == 'all'):
if self.eucalyptus_host:
self.regions.append(boto.connect_euca(host=self.eucalyptus_host).region.name, **self.credentials)
else:
configRegions_exclude = config.get('ec2', 'regions_exclude')
for regionInfo in ec2.regions():
if regionInfo.name not in configRegions_exclude:
self.regions.append(regionInfo.name)
@ -331,12 +263,16 @@ class Ec2Inventory(object):
env_region = os.environ.get('AWS_REGION')
if env_region is None:
env_region = os.environ.get('AWS_DEFAULT_REGION')
self.regions = [env_region]
self.regions = [ env_region ]
# Destination addresses
self.destination_variable = config.get('ec2', 'destination_variable')
self.vpc_destination_variable = config.get('ec2', 'vpc_destination_variable')
self.hostname_variable = config.get('ec2', 'hostname_variable')
if config.has_option('ec2', 'hostname_variable'):
self.hostname_variable = config.get('ec2', 'hostname_variable')
else:
self.hostname_variable = None
if config.has_option('ec2', 'destination_format') and \
config.has_option('ec2', 'destination_format_tags'):
@ -348,22 +284,36 @@ class Ec2Inventory(object):
# Route53
self.route53_enabled = config.getboolean('ec2', 'route53')
self.route53_hostnames = config.get('ec2', 'route53_hostnames')
if config.has_option('ec2', 'route53_hostnames'):
self.route53_hostnames = config.get('ec2', 'route53_hostnames')
else:
self.route53_hostnames = None
self.route53_excluded_zones = []
self.route53_excluded_zones = [a for a in config.get('ec2', 'route53_excluded_zones').split(',') if a]
if config.has_option('ec2', 'route53_excluded_zones'):
self.route53_excluded_zones.extend(
config.get('ec2', 'route53_excluded_zones', '').split(','))
# Include RDS instances?
self.rds_enabled = config.getboolean('ec2', 'rds')
self.rds_enabled = True
if config.has_option('ec2', 'rds'):
self.rds_enabled = config.getboolean('ec2', 'rds')
# Include RDS cluster instances?
self.include_rds_clusters = config.getboolean('ec2', 'include_rds_clusters')
if config.has_option('ec2', 'include_rds_clusters'):
self.include_rds_clusters = config.getboolean('ec2', 'include_rds_clusters')
else:
self.include_rds_clusters = False
# Include ElastiCache instances?
self.elasticache_enabled = config.getboolean('ec2', 'elasticache')
self.elasticache_enabled = True
if config.has_option('ec2', 'elasticache'):
self.elasticache_enabled = config.getboolean('ec2', 'elasticache')
# Return all EC2 instances?
self.all_instances = config.getboolean('ec2', 'all_instances')
if config.has_option('ec2', 'all_instances'):
self.all_instances = config.getboolean('ec2', 'all_instances')
else:
self.all_instances = False
# Instance states to be gathered in inventory. Default is 'running'.
# Setting 'all_instances' to 'yes' overrides this option.
@ -388,30 +338,49 @@ class Ec2Inventory(object):
self.ec2_instance_states = ['running']
# Return all RDS instances? (if RDS is enabled)
self.all_rds_instances = config.getboolean('ec2', 'all_rds_instances')
if config.has_option('ec2', 'all_rds_instances') and self.rds_enabled:
self.all_rds_instances = config.getboolean('ec2', 'all_rds_instances')
else:
self.all_rds_instances = False
# Return all ElastiCache replication groups? (if ElastiCache is enabled)
self.all_elasticache_replication_groups = config.getboolean('ec2', 'all_elasticache_replication_groups')
if config.has_option('ec2', 'all_elasticache_replication_groups') and self.elasticache_enabled:
self.all_elasticache_replication_groups = config.getboolean('ec2', 'all_elasticache_replication_groups')
else:
self.all_elasticache_replication_groups = False
# Return all ElastiCache clusters? (if ElastiCache is enabled)
self.all_elasticache_clusters = config.getboolean('ec2', 'all_elasticache_clusters')
if config.has_option('ec2', 'all_elasticache_clusters') and self.elasticache_enabled:
self.all_elasticache_clusters = config.getboolean('ec2', 'all_elasticache_clusters')
else:
self.all_elasticache_clusters = False
# Return all ElastiCache nodes? (if ElastiCache is enabled)
self.all_elasticache_nodes = config.getboolean('ec2', 'all_elasticache_nodes')
if config.has_option('ec2', 'all_elasticache_nodes') and self.elasticache_enabled:
self.all_elasticache_nodes = config.getboolean('ec2', 'all_elasticache_nodes')
else:
self.all_elasticache_nodes = False
# boto configuration profile (prefer CLI argument then environment variables then config file)
self.boto_profile = self.args.boto_profile or \
os.environ.get('AWS_PROFILE') or \
config.get('ec2', 'boto_profile')
self.boto_profile = self.args.boto_profile or os.environ.get('AWS_PROFILE')
if config.has_option('ec2', 'boto_profile') and not self.boto_profile:
self.boto_profile = config.get('ec2', 'boto_profile')
# AWS credentials (prefer environment variables)
if not (self.boto_profile or os.environ.get('AWS_ACCESS_KEY_ID') or
os.environ.get('AWS_PROFILE')):
aws_access_key_id = config.get('credentials', 'aws_access_key_id')
aws_secret_access_key = config.get('credentials', 'aws_secret_access_key')
aws_security_token = config.get('credentials', 'aws_security_token')
if config.has_option('credentials', 'aws_access_key_id'):
aws_access_key_id = config.get('credentials', 'aws_access_key_id')
else:
aws_access_key_id = None
if config.has_option('credentials', 'aws_secret_access_key'):
aws_secret_access_key = config.get('credentials', 'aws_secret_access_key')
else:
aws_secret_access_key = None
if config.has_option('credentials', 'aws_security_token'):
aws_security_token = config.get('credentials', 'aws_security_token')
else:
aws_security_token = None
if aws_access_key_id:
self.credentials = {
'aws_access_key_id': aws_access_key_id,
@ -435,74 +404,107 @@ class Ec2Inventory(object):
self.cache_path_index = os.path.join(cache_dir, "%s.index" % cache_name)
self.cache_max_age = config.getint('ec2', 'cache_max_age')
self.expand_csv_tags = config.getboolean('ec2', 'expand_csv_tags')
if config.has_option('ec2', 'expand_csv_tags'):
self.expand_csv_tags = config.getboolean('ec2', 'expand_csv_tags')
else:
self.expand_csv_tags = False
# Configure nested groups instead of flat namespace.
self.nested_groups = config.getboolean('ec2', 'nested_groups')
if config.has_option('ec2', 'nested_groups'):
self.nested_groups = config.getboolean('ec2', 'nested_groups')
else:
self.nested_groups = False
# Replace dash or not in group names
self.replace_dash_in_groups = config.getboolean('ec2', 'replace_dash_in_groups')
# IAM role to assume for connection
self.iam_role = config.get('ec2', 'iam_role')
if config.has_option('ec2', 'replace_dash_in_groups'):
self.replace_dash_in_groups = config.getboolean('ec2', 'replace_dash_in_groups')
else:
self.replace_dash_in_groups = True
# Configure which groups should be created.
group_by_options = [a for a in DEFAULTS if a.startswith('group_by')]
group_by_options = [
'group_by_instance_id',
'group_by_region',
'group_by_availability_zone',
'group_by_ami_id',
'group_by_instance_type',
'group_by_instance_state',
'group_by_key_pair',
'group_by_vpc_id',
'group_by_security_group',
'group_by_tag_keys',
'group_by_tag_none',
'group_by_route53_names',
'group_by_rds_engine',
'group_by_rds_parameter_group',
'group_by_elasticache_engine',
'group_by_elasticache_cluster',
'group_by_elasticache_parameter_group',
'group_by_elasticache_replication_group',
'group_by_aws_account',
]
for option in group_by_options:
setattr(self, option, config.getboolean('ec2', option))
if config.has_option('ec2', option):
setattr(self, option, config.getboolean('ec2', option))
else:
setattr(self, option, True)
# Do we need to just include hosts that match a pattern?
self.pattern_include = config.get('ec2', 'pattern_include')
if self.pattern_include:
self.pattern_include = re.compile(self.pattern_include)
try:
pattern_include = config.get('ec2', 'pattern_include')
if pattern_include and len(pattern_include) > 0:
self.pattern_include = re.compile(pattern_include)
else:
self.pattern_include = None
except configparser.NoOptionError:
self.pattern_include = None
# Do we need to exclude hosts that match a pattern?
self.pattern_exclude = config.get('ec2', 'pattern_exclude')
if self.pattern_exclude:
self.pattern_exclude = re.compile(self.pattern_exclude)
try:
pattern_exclude = config.get('ec2', 'pattern_exclude')
if pattern_exclude and len(pattern_exclude) > 0:
self.pattern_exclude = re.compile(pattern_exclude)
else:
self.pattern_exclude = None
except configparser.NoOptionError:
self.pattern_exclude = None
# Do we want to stack multiple filters?
self.stack_filters = config.getboolean('ec2', 'stack_filters')
if config.has_option('ec2', 'stack_filters'):
self.stack_filters = config.getboolean('ec2', 'stack_filters')
else:
self.stack_filters = False
# Instance filters (see boto and EC2 API docs). Ignore invalid filters.
self.ec2_instance_filters = []
self.ec2_instance_filters = defaultdict(list)
if config.has_option('ec2', 'instance_filters'):
filters = config.get('ec2', 'instance_filters')
if self.stack_filters and '&' in filters:
self.fail_with_error("AND filters along with stack_filter enabled is not supported.\n")
filters = [f for f in config.get('ec2', 'instance_filters').split(',') if f]
filter_sets = [f for f in filters.split(',') if f]
for filter_set in filter_sets:
filters = {}
filter_set = filter_set.strip()
for instance_filter in filter_set.split("&"):
instance_filter = instance_filter.strip()
if not instance_filter or '=' not in instance_filter:
continue
filter_key, filter_value = [x.strip() for x in instance_filter.split('=', 1)]
if not filter_key:
continue
filters[filter_key] = filter_value
self.ec2_instance_filters.append(filters.copy())
for instance_filter in filters:
instance_filter = instance_filter.strip()
if not instance_filter or '=' not in instance_filter:
continue
filter_key, filter_value = [x.strip() for x in instance_filter.split('=', 1)]
if not filter_key:
continue
self.ec2_instance_filters[filter_key].append(filter_value)
def parse_cli_args(self):
''' Command line argument processing '''
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on EC2')
parser.add_argument('--list', action='store_true', default=True,
help='List instances (default: True)')
help='List instances (default: True)')
parser.add_argument('--host', action='store',
help='Get all the variables about a specific instance')
help='Get all the variables about a specific instance')
parser.add_argument('--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests to EC2 (default: False - use cache files)')
help='Force refresh of cache by making API requests to EC2 (default: False - use cache files)')
parser.add_argument('--profile', '--boto-profile', action='store', dest='boto_profile',
help='Use boto profile for connections to EC2')
help='Use boto profile for connections to EC2')
self.args = parser.parse_args()
def do_api_calls_update_cache(self):
''' Do API calls to each region, and save data in cache files '''
@ -546,13 +548,6 @@ class Ec2Inventory(object):
connect_args['profile_name'] = self.boto_profile
self.boto_fix_security_token_in_profile(connect_args)
if self.iam_role:
sts_conn = sts.connect_to_region(region, **connect_args)
role = sts_conn.assume_role(self.iam_role, 'ansible_dynamic_inventory')
connect_args['aws_access_key_id'] = role.credentials.access_key
connect_args['aws_secret_access_key'] = role.credentials.secret_key
connect_args['security_token'] = role.credentials.session_token
conn = module.connect_to_region(region, **connect_args)
# connect_to_region will fail "silently" by returning None if the region name is wrong or not supported
if conn is None:
@ -569,12 +564,12 @@ class Ec2Inventory(object):
if self.ec2_instance_filters:
if self.stack_filters:
filters_dict = {}
for filters in self.ec2_instance_filters:
filters_dict.update(filters)
reservations.extend(conn.get_all_instances(filters=filters_dict))
for filter_key, filter_values in self.ec2_instance_filters.items():
filters_dict[filter_key] = filter_values
reservations.extend(conn.get_all_instances(filters = filters_dict))
else:
for filters in self.ec2_instance_filters:
reservations.extend(conn.get_all_instances(filters=filters))
for filter_key, filter_values in self.ec2_instance_filters.items():
reservations.extend(conn.get_all_instances(filters = { filter_key : filter_values }))
else:
reservations = conn.get_all_instances()
@ -588,7 +583,7 @@ class Ec2Inventory(object):
max_filter_value = 199
tags = []
for i in range(0, len(instance_ids), max_filter_value):
tags.extend(conn.get_all_tags(filters={'resource-type': 'instance', 'resource-id': instance_ids[i:i + max_filter_value]}))
tags.extend(conn.get_all_tags(filters={'resource-type': 'instance', 'resource-id': instance_ids[i:i+max_filter_value]}))
tags_by_instance_id = defaultdict(dict)
for tag in tags:
@ -610,44 +605,10 @@ class Ec2Inventory(object):
error = "Error connecting to %s backend.\n%s" % (backend, e.message)
self.fail_with_error(error, 'getting EC2 instances')
def tags_match_filters(self, tags):
''' return True if given tags match configured filters '''
if not self.ec2_instance_filters:
return True
for filters in self.ec2_instance_filters:
for filter_name, filter_value in filters.items():
if filter_name[:4] != 'tag:':
continue
filter_name = filter_name[4:]
if filter_name not in tags:
if self.stack_filters:
return False
continue
if isinstance(filter_value, list):
if self.stack_filters and tags[filter_name] not in filter_value:
return False
if not self.stack_filters and tags[filter_name] in filter_value:
return True
if isinstance(filter_value, six.string_types):
if self.stack_filters and tags[filter_name] != filter_value:
return False
if not self.stack_filters and tags[filter_name] == filter_value:
return True
return self.stack_filters
def get_rds_instances_by_region(self, region):
''' Makes an AWS API call to the list of RDS instances in a particular
region '''
if not HAS_BOTO3:
self.fail_with_error("Working with RDS instances requires boto3 - please install boto3 and try again",
"getting RDS instances")
client = ec2_utils.boto3_inventory_conn('client', 'rds', region, **self.credentials)
db_instances = client.describe_db_instances()
try:
conn = self.connect_to_aws(rds, region)
if conn:
@ -655,15 +616,8 @@ class Ec2Inventory(object):
while True:
instances = conn.get_all_dbinstances(marker=marker)
marker = instances.marker
for index, instance in enumerate(instances):
# Add tags to instances.
instance.arn = db_instances['DBInstances'][index]['DBInstanceArn']
tags = client.list_tags_for_resource(ResourceName=instance.arn)['TagList']
instance.tags = {}
for tag in tags:
instance.tags[tag['Key']] = tag['Value']
if self.tags_match_filters(instance.tags):
self.add_rds_instance(instance, region)
for instance in instances:
self.add_rds_instance(instance, region)
if not marker:
break
except boto.exception.BotoServerError as e:
@ -671,11 +625,7 @@ class Ec2Inventory(object):
if e.error_code == 'AuthFailure':
error = self.get_auth_error_message()
elif e.error_code == "OptInRequired":
error = "RDS hasn't been enabled for this account yet. " \
"You must either log in to the RDS service through the AWS console to enable it, " \
"or set 'rds = False' in ec2.ini"
elif not e.reason == "Forbidden":
if not e.reason == "Forbidden":
error = "Looks like AWS RDS is down:\n%s" % e.message
self.fail_with_error(error, 'getting RDS instances')
@ -702,7 +652,7 @@ class Ec2Inventory(object):
if 'LatestRestorableTime' in c:
del c['LatestRestorableTime']
if not self.ec2_instance_filters:
if self.ec2_instance_filters == {}:
matches_filter = True
else:
matches_filter = False
@ -714,18 +664,14 @@ class Ec2Inventory(object):
c['Tags'] = tags['TagList']
if self.ec2_instance_filters:
for filters in self.ec2_instance_filters:
for filter_key, filter_values in filters.items():
# get AWS tag key e.g. tag:env will be 'env'
tag_name = filter_key.split(":", 1)[1]
# Filter values is a list (if you put multiple values for the same tag name)
matches_filter = any(d['Key'] == tag_name and d['Value'] in filter_values for d in c['Tags'])
if matches_filter:
# it matches a filter, so stop looking for further matches
break
for filter_key, filter_values in self.ec2_instance_filters.items():
# get AWS tag key e.g. tag:env will be 'env'
tag_name = filter_key.split(":", 1)[1]
# Filter values is a list (if you put multiple values for the same tag name)
matches_filter = any(d['Key'] == tag_name and d['Value'] in filter_values for d in c['Tags'])
if matches_filter:
# it matches a filter, so stop looking for further matches
break
except Exception as e:
@ -746,7 +692,7 @@ class Ec2Inventory(object):
''' Makes an AWS API call to the list of ElastiCache clusters (with
nodes' info) in a particular region.'''
# ElastiCache boto module doesn't provide a get_all_instances method,
# ElastiCache boto module doesn't provide a get_all_intances method,
# that's why we need to call describe directly (it would be called by
# the shorthand method anyway...)
try:
@ -761,11 +707,7 @@ class Ec2Inventory(object):
if e.error_code == 'AuthFailure':
error = self.get_auth_error_message()
elif e.error_code == "OptInRequired":
error = "ElastiCache hasn't been enabled for this account yet. " \
"You must either log in to the ElastiCache service through the AWS console to enable it, " \
"or set 'elasticache = False' in ec2.ini"
elif not e.reason == "Forbidden":
if not e.reason == "Forbidden":
error = "Looks like AWS ElastiCache is down:\n%s" % e.message
self.fail_with_error(error, 'getting ElastiCache clusters')
@ -786,7 +728,7 @@ class Ec2Inventory(object):
''' Makes an AWS API call to the list of ElastiCache replication groups
in a particular region.'''
# ElastiCache boto module doesn't provide a get_all_instances method,
# ElastiCache boto module doesn't provide a get_all_intances method,
# that's why we need to call describe directly (it would be called by
# the shorthand method anyway...)
try:
@ -825,7 +767,7 @@ class Ec2Inventory(object):
errors.append(' - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment vars found but may not be correct')
boto_paths = ['/etc/boto.cfg', '~/.boto', '~/.aws/credentials']
boto_config_found = [p for p in boto_paths if os.path.isfile(os.path.expanduser(p))]
boto_config_found = list(p for p in boto_paths if os.path.isfile(os.path.expanduser(p)))
if len(boto_config_found) > 0:
errors.append(" - Boto configs found at '%s', but the credentials contained may not be correct" % ', '.join(boto_config_found))
else:
@ -859,7 +801,7 @@ class Ec2Inventory(object):
# Select the best destination address
if self.destination_format and self.destination_format_tags:
dest = self.destination_format.format(*[getattr(instance, 'tags').get(tag, '') for tag in self.destination_format_tags])
dest = self.destination_format.format(*[ getattr(instance, 'tags').get(tag, '') for tag in self.destination_format_tags ])
elif instance.subnet_id:
dest = getattr(instance, self.vpc_destination_variable, None)
if dest is None:
@ -949,16 +891,6 @@ class Ec2Inventory(object):
if self.nested_groups:
self.push_group(self.inventory, 'instance_states', state_name)
# Inventory: Group by platform
if self.group_by_platform:
if instance.platform:
platform = self.to_safe('platform_' + instance.platform)
else:
platform = self.to_safe('platform_undefined')
self.push(self.inventory, platform, hostname)
if self.nested_groups:
self.push_group(self.inventory, 'platforms', platform)
# Inventory: Group by key pair
if self.group_by_key_pair and instance.key_name:
key_name = self.to_safe('key_' + instance.key_name)
@ -983,7 +915,7 @@ class Ec2Inventory(object):
self.push_group(self.inventory, 'security_groups', key)
except AttributeError:
self.fail_with_error('\n'.join(['Package boto seems a bit older.',
'Please upgrade boto >= 2.3.0.']))
'Please upgrade boto >= 2.3.0.']))
# Inventory: Group by AWS account ID
if self.group_by_aws_account:
@ -1028,7 +960,8 @@ class Ec2Inventory(object):
self.push(self.inventory, 'ec2', hostname)
self.inventory["_meta"]["hostvars"][hostname] = self.get_host_info_dict_from_instance(instance)
self.inventory["_meta"]["hostvars"][hostname]['ansible_host'] = dest
self.inventory["_meta"]["hostvars"][hostname]['ansible_ssh_host'] = dest
def add_rds_instance(self, instance, region):
''' Adds an RDS instance to the inventory and index, as long as it is
@ -1107,25 +1040,8 @@ class Ec2Inventory(object):
except AttributeError:
self.fail_with_error('\n'.join(['Package boto seems a bit older.',
'Please upgrade boto >= 2.3.0.']))
# Inventory: Group by tag keys
if self.group_by_tag_keys:
for k, v in instance.tags.items():
if self.expand_csv_tags and v and ',' in v:
values = map(lambda x: x.strip(), v.split(','))
else:
values = [v]
'Please upgrade boto >= 2.3.0.']))
for v in values:
if v:
key = self.to_safe("tag_" + k + "=" + v)
else:
key = self.to_safe("tag_" + k)
self.push(self.inventory, key, hostname)
if self.nested_groups:
self.push_group(self.inventory, 'tags', self.to_safe("tag_" + k))
if v:
self.push_group(self.inventory, self.to_safe("tag_" + k), key)
# Inventory: Group by engine
if self.group_by_rds_engine:
@ -1139,17 +1055,11 @@ class Ec2Inventory(object):
if self.nested_groups:
self.push_group(self.inventory, 'rds_parameter_groups', self.to_safe("rds_parameter_group_" + instance.parameter_group.name))
# Global Tag: instances without tags
if self.group_by_tag_none and len(instance.tags) == 0:
self.push(self.inventory, 'tag_none', hostname)
if self.nested_groups:
self.push_group(self.inventory, 'tags', 'tag_none')
# Global Tag: all RDS instances
self.push(self.inventory, 'rds', hostname)
self.inventory["_meta"]["hostvars"][hostname] = self.get_host_info_dict_from_instance(instance)
self.inventory["_meta"]["hostvars"][hostname]['ansible_host'] = dest
self.inventory["_meta"]["hostvars"][hostname]['ansible_ssh_host'] = dest
def add_elasticache_cluster(self, cluster, region):
''' Adds an ElastiCache cluster to the inventory and index, as long as
@ -1400,7 +1310,8 @@ class Ec2Inventory(object):
r53_conn = route53.Route53Connection()
all_zones = r53_conn.get_zones()
route53_zones = [zone for zone in all_zones if zone.name[:-1] not in self.route53_excluded_zones]
route53_zones = [ zone for zone in all_zones if zone.name[:-1]
not in self.route53_excluded_zones ]
self.route53_records = {}
@ -1417,13 +1328,14 @@ class Ec2Inventory(object):
self.route53_records.setdefault(resource, set())
self.route53_records[resource].add(record_name)
def get_instance_route53_names(self, instance):
''' Check if an instance is referenced in the records we have from
Route53. If it is, return the list of domain names pointing to said
instance. If nothing points to it, return an empty list. '''
instance_attributes = ['public_dns_name', 'private_dns_name',
'ip_address', 'private_ip_address']
instance_attributes = [ 'public_dns_name', 'private_dns_name',
'ip_address', 'private_ip_address' ]
name_list = set()
@ -1452,7 +1364,7 @@ class Ec2Inventory(object):
elif key == 'ec2__previous_state':
instance_vars['ec2_previous_state'] = instance.previous_state or ''
instance_vars['ec2_previous_state_code'] = instance.previous_state_code
elif isinstance(value, (int, bool)):
elif type(value) in [int, bool]:
instance_vars[key] = value
elif isinstance(value, six.string_types):
instance_vars[key] = value.strip()
@ -1479,13 +1391,13 @@ class Ec2Inventory(object):
elif key == 'ec2_block_device_mapping':
instance_vars["ec2_block_devices"] = {}
for k, v in value.items():
instance_vars["ec2_block_devices"][os.path.basename(k)] = v.volume_id
instance_vars["ec2_block_devices"][ os.path.basename(k) ] = v.volume_id
else:
pass
# TODO Product codes if someone finds them useful
# print key
# print type(value)
# print value
#print key
#print type(value)
#print value
instance_vars[self.to_safe('ec2_account_id')] = self.aws_account_id
@ -1529,9 +1441,9 @@ class Ec2Inventory(object):
host_info['ec2_primary_cluster_port'] = node['ReadEndpoint']['Port']
host_info['ec2_primary_cluster_id'] = node['CacheClusterId']
elif node['CurrentRole'] == 'replica':
host_info['ec2_replica_cluster_address_' + str(replica_count)] = node['ReadEndpoint']['Address']
host_info['ec2_replica_cluster_port_' + str(replica_count)] = node['ReadEndpoint']['Port']
host_info['ec2_replica_cluster_id_' + str(replica_count)] = node['CacheClusterId']
host_info['ec2_replica_cluster_address_'+ str(replica_count)] = node['ReadEndpoint']['Address']
host_info['ec2_replica_cluster_port_'+ str(replica_count)] = node['ReadEndpoint']['Port']
host_info['ec2_replica_cluster_id_'+ str(replica_count)] = node['CacheClusterId']
replica_count += 1
# Target: Redis Replication Groups
@ -1557,7 +1469,7 @@ class Ec2Inventory(object):
# Target: Everything
# Preserve booleans and integers
elif isinstance(value, (int, bool)):
elif type(value) in [int, bool]:
host_info[key] = value
# Target: Everything
@ -1583,10 +1495,10 @@ class Ec2Inventory(object):
# Need to load index from cache
self.load_index_from_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# try updating the cache
self.do_api_calls_update_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# host might not exist anymore
return self.json_format_dict({}, True)

View File

@ -35,7 +35,7 @@ except:
import simplejson as json
# Options
# ------------------------------
#------------------------------
parser = OptionParser(usage="%prog [options] --list | --host <machine>")
parser.add_option('--list', default=False, dest="list", action="store_true",
@ -48,7 +48,6 @@ parser.add_option('--host', default=None, dest="host",
# helper functions
#
def get_ssh_config():
configs = []
for box in list_running_boxes():
@ -56,8 +55,7 @@ def get_ssh_config():
configs.append(config)
return configs
# list all the running instances in the fleet
#list all the running instances in the fleet
def list_running_boxes():
boxes = []
for line in subprocess.check_output(["fleetctl", "list-machines"]).split('\n'):
@ -67,7 +65,6 @@ def list_running_boxes():
return boxes
def get_a_ssh_config(box_name):
config = {}
config['Host'] = box_name
@ -75,12 +72,11 @@ def get_a_ssh_config(box_name):
config['ansible_python_interpreter'] = '/opt/bin/python'
return config
# List out servers that vagrant has running
# ------------------------------
#------------------------------
if options.list:
ssh_config = get_ssh_config()
hosts = {'coreos': []}
hosts = { 'coreos': []}
for data in ssh_config:
hosts['coreos'].append(data['Host'])
@ -89,14 +85,14 @@ if options.list:
sys.exit(1)
# Get out the host details
# ------------------------------
#------------------------------
elif options.host:
result = {}
ssh_config = get_ssh_config()
details = filter(lambda x: (x['Host'] == options.host), ssh_config)
if len(details) > 0:
# pass through the port, in case it's non standard.
#pass through the port, in case it's non standard.
result = details[0]
print(json.dumps(result))
@ -104,7 +100,7 @@ elif options.host:
# Print out help
# ------------------------------
#------------------------------
else:
parser.print_help()
sys.exit(1)

View File

@ -68,21 +68,6 @@
#
# foreman_hostgroup_myapp_webtier_datacenter1
#
# If the parameter want_hostcollections is set to true, the
# collections each host is in are created as Ansible groups with a
# foreman_hostcollection prefix, all lowercase and problematic
# parameters removed. So e.g. the Foreman host collection
#
# Patch Window Thursday
#
# would turn into the Ansible group:
#
# foreman_hostcollection_patchwindowthursday
#
# If the parameter host_filters is set, it will be used as the
# "search" parameter for the /api/v2/hosts call. This can be used to
# restrict the list of returned host, as shown below.
#
# Furthermore Ansible groups can be created on the fly using the
# *group_patterns* variable in *foreman.ini* so that you can build up
# hierarchies using parameters on the hostgroup and host variables.
@ -123,35 +108,15 @@ user = foreman
password = secret
ssl_verify = True
# Retrieve only hosts from the organization "Web Engineering".
# host_filters = organization="Web Engineering"
# Retrieve only hosts from the organization "Web Engineering" that are
# also in the host collection "Apache Servers".
# host_filters = organization="Web Engineering" and host_collection="Apache Servers"
[ansible]
group_patterns = ["{app}-{tier}-{color}",
"{app}-{color}",
"{app}",
"{tier}"]
group_prefix = foreman_
# Whether to fetch facts from Foreman and store them on the host
want_facts = True
# Whether to create Ansible groups for host collections. Only tested
# with Katello (Red Hat Satellite). Disabled by default to not break
# the script for stand-alone Foreman.
want_hostcollections = False
# Whether to interpret global parameters value as JSON (if possible, else
# take as is). Only tested with Katello (Red Hat Satellite).
# This allows to define lists and dictionaries (and more complicated structures)
# variables by entering them as JSON string in Foreman parameters.
# Disabled by default as the change would else not be backward compatible.
rich_params = False
[cache]
path = .
max_age = 60

View File

@ -46,7 +46,6 @@ if LooseVersion(requests.__version__) < LooseVersion('1.1.0'):
from requests.auth import HTTPBasicAuth
def json_format_dict(data, pretty=False):
"""Converts a dict to a JSON object and dumps it as a formatted string"""
@ -55,7 +54,6 @@ def json_format_dict(data, pretty=False):
else:
return json.dumps(data)
class ForemanInventory(object):
def __init__(self):
@ -64,7 +62,6 @@ class ForemanInventory(object):
self.params = dict() # Params of each host
self.facts = dict() # Facts of each host
self.hostgroups = dict() # host groups
self.hostcollections = dict() # host collections
self.session = None # Requests session
self.config_paths = [
"/etc/ansible/foreman.ini",
@ -108,22 +105,6 @@ class ForemanInventory(object):
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
self.want_facts = True
try:
self.want_hostcollections = config.getboolean('ansible', 'want_hostcollections')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
self.want_hostcollections = False
# Do we want parameters to be interpreted if possible as JSON? (no by default)
try:
self.rich_params = config.getboolean('ansible', 'rich_params')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
self.rich_params = False
try:
self.host_filters = config.get('foreman', 'host_filters')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
self.host_filters = None
# Cache related
try:
cache_path = os.path.expanduser(config.get('cache', 'path'))
@ -134,12 +115,10 @@ class ForemanInventory(object):
self.cache_path_inventory = cache_path + "/%s.index" % script
self.cache_path_params = cache_path + "/%s.params" % script
self.cache_path_facts = cache_path + "/%s.facts" % script
self.cache_path_hostcollections = cache_path + "/%s.hostcollections" % script
try:
self.cache_max_age = config.getint('cache', 'max_age')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
self.cache_max_age = 60
return True
def parse_cli_args(self):
@ -159,17 +138,12 @@ class ForemanInventory(object):
self.session.verify = self.foreman_ssl_verify
return self.session
def _get_json(self, url, ignore_errors=None, params=None):
if params is None:
params = {}
params['per_page'] = 250
def _get_json(self, url, ignore_errors=None):
page = 1
results = []
s = self._get_session()
while True:
params['page'] = page
ret = s.get(url, params=params)
ret = s.get(url, params={'page': page, 'per_page': 250})
if ignore_errors and ret.status_code in ignore_errors:
break
ret.raise_for_status()
@ -182,7 +156,7 @@ class ForemanInventory(object):
return json['results']
# List of all hosts is returned paginaged
results = results + json['results']
if len(results) >= json['subtotal']:
if len(results) >= json['total']:
break
page += 1
if len(json['results']) == 0:
@ -193,35 +167,22 @@ class ForemanInventory(object):
return results
def _get_hosts(self):
url = "%s/api/v2/hosts" % self.foreman_url
return self._get_json("%s/api/v2/hosts" % self.foreman_url)
params = {}
if self.host_filters:
params['search'] = self.host_filters
return self._get_json(url, params=params)
def _get_host_data_by_id(self, hid):
def _get_all_params_by_id(self, hid):
url = "%s/api/v2/hosts/%s" % (self.foreman_url, hid)
return self._get_json(url)
ret = self._get_json(url, [404])
if ret == []:
ret = {}
return ret.get('all_parameters', {})
def _get_facts_by_id(self, hid):
url = "%s/api/v2/hosts/%s/facts" % (self.foreman_url, hid)
return self._get_json(url)
def _resolve_params(self, host_params):
"""Convert host params to dict"""
def _resolve_params(self, host):
"""Fetch host params and convert to dict"""
params = {}
for param in host_params:
for param in self._get_all_params_by_id(host['id']):
name = param['name']
if self.rich_params:
try:
params[name] = json.loads(param['value'])
except ValueError:
params[name] = param['value']
else:
params[name] = param['value']
params[name] = param['value']
return params
@ -255,7 +216,6 @@ class ForemanInventory(object):
self.write_to_cache(self.inventory, self.cache_path_inventory)
self.write_to_cache(self.params, self.cache_path_params)
self.write_to_cache(self.facts, self.cache_path_facts)
self.write_to_cache(self.hostcollections, self.cache_path_hostcollections)
def to_safe(self, word):
'''Converts 'bad' characters in a string to underscores
@ -276,9 +236,6 @@ class ForemanInventory(object):
for host in self._get_hosts():
dns_name = host['name']
host_data = self._get_host_data_by_id(host['id'])
host_params = host_data.get('all_parameters', {})
# Create ansible groups for hostgroup
group = 'hostgroup'
val = host.get('%s_title' % group) or host.get('%s_name' % group)
@ -299,13 +256,16 @@ class ForemanInventory(object):
safe_key = self.to_safe('%s%s_%s' % (self.group_prefix, group, val.lower()))
self.inventory[safe_key].append(dns_name)
params = self._resolve_params(host_params)
params = self._resolve_params(host)
# Ansible groups by parameters in host groups and Foreman host
# attributes.
groupby = dict()
for k, v in params.items():
groupby[k] = self.to_safe(str(v))
groupby = copy.copy(params)
for k, v in host.items():
if isinstance(v, str):
groupby[k] = self.to_safe(v)
elif isinstance(v, int):
groupby[k] = v
# The name of the ansible groups is given by group_patterns:
for pattern in self.group_patterns:
@ -315,17 +275,6 @@ class ForemanInventory(object):
except KeyError:
pass # Host not part of this group
if self.want_hostcollections:
hostcollections = host_data.get('host_collections')
if hostcollections:
# Create Ansible groups for host collections
for hostcollection in hostcollections:
safe_key = self.to_safe('%shostcollection_%s' % (self.group_prefix, hostcollection['name'].lower()))
self.inventory[safe_key].append(dns_name)
self.hostcollections[dns_name] = hostcollections
self.cache[dns_name] = host
self.params[dns_name] = params
self.facts[dns_name] = self._get_facts(host)
@ -347,36 +296,31 @@ class ForemanInventory(object):
def load_inventory_from_cache(self):
"""Read the index from the cache file sets self.index"""
with open(self.cache_path_inventory, 'r') as fp:
self.inventory = json.load(fp)
cache = open(self.cache_path_inventory, 'r')
json_inventory = cache.read()
self.inventory = json.loads(json_inventory)
def load_params_from_cache(self):
"""Read the index from the cache file sets self.index"""
with open(self.cache_path_params, 'r') as fp:
self.params = json.load(fp)
cache = open(self.cache_path_params, 'r')
json_params = cache.read()
self.params = json.loads(json_params)
def load_facts_from_cache(self):
"""Read the index from the cache file sets self.facts"""
if not self.want_facts:
return
with open(self.cache_path_facts, 'r') as fp:
self.facts = json.load(fp)
def load_hostcollections_from_cache(self):
"""Read the index from the cache file sets self.hostcollections"""
if not self.want_hostcollections:
return
with open(self.cache_path_hostcollections, 'r') as fp:
self.hostcollections = json.load(fp)
cache = open(self.cache_path_facts, 'r')
json_facts = cache.read()
self.facts = json.loads(json_facts)
def load_cache_from_cache(self):
"""Read the cache from the cache file sets self.cache"""
with open(self.cache_path_cache, 'r') as fp:
self.cache = json.load(fp)
cache = open(self.cache_path_cache, 'r')
json_cache = cache.read()
self.cache = json.loads(json_cache)
def get_inventory(self):
if self.args.refresh_cache or not self.is_cache_valid():
@ -385,7 +329,6 @@ class ForemanInventory(object):
self.load_inventory_from_cache()
self.load_params_from_cache()
self.load_facts_from_cache()
self.load_hostcollections_from_cache()
self.load_cache_from_cache()
def get_host_info(self):

View File

@ -1,12 +1,8 @@
#!/usr/bin/env python
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
import argparse
from ipalib import api
import json
from distutils.version import StrictVersion
def initialize():
'''
@ -20,12 +16,11 @@ def initialize():
try:
api.Backend.rpcclient.connect()
except AttributeError:
# FreeIPA < 4.0 compatibility
#FreeIPA < 4.0 compatibility
api.Backend.xmlclient.connect()
return api
def list_groups(api):
'''
This function prints a list of all host groups. This function requires
@ -33,18 +28,14 @@ def list_groups(api):
'''
inventory = {}
hostvars = {}
hostvars={}
meta={}
ipa_version = api.Command.env()['result']['version']
result = api.Command.hostgroup_find()['result']
for hostgroup in result:
# Get direct and indirect members (nested hostgroups) of hostgroup
members = []
if StrictVersion(ipa_version) >= StrictVersion('4.0.0'):
hostgroup_name = hostgroup['cn'][0]
hostgroup = api.Command.hostgroup_show(hostgroup_name)['result']
if 'member_host' in hostgroup:
members = [host for host in hostgroup['member_host']]
if 'memberindirect_host' in hostgroup:
@ -60,7 +51,6 @@ def list_groups(api):
return None
def parse_args():
'''
This function parses the arguments that were passed in via the command line.
@ -76,7 +66,6 @@ def parse_args():
return parser.parse_args()
def print_host(host):
'''
This function is really a stub, it could return variables to be used in
@ -90,7 +79,6 @@ def print_host(host):
return None
if __name__ == '__main__':
args = parse_args()

View File

@ -37,14 +37,13 @@
# statement in the inventory script. However, you can specify an absolute
# path to the secrets.py file with 'libcloud_secrets' parameter.
# This option will be deprecated in a future release.
libcloud_secrets =
libcloud_secrets =
# If you are not going to use a 'secrets.py' file, you can set the necessary
# authorization parameters here.
gce_service_account_email_address =
gce_service_account_pem_file_path =
gce_project_id =
gce_zone =
gce_service_account_email_address =
gce_service_account_pem_file_path =
gce_project_id =
# Filter inventory based on on state. Leave undefined to return instances regardless of state.
# example: Uncomment to only return inventory in the running or provisioning state

View File

@ -40,7 +40,6 @@ based on the data obtained from the libcloud Node object:
- gce_tags
- gce_metadata
- gce_network
- gce_subnetwork
When run in --list mode, instances are grouped by the following categories:
- zone:
@ -74,6 +73,7 @@ Contributors: Matt Hite <mhite@hotmail.com>, Tom Melendez <supertom@google.com>
Version: 0.0.3
'''
__requires__ = ['pycrypto>=2.6']
try:
import pkg_resources
except ImportError:
@ -83,8 +83,8 @@ except ImportError:
# library is used.
pass
USER_AGENT_PRODUCT = "Ansible-gce_inventory_plugin"
USER_AGENT_VERSION = "v2"
USER_AGENT_PRODUCT="Ansible-gce_inventory_plugin"
USER_AGENT_VERSION="v2"
import sys
import os
@ -92,10 +92,7 @@ import argparse
from time import time
if sys.version_info >= (3, 0):
import configparser
else:
import ConfigParser as configparser
import ConfigParser
import logging
logging.getLogger('libcloud.common.google').addHandler(logging.NullHandler())
@ -216,11 +213,10 @@ class GceInventory(object):
# This provides empty defaults to each key, so that environment
# variable configuration (as opposed to INI configuration) is able
# to work.
config = configparser.SafeConfigParser(defaults={
config = ConfigParser.SafeConfigParser(defaults={
'gce_service_account_email_address': '',
'gce_service_account_pem_file_path': '',
'gce_project_id': '',
'gce_zone': '',
'libcloud_secrets': '',
'inventory_ip_type': '',
'cache_path': '~/.ansible/tmp',
@ -274,11 +270,10 @@ class GceInventory(object):
# exists.
secrets_path = self.config.get('gce', 'libcloud_secrets')
secrets_found = False
try:
import secrets
args = list(secrets.GCE_PARAMS)
kwargs = secrets.GCE_KEYWORD_PARAMS
args = list(getattr(secrets, 'GCE_PARAMS', []))
kwargs = getattr(secrets, 'GCE_KEYWORD_PARAMS', {})
secrets_found = True
except:
pass
@ -296,23 +291,18 @@ class GceInventory(object):
secrets_found = True
except:
pass
if not secrets_found:
args = [
self.config.get('gce', 'gce_service_account_email_address'),
self.config.get('gce', 'gce_service_account_pem_file_path')
self.config.get('gce','gce_service_account_email_address'),
self.config.get('gce','gce_service_account_pem_file_path')
]
kwargs = {'project': self.config.get('gce', 'gce_project_id'),
'datacenter': self.config.get('gce', 'gce_zone')}
kwargs = {'project': self.config.get('gce', 'gce_project_id')}
# If the appropriate environment variables are set, they override
# other configuration; process those into our args and kwargs.
args[0] = os.environ.get('GCE_EMAIL', args[0])
args[1] = os.environ.get('GCE_PEM_FILE_PATH', args[1])
args[1] = os.environ.get('GCE_CREDENTIALS_FILE_PATH', args[1])
kwargs['project'] = os.environ.get('GCE_PROJECT', kwargs['project'])
kwargs['datacenter'] = os.environ.get('GCE_ZONE', kwargs['datacenter'])
# Retrieve and return the GCE driver.
gce = get_driver(Provider.GCE)(*args, **kwargs)
@ -325,7 +315,7 @@ class GceInventory(object):
'''returns a list of comma separated zones parsed from the GCE_ZONE environment variable.
If provided, this will be used to filter the results of the grouped_instances call'''
import csv
reader = csv.reader([os.environ.get('GCE_ZONE', "")], skipinitialspace=True)
reader = csv.reader([os.environ.get('GCE_ZONE',"")], skipinitialspace=True)
zones = [r for r in reader]
return [z for z in zones[0]]
@ -335,16 +325,17 @@ class GceInventory(object):
parser = argparse.ArgumentParser(
description='Produce an Ansible Inventory file based on GCE')
parser.add_argument('--list', action='store_true', default=True,
help='List instances (default: True)')
help='List instances (default: True)')
parser.add_argument('--host', action='store',
help='Get all information about an instance')
help='Get all information about an instance')
parser.add_argument('--pretty', action='store_true', default=False,
help='Pretty format (default: False)')
help='Pretty format (default: False)')
parser.add_argument(
'--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests (default: False - use cache files)')
self.args = parser.parse_args()
def node_to_dict(self, inst):
md = {}
@ -356,9 +347,6 @@ class GceInventory(object):
md[entry['key']] = entry['value']
net = inst.extra['networkInterfaces'][0]['network'].split('/')[-1]
subnet = None
if 'subnetwork' in inst.extra['networkInterfaces'][0]:
subnet = inst.extra['networkInterfaces'][0]['subnetwork'].split('/')[-1]
# default to exernal IP unless user has specified they prefer internal
if self.ip_type == 'internal':
ssh_host = inst.private_ips[0]
@ -379,7 +367,6 @@ class GceInventory(object):
'gce_tags': inst.extra['tags'],
'gce_metadata': md,
'gce_network': net,
'gce_subnetwork': subnet,
# Hosts don't have a public name, so we add an IP
'ansible_ssh_host': ssh_host
}
@ -407,7 +394,7 @@ class GceInventory(object):
all_nodes = []
params, more_results = {'maxResults': 500}, True
while more_results:
self.driver.connection.gce_params = params
self.driver.connection.gce_params=params
all_nodes.extend(self.driver.list_nodes())
more_results = 'pageToken' in params
return all_nodes
@ -483,13 +470,6 @@ class GceInventory(object):
else:
groups[stat] = [name]
for private_ip in node.private_ips:
groups[private_ip] = [name]
if len(node.public_ips) >= 1:
for public_ip in node.public_ips:
groups[public_ip] = [name]
groups["_meta"] = meta
return groups

View File

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
from subprocess import Popen,PIPE
import sys
import json

View File

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
from subprocess import Popen,PIPE
import sys
import json

View File

@ -113,15 +113,11 @@ load_chube_config()
# Imports for ansible
import ConfigParser
class LinodeInventory(object):
def _empty_inventory(self):
return {"_meta": {"hostvars": {}}}
def __init__(self):
"""Main execution path."""
# Inventory grouped by display group
self.inventory = self._empty_inventory()
self.inventory = {}
# Index of label to Linode ID
self.index = {}
# Local cache of Datacenter objects populated by populate_datacenter_cache()
@ -142,7 +138,7 @@ class LinodeInventory(object):
data_to_print = self.get_host_info()
elif self.args.list:
# Display list of nodes for inventory
if len(self.inventory) == 1:
if len(self.inventory) == 0:
data_to_print = self.get_inventory_from_cache()
else:
data_to_print = self.json_format_dict(self.inventory, True)
@ -175,11 +171,11 @@ class LinodeInventory(object):
"""Command line argument processing"""
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on Linode')
parser.add_argument('--list', action='store_true', default=True,
help='List nodes (default: True)')
help='List nodes (default: True)')
parser.add_argument('--host', action='store',
help='Get all the variables about a specific node')
help='Get all the variables about a specific node')
parser.add_argument('--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests to Linode (default: False - use cache files)')
help='Force refresh of cache by making API requests to Linode (default: False - use cache files)')
self.args = parser.parse_args()
def do_api_calls_update_cache(self):
@ -235,15 +231,9 @@ class LinodeInventory(object):
# Inventory: Group by datacenter city
self.push(self.inventory, self.get_datacenter_city(node), dest)
# Inventory: Group by display group
# Inventory: Group by dipslay group
self.push(self.inventory, node.display_group, dest)
# Inventory: Add a "linode" global tag group
self.push(self.inventory, "linode", dest)
# Add host info to hostvars
self.inventory["_meta"]["hostvars"][dest] = self.get_host_info(node)
def get_node_public_ip(self, node):
"""Returns a the public IP address of the node"""
return [addr.address for addr in node.ipaddresses if addr.is_public][0]
@ -255,19 +245,16 @@ class LinodeInventory(object):
# Need to load index from cache
self.load_index_from_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# try updating the cache
self.do_api_calls_update_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# host might not exist anymore
return self.json_format_dict({}, True)
node_id = self.index[self.args.host]
node = self.get_node(node_id)
return self.json_format_dict(self.get_host_info(node), True)
def get_host_info(self, node):
node_vars = {}
for direct_attr in [
"api_id",
@ -308,7 +295,7 @@ class LinodeInventory(object):
if private_ips:
node_vars["private_ip"] = private_ips[0]
return node_vars
return self.json_format_dict(node_vars, True)
def push(self, my_dict, key, element):
"""Pushed an element onto an array that may not have been defined in the dict."""

View File

@ -35,7 +35,6 @@ import sys
import lxc
import json
def build_dict():
"""Returns a dictionary keyed to the defined LXC groups. All
containers, including the ones not in any group, are included in the
@ -52,8 +51,7 @@ def build_dict():
# Create a dictionary for each group (including the 'all' group
return dict([(g, {'hosts': [k for k, v in containers.items() if g in v],
'vars': {'ansible_connection': 'lxc'}}) for g in groups])
'vars': {'ansible_connection':'lxc'}}) for g in groups])
def main(argv):
"""Returns a JSON dictionary as expected by Ansible"""

View File

@ -1,13 +0,0 @@
# LXD external inventory script settings
[lxd]
# The default resource
#resource = local:
# The group name to add the hosts to
#group = lxd
# The connection type to return for these hosts - lxd hasn't been tested yet
#connection = lxd
connection = smart

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python
# (c) 2013, Michael Scherer <misc@zarb.org>
# (c) 2014, Hiroaki Nakamura <hnakamur@gmail.com>
# (c) 2016, Andew Clarke <andrew@oscailte.org>
#
# This file is based on https://github.com/ansible/ansible/blob/devel/plugins/inventory/libvirt_lxc.py which is part of Ansible,
# and https://github.com/hnakamur/lxc-ansible-playbooks/blob/master/provisioning/inventory-lxc.py
#
# NOTE, this file has some obvious limitations, improvements welcome
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import os
from subprocess import Popen, PIPE
import distutils.spawn
import sys
import json
try:
import configparser
except:
from six.moves import configparser
# Set up defaults
resource = 'local:'
group = 'lxd'
connection = 'lxd'
hosts = {}
result = {}
# Read the settings from the lxd.ini file
config = configparser.SafeConfigParser()
config.read(os.path.dirname(os.path.realpath(__file__)) + '/lxd.ini')
if config.has_option('lxd', 'resource'):
resource = config.get('lxd', 'resource')
if config.has_option('lxd', 'group'):
group = config.get('lxd', 'group')
if config.has_option('lxd', 'connection'):
connection = config.get('lxd', 'connection')
# Ensure executable exists
if distutils.spawn.find_executable('lxc'):
# Set up containers result and hosts array
result[group] = {}
result[group]['hosts'] = []
# Run the command and load json result
pipe = Popen(['lxc', 'list', resource, '--format', 'json'], stdout=PIPE, universal_newlines=True)
lxdjson = json.load(pipe.stdout)
# Iterate the json lxd output
for item in lxdjson:
# Check state and network
if 'state' in item and item['state'] is not None and 'network' in item['state']:
network = item['state']['network']
# Check for eth0 and addresses
if 'eth0' in network and 'addresses' in network['eth0']:
addresses = network['eth0']['addresses']
# Iterate addresses
for address in addresses:
# Only return inet family addresses
if 'family' in address and address['family'] == 'inet':
if 'address' in address:
ip = address['address']
name = item['name']
# Add the host to the results and the host array
result[group]['hosts'].append(name)
hosts[name] = ip
# Set the other containers result values
result[group]['vars'] = {}
result[group]['vars']['ansible_connection'] = connection
# Process arguments
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(result))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
if sys.argv[2] == 'localhost':
print(json.dumps({'ansible_connection': 'local'}))
else:
if connection == 'lxd':
print(json.dumps({'ansible_connection': connection}))
else:
print(json.dumps({'ansible_connection': connection, 'ansible_host': hosts[sys.argv[2]]}))
else:
print("Need an argument, either --list or --host <host>")

View File

@ -32,7 +32,6 @@ try:
except ImportError:
import ConfigParser as configparser
class MDTInventory(object):
def __init__(self):
@ -96,7 +95,7 @@ class MDTInventory(object):
'''
Create empty inventory dictionary
'''
return {"_meta": {"hostvars": {}}}
return {"_meta" : {"hostvars" : {}}}
def read_settings(self):
'''
@ -120,6 +119,7 @@ class MDTInventory(object):
if config.has_option('tower', 'groupname'):
self.mdt_groupname = config.get('tower', 'groupname')
def parse_cli_args(self):
'''
Command line argument processing

View File

@ -19,7 +19,7 @@
# default field group for host: groups
# Uncomment to override:
# group_field=state
# default fields retrieved: address, alias, display_name, children, parents
# default fields retrieved: address, alias, display_name, childs, parents
# To override, uncomment the following line
# fields_to_retrieve=address,alias,display_name
#

View File

@ -47,7 +47,6 @@ except ImportError:
print("Error: mk_livestatus is needed. Try something like: pip install python-mk-livestatus")
exit(1)
class NagiosLivestatusInventory(object):
def parse_ini_file(self):
@ -81,19 +80,19 @@ class NagiosLivestatusInventory(object):
# Local unix socket
unix_match = re.match('unix:(.*)', livestatus_uri)
if unix_match is not None:
backend_definition = {'connection': unix_match.group(1)}
backend_definition = { 'connection': unix_match.group(1) }
# Remote tcp connection
tcp_match = re.match('tcp:(.*):([^:]*)', livestatus_uri)
if tcp_match is not None:
backend_definition = {'connection': (tcp_match.group(1), int(tcp_match.group(2)))}
backend_definition = { 'connection': (tcp_match.group(1), int(tcp_match.group(2))) }
# No valid livestatus_uri => exiting
if backend_definition is None:
raise Exception('livestatus_uri field is invalid (%s). Expected: unix:/path/to/live or tcp:host:port' % livestatus_uri)
# Updating backend_definition with current value
backend_definition['name'] = section
backend_definition['name'] = section
backend_definition['fields'] = fields_to_retrieve
for key, value in section_values.items():
backend_definition[key] = value
@ -102,8 +101,8 @@ class NagiosLivestatusInventory(object):
def parse_options(self):
parser = argparse.ArgumentParser()
parser.add_argument('--host', nargs=1)
parser.add_argument('--list', action='store_true')
parser.add_argument('--host', nargs=1)
parser.add_argument('--list', action='store_true')
parser.add_argument('--pretty', action='store_true')
self.options = parser.parse_args()
@ -114,7 +113,7 @@ class NagiosLivestatusInventory(object):
if hostname not in self.result[group]['hosts']:
self.result[group]['hosts'].append(hostname)
def query_backend(self, backend, host=None):
def query_backend(self, backend, host = None):
'''Query a livestatus backend'''
hosts_request = Socket(backend['connection']).hosts.columns(backend['host_field'], backend['group_field'])
@ -128,10 +127,10 @@ class NagiosLivestatusInventory(object):
hosts = hosts_request.call()
for host in hosts:
hostname = host[backend['host_field']]
hostname = host[backend['host_field']]
hostgroups = host[backend['group_field']]
if not isinstance(hostgroups, list):
hostgroups = [hostgroups]
hostgroups = [ hostgroups ]
self.add_host(hostname, 'all')
self.add_host(hostname, backend['name'])
for group in hostgroups:
@ -167,9 +166,9 @@ class NagiosLivestatusInventory(object):
self.query_backend(backend, self.options.host)
if self.options.host:
print(json.dumps(self.result['_meta']['hostvars'][self.options.host[0]], indent=self.json_indent))
print(json.dumps(self.result['_meta']['hostvars'][self.options.host[0]], indent = self.json_indent))
elif self.options.list:
print(json.dumps(self.result, indent=self.json_indent))
print(json.dumps(self.result, indent = self.json_indent))
else:
print("usage: --list or --host HOSTNAME [--pretty]")
exit(1)

View File

@ -42,7 +42,6 @@ except ImportError:
print("Error: SQLAlchemy is needed. Try something like: pip install sqlalchemy")
exit(1)
class NagiosNDOInventory(object):
def read_settings(self):

View File

@ -142,7 +142,7 @@ def get_metadata(server):
key = 'os_' + re.sub(r"[^A-Za-z0-9\-]", "_", key).lower()
# Att value to instance result (exclude manager class)
# TODO: maybe use value.__class__ or similar inside of key_name
#TODO: maybe use value.__class__ or similar inside of key_name
if key != 'os_manager':
results[key] = value
return results

View File

@ -150,7 +150,6 @@ from click.exceptions import UsageError
from six import string_types
def warning(*objs):
print("WARNING: ", *objs, file=sys.stderr)

View File

@ -29,11 +29,8 @@
# - /etc/openstack/clouds.yaml
# - /etc/ansible/openstack.yml
# The clouds.yaml file can contain entries for multiple clouds and multiple
# regions of those clouds. If it does, this inventory module will by default
# connect to all of them and present them as one contiguous inventory. You
# can limit to one cloud by passing the `--cloud` parameter, or use the
# OS_CLOUD environment variable. If caching is enabled, and a cloud is
# selected, then per-cloud cache folders will be used.
# regions of those clouds. If it does, this inventory module will connect to
# all of them and present them as one contiguous inventory.
#
# See the adjacent openstack.yml file for an example config file
# There are two ansible inventory specific options that can be set in
@ -47,9 +44,6 @@
# has failed (for example, bad credentials or being offline).
# When set to False, the inventory will return hosts from
# whichever other clouds it can contact. (Default: True)
#
# Also it is possible to pass the correct user by setting an ansible_user: $myuser
# metadata attribute.
import argparse
import collections
@ -114,8 +108,8 @@ def get_groups_from_server(server_vars, namegroup=True):
return groups
def get_host_groups(inventory, refresh=False, cloud=None):
(cache_file, cache_expiration_time) = get_cache_settings(cloud)
def get_host_groups(inventory, refresh=False):
(cache_file, cache_expiration_time) = get_cache_settings()
if is_cache_stale(cache_file, cache_expiration_time, refresh=refresh):
groups = to_json(get_host_groups_from_cloud(inventory))
open(cache_file, 'w').write(groups)
@ -129,11 +123,6 @@ def append_hostvars(hostvars, groups, key, server, namegroup=False):
ansible_ssh_host=server['interface_ip'],
ansible_host=server['interface_ip'],
openstack=server)
metadata = server.get('metadata', {})
if 'ansible_user' in metadata:
hostvars[key]['ansible_user'] = metadata['ansible_user']
for group in get_groups_from_server(server, namegroup=namegroup):
groups[group].append(key)
@ -188,14 +177,12 @@ def is_cache_stale(cache_file, cache_expiration_time, refresh=False):
return True
def get_cache_settings(cloud=None):
def get_cache_settings():
config = os_client_config.config.OpenStackConfig(
config_files=os_client_config.config.CONFIG_FILES + CONFIG_FILES)
# For inventory-wide caching
cache_expiration_time = config.get_cache_expiration_time()
cache_path = config.get_cache_path()
if cloud:
cache_path = '{0}_{1}'.format(cache_path, cloud)
if not os.path.exists(cache_path):
os.makedirs(cache_path)
cache_file = os.path.join(cache_path, 'ansible-inventory.cache')
@ -208,8 +195,6 @@ def to_json(in_dict):
def parse_args():
parser = argparse.ArgumentParser(description='OpenStack Inventory Module')
parser.add_argument('--cloud', default=os.environ.get('OS_CLOUD'),
help='Cloud name (default: None')
parser.add_argument('--private',
action='store_true',
help='Use private address for ansible host')
@ -234,7 +219,6 @@ def main():
refresh=args.refresh,
config_files=config_files,
private=args.private,
cloud=args.cloud,
)
if hasattr(shade.inventory.OpenStackInventory, 'extra_config'):
inventory_args.update(dict(
@ -249,7 +233,7 @@ def main():
inventory = shade.inventory.OpenStackInventory(**inventory_args)
if args.list:
output = get_host_groups(inventory, refresh=args.refresh, cloud=args.cloud)
output = get_host_groups(inventory, refresh=args.refresh)
elif args.host:
output = to_json(inventory.get_host(args.host))
print(output)

View File

@ -26,31 +26,30 @@
# Groups are determined by the description field of openvz guests
# multiple groups can be separated by commas: webserver,dbserver
from subprocess import Popen, PIPE
from subprocess import Popen,PIPE
import sys
import json
# List openvz hosts
vzhosts = ['vzhost1', 'vzhost2', 'vzhost3']
# Add openvz hosts to the inventory and Add "_meta" trick
#List openvz hosts
vzhosts = ['vzhost1','vzhost2','vzhost3']
#Add openvz hosts to the inventory and Add "_meta" trick
inventory = {'vzhosts': {'hosts': vzhosts}, '_meta': {'hostvars': {}}}
# default group, when description not defined
#default group, when description not defined
default_group = ['vzguest']
def get_guests():
# Loop through vzhosts
#Loop through vzhosts
for h in vzhosts:
# SSH to vzhost and get the list of guests in json
pipe = Popen(['ssh', h, 'vzlist', '-j'], stdout=PIPE, universal_newlines=True)
#SSH to vzhost and get the list of guests in json
pipe = Popen(['ssh', h,'vzlist','-j'], stdout=PIPE, universal_newlines=True)
# Load Json info of guests
#Load Json info of guests
json_data = json.loads(pipe.stdout.read())
# loop through guests
#loop through guests
for j in json_data:
# Add information to host vars
#Add information to host vars
inventory['_meta']['hostvars'][j['hostname']] = {
'ctid': j['ctid'],
'veid': j['veid'],
@ -60,13 +59,13 @@ def get_guests():
'ip': j['ip']
}
# determine group from guest description
#determine group from guest description
if j['description'] is not None:
groups = j['description'].split(",")
else:
groups = default_group
# add guest to inventory
#add guest to inventory
for g in groups:
if g not in inventory:
inventory[g] = {'hosts': []}

View File

@ -230,7 +230,7 @@ class OVirtInventory(object):
"""
return [x.get_name() for x in inst.get_tags().list()]
def get_machine_type(self, inst):
def get_machine_type(self,inst):
inst_type = inst.get_instance_type()
if inst_type:
return self.driver.instancetypes.get(id=inst_type.id).name

View File

@ -182,9 +182,9 @@ def get_dict_of_struct(connection, vm):
(stat.name, stat.values[0].datum) for stat in stats
),
'devices': dict(
(device.name, [ip.address for ip in device.ips]) for device in devices if device.ips
(device.name, [ip.address for ip in device.ips]) for device in devices
),
'ansible_host': next((device.ips[0].address for device in devices if device.ips), None)
'ansible_host': devices[0].ips[0].address if len(devices) > 0 else None,
}

View File

@ -37,7 +37,6 @@ replace_dash_in_groups = True
# The packet inventory output can become very large. To manage its size,
# configure which groups should be created.
group_by_device_id = True
group_by_hostname = True
group_by_facility = True
group_by_project = True
group_by_operating_system = True

View File

@ -63,11 +63,10 @@ except ImportError:
ini_section = 'packet'
class PacketInventory(object):
def _empty_inventory(self):
return {"_meta": {"hostvars": {}}}
return {"_meta" : {"hostvars" : {}}}
def __init__(self):
''' Main execution path '''
@ -102,6 +101,7 @@ class PacketInventory(object):
print(data_to_print)
def is_cache_valid(self):
''' Determines if the cache files have expired, or if it is still valid '''
@ -175,7 +175,6 @@ class PacketInventory(object):
# Configure which groups should be created.
group_by_options = [
'group_by_device_id',
'group_by_hostname',
'group_by_facility',
'group_by_project',
'group_by_operating_system',
@ -225,13 +224,14 @@ class PacketInventory(object):
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on Packet')
parser.add_argument('--list', action='store_true', default=True,
help='List Devices (default: True)')
help='List Devices (default: True)')
parser.add_argument('--host', action='store',
help='Get all the variables about a specific device')
help='Get all the variables about a specific device')
parser.add_argument('--refresh-cache', action='store_true', default=False,
help='Force refresh of cache by making API requests to Packet (default: False - use cache files)')
help='Force refresh of cache by making API requests to Packet (default: False - use cache files)')
self.args = parser.parse_args()
def do_api_calls_update_cache(self):
''' Do API calls to each region, and save data in cache files '''
@ -244,7 +244,7 @@ class PacketInventory(object):
def connect(self):
''' create connection to api server'''
token = os.environ.get('PACKET_API_TOKEN')
token=os.environ.get('PACKET_API_TOKEN')
if token is None:
raise Exception("Error reading token from environment (PACKET_API_TOKEN)!")
manager = packet.Manager(auth_token=token)
@ -270,7 +270,7 @@ class PacketInventory(object):
try:
manager = self.connect()
devices = manager.list_devices(project_id=project.id, params=params)
devices = manager.list_devices(project_id=project.id, params = params)
for device in devices:
self.add_device(device, project)
@ -307,6 +307,7 @@ class PacketInventory(object):
if ip_address['public'] is True and ip_address['address_family'] == 4:
dest = ip_address['address']
if not dest:
# Skip devices we cannot address (e.g. private VPC subnet)
return
@ -328,12 +329,6 @@ class PacketInventory(object):
if self.nested_groups:
self.push_group(self.inventory, 'devices', device.id)
# Inventory: Group by device name (hopefully a group of 1)
if self.group_by_hostname:
self.push(self.inventory, device.hostname, dest)
if self.nested_groups:
self.push_group(self.inventory, 'hostnames', project.name)
# Inventory: Group by project
if self.group_by_project:
self.push(self.inventory, project.name, dest)
@ -378,6 +373,7 @@ class PacketInventory(object):
self.inventory["_meta"]["hostvars"][dest] = self.get_host_info_dict_from_device(device)
def get_host_info_dict_from_device(self, device):
device_vars = {}
for key in vars(device):
@ -389,7 +385,7 @@ class PacketInventory(object):
device_vars[key] = device.state or ''
elif key == 'packet_hostname':
device_vars[key] = value
elif isinstance(value, (int, bool)):
elif type(value) in [int, bool]:
device_vars[key] = value
elif isinstance(value, six.string_types):
device_vars[key] = value.strip()
@ -407,9 +403,9 @@ class PacketInventory(object):
device_vars[key] = k
else:
pass
# print key
# print type(value)
# print value
#print key
#print type(value)
#print value
return device_vars
@ -420,10 +416,10 @@ class PacketInventory(object):
# Need to load index from cache
self.load_index_from_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# try updating the cache
self.do_api_calls_update_cache()
if self.args.host not in self.index:
if not self.args.host in self.index:
# host might not exist anymore
return self.json_format_dict({}, True)
@ -459,6 +455,7 @@ class PacketInventory(object):
json_inventory = cache.read()
return json_inventory
def load_index_from_cache(self):
''' Reads the index from the cache file sets self.index '''
@ -466,6 +463,7 @@ class PacketInventory(object):
json_index = cache.read()
self.index = json.loads(json_index)
def write_to_cache(self, data, filename):
''' Writes data in JSON format to a file '''

View File

@ -25,6 +25,7 @@
#
# { "groups": ["utility", "databases"], "a": false, "b": true }
import urllib
try:
import json
except ImportError:
@ -34,16 +35,13 @@ import sys
from optparse import OptionParser
from six import iteritems
from six.moves.urllib.parse import urlencode
from ansible.module_utils.urls import open_url
class ProxmoxNodeList(list):
def get_names(self):
return [node['node'] for node in self]
class ProxmoxVM(dict):
def get_variables(self):
variables = {}
@ -51,11 +49,8 @@ class ProxmoxVM(dict):
variables['proxmox_' + key] = value
return variables
class ProxmoxVMList(list):
def __init__(self, data=None):
data = [] if data is None else data
def __init__(self, data=[]):
for item in data:
self.append(ProxmoxVM(item))
@ -73,17 +68,14 @@ class ProxmoxVMList(list):
return variables
class ProxmoxPoolList(list):
def get_names(self):
return [pool['poolid'] for pool in self]
class ProxmoxPool(dict):
def get_members_name(self):
return [member['name'] for member in self['members'] if member['template'] != 1]
class ProxmoxAPI(object):
def __init__(self, options):
self.options = options
@ -99,7 +91,7 @@ class ProxmoxAPI(object):
def auth(self):
request_path = '{}api2/json/access/ticket'.format(self.options.url)
request_params = urlencode({
request_params = urllib.urlencode({
'username': self.options.username,
'password': self.options.password,
})
@ -147,7 +139,6 @@ class ProxmoxAPI(object):
def pool(self, poolid):
return ProxmoxPool(self.get('api2/json/pools/{}'.format(poolid)))
def main_list(options):
results = {
'all': {
@ -208,7 +199,6 @@ def main_list(options):
return results
def main_host(options):
proxmox_api = ProxmoxAPI(options)
proxmox_api.auth()
@ -221,7 +211,6 @@ def main_host(options):
return {}
def main():
parser = OptionParser(usage='%prog [options] --list | --host HOSTNAME')
parser.add_option('--list', action="store_true", default=False, dest="list")
@ -246,6 +235,5 @@ def main():
print(json.dumps(data, indent=indent))
if __name__ == '__main__':
main()

View File

@ -1,46 +1,31 @@
#!/usr/bin/env python
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import json
import os
import requests
import os
import argparse
import types
RACKHD_URL = 'http://localhost:8080'
class RackhdInventory(object):
def __init__(self, nodeids):
self._inventory = {}
for nodeid in nodeids:
self._load_inventory_data(nodeid)
inventory = {}
for (nodeid, info) in self._inventory.items():
inventory[nodeid] = (self._format_output(nodeid, info))
for nodeid,info in self._inventory.items():
inventory[nodeid]= (self._format_output(nodeid, info))
print(json.dumps(inventory))
def _load_inventory_data(self, nodeid):
info = {}
info['ohai'] = RACKHD_URL + '/api/common/nodes/{0}/catalogs/ohai'.format(nodeid)
info['ohai'] = RACKHD_URL + '/api/common/nodes/{0}/catalogs/ohai'.format(nodeid )
info['lookup'] = RACKHD_URL + '/api/common/lookups/?q={0}'.format(nodeid)
results = {}
for (key, url) in info.items():
r = requests.get(url, verify=False)
for key,url in info.items():
r = requests.get( url, verify=False)
results[key] = r.text
self._inventory[nodeid] = results
@ -50,8 +35,8 @@ class RackhdInventory(object):
ipaddress = ''
if len(node_info) > 0:
ipaddress = node_info[0]['ipAddress']
output = {'hosts': [ipaddress], 'vars': {}}
for (key, result) in info.items():
output = { 'hosts':[ipaddress],'vars':{}}
for key,result in info.items():
output['vars'][key] = json.loads(result)
output['vars']['ansible_ssh_user'] = 'monorail'
except KeyError:
@ -65,12 +50,11 @@ def parse_args():
parser.add_argument('--list', action='store_true')
return parser.parse_args()
try:
# check if rackhd url(ie:10.1.1.45:8080) is specified in the environment
#check if rackhd url(ie:10.1.1.45:8080) is specified in the environment
RACKHD_URL = 'http://' + str(os.environ['RACKHD_URL'])
except:
# use default values
#use default values
pass
# Use the nodeid specified in the environment to limit the data returned
@ -86,7 +70,7 @@ if (parse_args().host):
if (parse_args().list):
try:
url = RACKHD_URL + '/api/common/nodes'
r = requests.get(url, verify=False)
r = requests.get( url, verify=False)
data = json.loads(r.text)
for entry in data:
if entry['type'] == 'compute':

View File

@ -168,11 +168,10 @@ except ImportError:
from time import time
from ansible.constants import get_config
from ansible.module_utils.parsing.convert_bool import boolean
from ansible.module_utils.six import text_type
from ansible.constants import get_config, mk_boolean
NON_CALLABLES = (text_type, str, bool, dict, int, list, type(None))
NON_CALLABLES = (basestring, bool, dict, int, list, type(None))
def load_config_file():
@ -230,22 +229,18 @@ def _list_into_cache(regions):
try:
# Ansible 2.3+
networks = get_config(p, 'rax', 'access_network',
'RAX_ACCESS_NETWORK', 'public', value_type='list')
'RAX_ACCESS_NETWORK', 'public', value_type='list')
except TypeError:
# Ansible 2.2.x and below
# pylint: disable=unexpected-keyword-arg
networks = get_config(p, 'rax', 'access_network',
'RAX_ACCESS_NETWORK', 'public', islist=True)
'RAX_ACCESS_NETWORK', 'public', islist=True)
try:
try:
# Ansible 2.3+
ip_versions = map(int, get_config(p, 'rax', 'access_ip_version',
'RAX_ACCESS_IP_VERSION', 4, value_type='list'))
'RAX_ACCESS_IP_VERSION', 4, value_type='list'))
except TypeError:
# Ansible 2.2.x and below
# pylint: disable=unexpected-keyword-arg
ip_versions = map(int, get_config(p, 'rax', 'access_ip_version',
'RAX_ACCESS_IP_VERSION', 4, islist=True))
'RAX_ACCESS_IP_VERSION', 4, islist=True))
except:
ip_versions = [4]
else:
@ -293,7 +288,7 @@ def _list_into_cache(regions):
if not cbs_attachments[region]:
cbs = pyrax.connect_to_cloud_blockstorage(region)
for vol in cbs.list():
if boolean(vol.bootable, strict=False):
if mk_boolean(vol.bootable):
for attachment in vol.attachments:
metadata = vol.volume_image_metadata
server_id = attachment['server_id']
@ -439,12 +434,11 @@ def setup():
try:
# Ansible 2.3+
region_list = get_config(p, 'rax', 'regions', 'RAX_REGION', 'all',
value_type='list')
value_type='list')
except TypeError:
# Ansible 2.2.x and below
# pylint: disable=unexpected-keyword-arg
region_list = get_config(p, 'rax', 'regions', 'RAX_REGION', 'all',
islist=True)
islist=True)
for region in region_list:
region = region.strip().upper()

View File

@ -41,7 +41,6 @@ try:
except:
import simplejson as json
class SoftLayerInventory(object):
common_items = [
'id',
@ -53,8 +52,7 @@ class SoftLayerInventory(object):
'primaryIpAddress',
'datacenter',
'tagReferences.tag.name',
'userData.value',
]
]
vs_items = [
'lastKnownPowerState.name',
@ -63,16 +61,16 @@ class SoftLayerInventory(object):
'maxMemory',
'activeTransaction.transactionStatus[friendlyName,name]',
'status',
]
]
hw_items = [
'hardwareStatusId',
'processorPhysicalCoreAmount',
'memoryCapacity',
]
]
def _empty_inventory(self):
return {"_meta": {"hostvars": {}}}
return {"_meta" : {"hostvars" : {}}}
def __init__(self):
'''Main path'''
@ -106,9 +104,9 @@ class SoftLayerInventory(object):
parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on SoftLayer')
parser.add_argument('--list', action='store_true', default=False,
help='List instances (default: False)')
help='List instances (default: False)')
parser.add_argument('--host', action='store',
help='Get all the variables about a specific instance')
help='Get all the variables about a specific instance')
self.args = parser.parse_args()
def json_format_dict(self, data, pretty=False):
@ -138,8 +136,6 @@ class SoftLayerInventory(object):
if 'primaryIpAddress' not in instance:
return
instance['userData'] = instance['userData'][0]['value'] if instance['userData'] else ''
dest = instance['primaryIpAddress']
self.inventory["_meta"]["hostvars"][dest] = instance
@ -178,7 +174,7 @@ class SoftLayerInventory(object):
def get_virtual_servers(self):
'''Get all the CCI instances'''
vs = SoftLayer.VSManager(self.client)
mask = "mask[%s]" % ','.join(itertools.chain(self.common_items, self.vs_items))
mask = "mask[%s]" % ','.join(itertools.chain(self.common_items,self.vs_items))
instances = vs.list_instances(mask=mask)
for instance in instances:
@ -187,7 +183,7 @@ class SoftLayerInventory(object):
def get_physical_servers(self):
'''Get all the hardware instances'''
hw = SoftLayer.HardwareManager(self.client)
mask = "mask[%s]" % ','.join(itertools.chain(self.common_items, self.hw_items))
mask = "mask[%s]" % ','.join(itertools.chain(self.common_items,self.hw_items))
instances = hw.list_hardware(mask=mask)
for instance in instances:

View File

@ -56,14 +56,11 @@ try:
except:
import simplejson as json
base_dir = os.path.dirname(os.path.realpath(__file__))
default_ini_file = os.path.join(base_dir, "spacewalk.ini")
base_dir = os.path.dirname(os.path.realpath(__file__))
SW_REPORT = '/usr/bin/spacewalk-report'
CACHE_DIR = os.path.join(base_dir, ".spacewalk_reports")
CACHE_AGE = 300 # 5min
INI_FILE = os.path.expanduser(os.path.expandvars(os.environ.get("SPACEWALK_INI_PATH", default_ini_file)))
CACHE_AGE = 300 # 5min
INI_FILE = os.path.join(base_dir, "spacewalk.ini")
# Sanity check
if not os.path.exists(SW_REPORT):
@ -76,8 +73,7 @@ if not os.path.exists(CACHE_DIR):
os.chmod(CACHE_DIR, 0o2775)
# Helper functions
# ------------------------------
#------------------------------
def spacewalk_report(name):
"""Yield a dictionary form of each CSV output produced by the specified
@ -95,7 +91,7 @@ def spacewalk_report(name):
lines = open(cache_filename, 'r').readlines()
keys = lines[0].strip().split(',')
# add 'spacewalk_' prefix to the keys
keys = ['spacewalk_' + key for key in keys]
keys = [ 'spacewalk_' + key for key in keys ]
for line in lines[1:]:
values = line.strip().split(',')
if len(keys) == len(values):
@ -103,7 +99,7 @@ def spacewalk_report(name):
# Options
# ------------------------------
#------------------------------
parser = OptionParser(usage="%prog [options] --list | --host <machine>")
parser.add_option('--list', default=False, dest="list", action="store_true",
@ -121,20 +117,20 @@ parser.add_option('-p', default=False, dest="prefix_org_name", action="store_tru
# read spacewalk.ini if present
# ------------------------------
#------------------------------
if os.path.exists(INI_FILE):
config = ConfigParser.SafeConfigParser()
config.read(INI_FILE)
if config.has_option('spacewalk', 'cache_age'):
CACHE_AGE = config.get('spacewalk', 'cache_age')
if not options.org_number and config.has_option('spacewalk', 'org_number'):
options.org_number = config.get('spacewalk', 'org_number')
if not options.prefix_org_name and config.has_option('spacewalk', 'prefix_org_name'):
options.prefix_org_name = config.getboolean('spacewalk', 'prefix_org_name')
if config.has_option('spacewalk' , 'cache_age'):
CACHE_AGE = config.get('spacewalk' , 'cache_age')
if not options.org_number and config.has_option('spacewalk' , 'org_number'):
options.org_number = config.get('spacewalk' , 'org_number')
if not options.prefix_org_name and config.has_option('spacewalk' , 'prefix_org_name'):
options.prefix_org_name = config.getboolean('spacewalk' , 'prefix_org_name')
# Generate dictionary for mapping group_id to org_id
# ------------------------------
#------------------------------
org_groups = {}
try:
for group in spacewalk_report('system-groups'):
@ -147,14 +143,14 @@ except (OSError) as e:
# List out the known server from Spacewalk
# ------------------------------
#------------------------------
if options.list:
# to build the "_meta"-Group with hostvars first create dictionary for later use
host_vars = {}
try:
for item in spacewalk_report('inventory'):
host_vars[item['spacewalk_profile_name']] = dict((key, (value.split(';') if ';' in value else value)) for key, value in item.items())
host_vars[ item['spacewalk_profile_name'] ] = dict( ( key, ( value.split(';') if ';' in value else value) ) for key, value in item.items() )
except (OSError) as e:
print('Problem executing the command "%s inventory": %s' %
@ -162,11 +158,11 @@ if options.list:
sys.exit(2)
groups = {}
meta = {"hostvars": {}}
meta = { "hostvars" : {} }
try:
for system in spacewalk_report('system-groups-systems'):
# first get org_id of system
org_id = org_groups[system['spacewalk_group_id']]
org_id = org_groups[ system['spacewalk_group_id'] ]
# shall we add the org_id as prefix to the group name:
if options.prefix_org_name:
@ -182,16 +178,16 @@ if options.list:
groups[group_name] = set()
groups[group_name].add(system['spacewalk_server_name'])
if system['spacewalk_server_name'] in host_vars and not system['spacewalk_server_name'] in meta["hostvars"]:
meta["hostvars"][system['spacewalk_server_name']] = host_vars[system['spacewalk_server_name']]
if system['spacewalk_server_name'] in host_vars and not system['spacewalk_server_name'] in meta[ "hostvars" ]:
meta[ "hostvars" ][ system['spacewalk_server_name'] ] = host_vars[ system['spacewalk_server_name'] ]
# or we list all groups and systems:
else:
if group_name not in groups:
groups[group_name] = set()
groups[group_name].add(system['spacewalk_server_name'])
if system['spacewalk_server_name'] in host_vars and not system['spacewalk_server_name'] in meta["hostvars"]:
meta["hostvars"][system['spacewalk_server_name']] = host_vars[system['spacewalk_server_name']]
if system['spacewalk_server_name'] in host_vars and not system['spacewalk_server_name'] in meta[ "hostvars" ]:
meta[ "hostvars" ][ system['spacewalk_server_name'] ] = host_vars[ system['spacewalk_server_name'] ]
except (OSError) as e:
print('Problem executing the command "%s system-groups-systems": %s' %
@ -202,15 +198,15 @@ if options.list:
for group, systems in iteritems(groups):
print('[%s]\n%s\n' % (group, '\n'.join(systems)))
else:
final = dict([(k, list(s)) for k, s in iteritems(groups)])
final = dict( [ (k, list(s)) for k, s in iteritems(groups) ] )
final["_meta"] = meta
print(json.dumps(final))
# print(json.dumps(groups))
print(json.dumps( final ))
#print(json.dumps(groups))
sys.exit(0)
# Return a details information concerning the spacewalk server
# ------------------------------
#------------------------------
elif options.host:
host_details = {}
@ -230,7 +226,7 @@ elif options.host:
for k, v in iteritems(host_details):
print(' %s: %s' % (k, '\n '.join(v.split(';'))))
else:
print(json.dumps(dict((key, (value.split(';') if ';' in value else value)) for key, value in host_details.items())))
print( json.dumps( dict( ( key, ( value.split(';') if ';' in value else value) ) for key, value in host_details.items() ) ) )
sys.exit(0)
else:

View File

@ -43,24 +43,21 @@
import argparse
import os.path
import sys
from collections import MutableSequence
import paramiko
try:
import json
except ImportError:
import simplejson as json
import paramiko
SSH_CONF = '~/.ssh/config'
_key = 'ssh_config'
_ssh_to_ansible = [('user', 'ansible_ssh_user'),
('hostname', 'ansible_ssh_host'),
('identityfile', 'ansible_ssh_private_key_file'),
('port', 'ansible_ssh_port')]
('hostname', 'ansible_ssh_host'),
('identityfile', 'ansible_ssh_private_key_file'),
('port', 'ansible_ssh_port')]
def get_config():
@ -71,7 +68,7 @@ def get_config():
cfg.parse(f)
ret_dict = {}
for d in cfg._config:
if isinstance(d['host'], MutableSequence):
if type(d['host']) is list:
alias = d['host'][0]
else:
alias = d['host']
@ -96,7 +93,7 @@ def print_list():
# If the attribute is a list, just take the first element.
# Private key is returned in a list for some reason.
attr = attributes[ssh_opt]
if isinstance(attr, MutableSequence):
if type(attr) is list:
attr = attr[0]
tmp_dict[ans_opt] = attr
if tmp_dict:

View File

@ -64,9 +64,9 @@ CONFIG_FILES = ['/etc/stacki/stacki.yml', '/etc/ansible/stacki.yml']
def stack_auth(params):
endpoint = params['stacki_endpoint']
auth_creds = {'USERNAME': params['stacki_user'],
'PASSWORD': params['stacki_password']}
endpoint = params['stacki_endpoint']
auth_creds = {'USERNAME': params['stacki_user'],
'PASSWORD': params['stacki_password']}
client = requests.session()
client.get(endpoint)
@ -99,18 +99,17 @@ def stack_build_header(auth_creds):
def stack_host_list(endpoint, header, client):
stack_r = client.post(endpoint, data=json.dumps({"cmd": "list host"}),
stack_r = client.post(endpoint, data=json.dumps({ "cmd": "list host"}),
headers=header)
return json.loads(stack_r.json())
def stack_net_list(endpoint, header, client):
stack_r = client.post(endpoint, data=json.dumps({"cmd": "list host interface"}),
stack_r = client.post(endpoint, data=json.dumps({ "cmd": "list host interface"}),
headers=header)
return json.loads(stack_r.json())
def format_meta(hostdata, intfdata, config):
use_hostnames = config['use_hostnames']
meta = dict(all=dict(hosts=list()),
@ -160,6 +159,7 @@ def parse_args():
def main():
args = parse_args()
if StrictVersion(requests.__version__) < StrictVersion("2.4.3"):
sys.exit('requests>=2.4.3 is required for this inventory script')

View File

@ -16,21 +16,20 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import sys
from subprocess import Popen, PIPE
from subprocess import Popen,PIPE
try:
import json
except ImportError:
import simplejson as json
class SetEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
VBOX = "VBoxManage"
VBOX="VBoxManage"
def get_hosts(host=None):
@ -40,7 +39,7 @@ def get_hosts(host=None):
if host:
p = Popen([VBOX, 'showvminfo', host], stdout=PIPE)
else:
returned = {'all': set(), '_metadata': {}}
returned = { 'all': set(), '_metadata': {} }
p = Popen([VBOX, 'list', '-l', 'vms'], stdout=PIPE)
except:
sys.exit(1)
@ -51,7 +50,7 @@ def get_hosts(host=None):
for line in p.stdout.readlines():
try:
k, v = line.split(':', 1)
k,v = line.split(':',1)
except:
continue
@ -63,11 +62,11 @@ def get_hosts(host=None):
if v not in hostvars:
curname = v
hostvars[curname] = {}
try: # try to get network info
x = Popen([VBOX, 'guestproperty', 'get', curname, "/VirtualBox/GuestInfo/Net/0/V4/IP"], stdout=PIPE)
try: # try to get network info
x = Popen([VBOX, 'guestproperty', 'get', curname,"/VirtualBox/GuestInfo/Net/0/V4/IP"],stdout=PIPE)
ipinfo = x.stdout.read()
if 'Value' in ipinfo:
a, ip = ipinfo.split(':', 1)
a,ip = ipinfo.split(':',1)
hostvars[curname]['ansible_ssh_host'] = ip.strip()
except:
pass
@ -84,11 +83,11 @@ def get_hosts(host=None):
returned['all'].add(curname)
continue
pref_k = 'vbox_' + k.strip().replace(' ', '_')
pref_k = 'vbox_' + k.strip().replace(' ','_')
if k.startswith(' '):
if prevkey not in hostvars[curname]:
hostvars[curname][prevkey] = {}
hostvars[curname][prevkey][pref_k] = v
hostvars[curname][prevkey][pref_k]= v
else:
if v != '':
hostvars[curname][pref_k] = v

View File

@ -38,20 +38,18 @@ import os
import ssl
import sys
import time
import ConfigParser
from six import integer_types, text_type, string_types
from six.moves import configparser
from six import text_type, string_types
# Disable logging message trigged by pSphere/suds.
try:
from logging import NullHandler
except ImportError:
from logging import Handler
class NullHandler(Handler):
def emit(self, record):
pass
logging.getLogger('psphere').addHandler(NullHandler())
logging.getLogger('suds').addHandler(NullHandler())
@ -64,11 +62,11 @@ from suds.sudsobject import Object as SudsObject
class VMwareInventory(object):
def __init__(self, guests_only=None):
self.config = configparser.SafeConfigParser()
self.config = ConfigParser.SafeConfigParser()
if os.environ.get('VMWARE_INI', ''):
config_files = [os.environ['VMWARE_INI']]
else:
config_files = [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']
config_files = [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']
for config_file in config_files:
if os.path.exists(config_file):
self.config.read(config_file)
@ -210,7 +208,7 @@ class VMwareInventory(object):
if obj_info != ():
l.append(obj_info)
return l
elif isinstance(obj, (type(None), bool, float) + string_types + integer_types):
elif isinstance(obj, (type(None), bool, int, long, float, string_types)):
return obj
else:
return ()
@ -364,7 +362,7 @@ class VMwareInventory(object):
# Loop through all VMs on physical host.
for vm in host.vm:
if prefix_filter:
if vm.name.startswith(prefix_filter):
if vm.name.startswith( prefix_filter ):
continue
self._add_host(inv, 'all', vm.name)
self._add_host(inv, vm_group, vm.name)

View File

@ -1,19 +1,4 @@
#!/usr/bin/env python
#
# This file is part of Ansible,
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Requirements
# - pyvmomi >= 6.0.0.2016.4
@ -38,34 +23,34 @@ $ jq '._meta.hostvars[].config' data.json | head
from __future__ import print_function
import argparse
import atexit
import datetime
import getpass
import itertools
import json
import jinja2
import os
import re
import six
import ssl
import sys
import uuid
from collections import defaultdict
from six.moves import configparser
from time import time
import six
from jinja2 import Environment
from six import integer_types, string_types
from six.moves import configparser
HAS_PYVMOMI = False
try:
import argparse
except ImportError:
sys.exit('Error: This inventory script required "argparse" python module. Please install it or upgrade to python-2.7')
try:
from pyVmomi import vim, vmodl
from pyVmomi import vim
from pyVim.connect import SmartConnect, Disconnect
HAS_PYVMOMI = True
except ImportError:
sys.exit("ERROR: This inventory script required 'pyVmomi' Python module, it was not able to load it")
pass
try:
import json
except ImportError:
import simplejson as json
hasvcr = False
try:
@ -76,23 +61,6 @@ except ImportError:
pass
def regex_match(s, pattern):
'''Custom filter for regex matching'''
reg = re.compile(pattern)
if reg.match(s):
return True
else:
return False
def select_chain_match(inlist, key, pattern):
'''Get a key from a list of dicts, squash values to a single list, then filter'''
outlist = [x[key] for x in inlist]
outlist = list(itertools.chain(*outlist))
outlist = [x for x in outlist if regex_match(x, pattern)]
return outlist
class VMwareMissingHostException(Exception):
pass
@ -121,7 +89,10 @@ class VMWareInventory(object):
skip_keys = []
groupby_patterns = []
safe_types = [bool, str, float, None] + list(integer_types)
if sys.version_info > (3, 0):
safe_types = [int, bool, str, float, None]
else:
safe_types = [int, long, bool, str, float, None]
iter_types = [dict, list]
bad_types = ['Array', 'disabledMethod', 'declaredAlarmState']
@ -133,18 +104,15 @@ class VMWareInventory(object):
custom_fields = {}
# use jinja environments to allow for custom filters
env = Environment()
env.filters['regex_match'] = regex_match
env.filters['select_chain_match'] = select_chain_match
# translation table for attributes to fetch for known vim types
vimTable = {
vim.Datastore: ['_moId', 'name'],
vim.ResourcePool: ['_moId', 'name'],
vim.HostSystem: ['_moId', 'name'],
}
if not HAS_PYVMOMI:
vimTable = {}
else:
vimTable = {
vim.Datastore: ['_moId', 'name'],
vim.ResourcePool: ['_moId', 'name'],
vim.HostSystem: ['_moId', 'name'],
}
@staticmethod
def _empty_inventory():
@ -365,21 +333,13 @@ class VMWareInventory(object):
''' Make API calls '''
instances = []
try:
si = SmartConnect(**inkwargs)
except ssl.SSLError as connection_error:
if '[SSL: CERTIFICATE_VERIFY_FAILED]' in str(connection_error) and self.validate_certs:
sys.exit("Unable to connect to ESXi server due to %s, "
"please specify validate_certs=False and try again" % connection_error)
except Exception as exc:
self.debugl("Unable to connect to ESXi server due to %s" % exc)
sys.exit("Unable to connect to ESXi server due to %s" % exc)
si = SmartConnect(**inkwargs)
self.debugl('retrieving all instances')
if not si:
sys.exit("Could not connect to the specified host using specified "
"username and password")
print("Could not connect to the specified host using specified "
"username and password")
return -1
atexit.register(Disconnect, si)
content = si.RetrieveContent()
@ -410,16 +370,12 @@ class VMWareInventory(object):
instance_tuples.append((instance, ifacts))
self.debugl('facts collected for all instances')
try:
cfm = content.customFieldsManager
if cfm is not None and cfm.field:
for f in cfm.field:
if f.managedObjectType == vim.VirtualMachine:
self.custom_fields[f.key] = f.name
self.debugl('%d custom fields collected' % len(self.custom_fields))
except vmodl.RuntimeFault as exc:
self.debugl("Unable to gather custom fields due to %s" % exc.msg)
cfm = content.customFieldsManager
if cfm is not None and cfm.field:
for f in cfm.field:
if f.managedObjectType == vim.VirtualMachine:
self.custom_fields[f.key] = f.name
self.debugl('%d custom fieds collected' % len(self.custom_fields))
return instance_tuples
def instances_to_inventory(self, instances):
@ -456,7 +412,7 @@ class VMWareInventory(object):
# Reset the inventory keys
for k, v in name_mapping.items():
if not host_mapping or k not in host_mapping:
if not host_mapping or not k in host_mapping:
continue
# set ansible_host (2.x)
@ -511,7 +467,7 @@ class VMWareInventory(object):
for k, v in inventory['_meta']['hostvars'].items():
if 'customvalue' in v:
for tv in v['customvalue']:
if not isinstance(tv['value'], string_types):
if not isinstance(tv['value'], str) and not isinstance(tv['value'], unicode):
continue
newkey = None
@ -542,7 +498,7 @@ class VMWareInventory(object):
mapping = {}
for k, v in inventory['_meta']['hostvars'].items():
t = self.env.from_string(pattern)
t = jinja2.Template(pattern)
newkey = None
try:
newkey = t.render(v)
@ -588,27 +544,15 @@ class VMWareInventory(object):
for idx, x in enumerate(parts):
if isinstance(val, dict):
if x in val:
val = val.get(x)
elif x.lower() in val:
val = val.get(x.lower())
# if the val wasn't set yet, get it from the parent
if not val:
val = getattr(vm, x)
else:
# if the val wasn't set yet, get it from the parent
if not val:
try:
val = getattr(vm, x)
except AttributeError as e:
self.debugl(e)
else:
# in a subkey, get the subprop from the previous attrib
try:
val = getattr(val, x)
except AttributeError as e:
self.debugl(e)
# make sure it serializes
val = self._process_object_types(val)
# in a subkey, get the subprop from the previous attrib
try:
val = getattr(val, x)
except AttributeError as e:
self.debugl(e)
# lowercase keys if requested
if self.lowerkeys:
@ -672,7 +616,7 @@ class VMWareInventory(object):
return rdata
def _process_object_types(self, vobj, thisvm=None, inkey='', level=0):
def _process_object_types(self, vobj, thisvm=None, inkey=None, level=0):
''' Serialize an object '''
rdata = {}
@ -696,10 +640,12 @@ class VMWareInventory(object):
rdata = vobj.decode('ascii', 'ignore')
elif issubclass(type(vobj), bool) or isinstance(vobj, bool):
rdata = vobj
elif issubclass(type(vobj), integer_types) or isinstance(vobj, integer_types):
elif issubclass(type(vobj), int) or isinstance(vobj, int):
rdata = vobj
elif issubclass(type(vobj), float) or isinstance(vobj, float):
rdata = vobj
elif issubclass(type(vobj), long) or isinstance(vobj, long):
rdata = vobj
elif issubclass(type(vobj), list) or issubclass(type(vobj), tuple):
rdata = []
try:
@ -764,7 +710,7 @@ class VMWareInventory(object):
return self.inventory['_meta']['hostvars'][host]
elif self.args.host and self.inventory['_meta']['hostvars']:
match = None
for k, v in self.inventory['_meta']['hostvars'].items():
for k, v in self.inventory['_meta']['hostvars']:
if self.inventory['_meta']['hostvars'][k]['name'] == self.args.host:
match = k
break
@ -779,3 +725,5 @@ class VMWareInventory(object):
if __name__ == "__main__":
# Run the script
print(VMWareInventory().show())

View File

@ -54,7 +54,6 @@ except ImportError as e:
# Imports for ansible
import ConfigParser
class AzureInventory(object):
def __init__(self):
"""Main execution path."""
@ -172,9 +171,10 @@ class AzureInventory(object):
parser.add_argument('--list-images', action='store',
help='Get all available images.')
parser.add_argument('--refresh-cache',
action='store_true', default=False,
help='Force refresh of thecache by making API requests to Azure '
'(default: False - use cache files)')
action='store_true', default=False,
help='Force refresh of thecache by making API requests to Azure '
'(default: False - use cache files)',
)
parser.add_argument('--host', action='store',
help='Get all information about an instance.')
self.args = parser.parse_args()
@ -198,7 +198,7 @@ class AzureInventory(object):
associated with a cloud service.
"""
try:
for deployment in self.sms.get_hosted_service_properties(cloud_service.service_name, embed_detail=True).deployments.deployments:
for deployment in self.sms.get_hosted_service_properties(cloud_service.service_name,embed_detail=True).deployments.deployments:
self.add_deployment(cloud_service, deployment)
except Exception as e:
sys.exit("Error: Failed to access deployments - {0}".format(str(e)))

View File

@ -24,12 +24,10 @@ Zabbix Server external inventory script.
========================================
Returns hosts and hostgroups from Zabbix Server.
If you want to run with --limit against a host group with space in the
name, use asterisk. For example --limit="Linux*servers".
Configuration is read from `zabbix.ini`.
Tested with Zabbix Server 2.0.6 and 3.2.3.
Tested with Zabbix Server 2.0.6.
"""
from __future__ import print_function
@ -37,10 +35,7 @@ from __future__ import print_function
import os
import sys
import argparse
try:
import ConfigParser as configparser
except ImportError:
import configparser
import ConfigParser
try:
from zabbix_api import ZabbixAPI
@ -54,11 +49,10 @@ try:
except:
import simplejson as json
class ZabbixInventory(object):
def read_settings(self):
config = configparser.SafeConfigParser()
config = ConfigParser.SafeConfigParser()
conf_path = './zabbix.ini'
if not os.path.exists(conf_path):
conf_path = os.path.dirname(os.path.realpath(__file__)) + '/zabbix.ini'
@ -102,14 +96,11 @@ class ZabbixInventory(object):
for group in host['groups']:
groupname = group['name']
if groupname not in data:
if not groupname in data:
data[groupname] = self.hoststub()
data[groupname]['hosts'].append(hostname)
# Prevents Ansible from calling this script for each server with --host
data['_meta'] = {'hostvars': self.meta}
return data
def __init__(self):
@ -118,7 +109,6 @@ class ZabbixInventory(object):
self.zabbix_server = None
self.zabbix_username = None
self.zabbix_password = None
self.meta = {}
self.read_settings()
self.read_cli()

View File

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from subprocess import Popen, PIPE
from subprocess import Popen,PIPE
import sys
import json

View File

@ -14,9 +14,14 @@ PAPER =
BUILDDIR = _build
RSTDIR = rst
MODULES_PATH = ../../lib
EXCLUDE_PATHS = ../../lib/ansible/modules ../../lib/ansible/utils/module_docs_fragments ../../lib/ansible/module_utils/six
EXCLUDE_PATHS = ../../lib/ansible/modules ../../lib/ansible/utils/module_docs_fragments ../../lib/ansible/compat/six ../../lib/ansible/module_utils/six.py
DOC_PROJECTS = "Ansible API"
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter

View File

@ -18,7 +18,7 @@ import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('../bin'))
#sys.path.insert(0, os.path.abspath('../bin'))
sys.path.insert(0, os.path.abspath('../lib/ansible'))
import sphinx_rtd_theme
import alabaster
@ -26,7 +26,7 @@ import alabaster
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@ -41,8 +41,8 @@ extensions = [
'alabaster',
]
# autodoc_default_flags = ['members', 'show-inheritance', 'inherited-members', 'undoc-members', ]
autodoc_default_flags = ['members', 'show-inheritance', 'undoc-members', ]
#autodoc_default_flags = ['members', 'show-inheritance', 'inherited-members', 'undoc-members',]
autodoc_default_flags = ['members', 'show-inheritance', 'undoc-members',]
autoclass_content = 'both'
autodoc_member_order = 'bysource'
autodoc_mock_imports = ['xmltodict', 'winrm', 'redis', 'StricRedis']
@ -56,7 +56,7 @@ templates_path = ['_templates']
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@ -84,9 +84,9 @@ language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
#today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -94,27 +94,27 @@ exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
@ -124,13 +124,13 @@ todo_include_todos = True
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = 'alabaster'
# html_theme_path = ['../docsite/_themes']
# html_theme = 'srtd'
#html_theme = 'alabaster'
#html_theme_path = ['../docsite/_themes']
#html_theme = 'srtd'
html_short_title = 'Ansible Documentation'
# html_theme = "sphinx_rtd_theme"
# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
#html_theme = "sphinx_rtd_theme"
#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_theme_path = [alabaster.get_path()]
html_theme = 'alabaster'
@ -138,26 +138,26 @@ html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
#html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@ -167,62 +167,62 @@ html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y'
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
#html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
#html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
#html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
#html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
# html_search_language = 'en'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
# html_search_options = {'type': 'default'}
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'Ansibledoc'
@ -231,16 +231,16 @@ htmlhelp_basename = 'Ansibledoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
#'preamble': '',
# Latex figure (float) alignment
# 'figure_align': 'htbp',
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
@ -253,23 +253,23 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
#latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
#latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
@ -282,7 +282,7 @@ man_pages = [
]
# If true, show URL addresses after external links.
# man_show_urls = False
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@ -297,13 +297,13 @@ texinfo_documents = [
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
#texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
#texinfo_no_detailmenu = False

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python
import optparse
import os
import sys
import yaml
from jinja2 import Environment, FileSystemLoader
DEFAULT_TEMPLATE_FILE = 'config.rst.j2'
def generate_parser():
p = optparse.OptionParser(
version='%prog 1.0',
usage='usage: %prog [options]',
description='Generate module documentation from metadata',
)
p.add_option("-t", "--template-file", action="store", dest="template_file", default=DEFAULT_TEMPLATE_FILE, help="directory containing Jinja2 templates")
p.add_option("-o", "--output-dir", action="store", dest="output_dir", default='/tmp/', help="Output directory for rst files")
p.add_option("-d", "--docs-source", action="store", dest="docs", default=None, help="Source for attribute docs")
(options, args) = p.parse_args()
return p
def fix_description(config_options):
'''some descriptions are strings, some are lists. workaround it...'''
for config_key in config_options:
description = config_options[config_key].get('description', [])
if isinstance(description, list):
desc_list = description
else:
desc_list = [description]
config_options[config_key]['description'] = desc_list
return config_options
def main(args):
parser = generate_parser()
(options, args) = parser.parse_args()
output_dir = os.path.abspath(options.output_dir)
template_file_full_path = os.path.abspath(options.template_file)
template_file = os.path.basename(template_file_full_path)
template_dir = os.path.dirname(os.path.abspath(template_file_full_path))
if options.docs:
with open(options.docs) as f:
docs = yaml.safe_load(f)
else:
docs = {}
config_options = docs
config_options = fix_description(config_options)
env = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True,)
template = env.get_template(template_file)
output_name = os.path.join(output_dir, template_file.replace('.j2', ''))
temp_vars = {'config_options': config_options}
with open(output_name, 'w') as f:
f.write(template.render(temp_vars).encode('utf-8'))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[:]))

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python
import optparse
import yaml
from jinja2 import Environment, FileSystemLoader
from ansible.playbook import Play
from ansible.playbook.block import Block
from ansible.playbook.role import Role
from ansible.playbook.task import Task
template_file = 'playbooks_keywords.rst.j2'
oblist = {}
clist = []
class_list = [Play, Role, Block, Task]
p = optparse.OptionParser(
version='%prog 1.0',
usage='usage: %prog [options]',
description='Generate module documentation from metadata',
)
p.add_option("-T", "--template-dir", action="store", dest="template_dir", default="../templates", help="directory containing Jinja2 templates")
p.add_option("-o", "--output-dir", action="store", dest="output_dir", default='/tmp/', help="Output directory for rst files")
p.add_option("-d", "--docs-source", action="store", dest="docs", default=None, help="Source for attribute docs")
(options, args) = p.parse_args()
for aclass in class_list:
aobj = aclass()
name = type(aobj).__name__
if options.docs:
with open(options.docs) as f:
docs = yaml.safe_load(f)
else:
docs = {}
# build ordered list to loop over and dict with attributes
clist.append(name)
oblist[name] = dict((x, aobj.__dict__['_attributes'][x]) for x in aobj.__dict__['_attributes'] if 'private' not in x or not x.private)
# pick up docs if they exist
for a in oblist[name]:
if a in docs:
oblist[name][a] = docs[a]
else:
oblist[name][a] = ' UNDOCUMENTED!! '
# loop is really with_ for users
if name == 'Task':
oblist[name]['with_<lookup_plugin>'] = 'with_ is how loops are defined, it can use any available lookup plugin to generate the item list'
# local_action is implicit with action
if 'action' in oblist[name]:
oblist[name]['local_action'] = 'Same as action but also implies ``delegate_to: localhost``'
# remove unusable (used to be private?)
for nouse in ('loop', 'loop_args'):
if nouse in oblist[name]:
del oblist[name][nouse]
env = Environment(loader=FileSystemLoader(options.template_dir), trim_blocks=True,)
template = env.get_template(template_file)
outputname = options.output_dir + template_file.replace('.j2', '')
tempvars = {'oblist': oblist, 'clist': clist}
with open(outputname, 'w') as f:
f.write(template.render(tempvars))

View File

@ -1,280 +0,0 @@
#!/usr/bin/env python
import optparse
import os
import pprint
import sys
from jinja2 import Environment, FileSystemLoader
from ansible.module_utils._text import to_bytes
def generate_parser():
p = optparse.OptionParser(
version='%prog 1.0',
usage='usage: %prog [options]',
description='Generate cli documentation from cli docstrings',
)
p.add_option("-t", "--template-file", action="store", dest="template_file", default="../templates/man.j2", help="path to jinja2 template")
p.add_option("-o", "--output-dir", action="store", dest="output_dir", default='/tmp/', help="Output directory for rst files")
p.add_option("-f", "--output-format", action="store", dest="output_format", default='man', help="Output format for docs (the default 'man' or 'rst')")
return p
# from https://www.python.org/dev/peps/pep-0257/
def trim_docstring(docstring):
if not docstring:
return ''
# Convert tabs to spaces (following the normal Python rules)
# and split into a list of lines:
lines = docstring.expandtabs().splitlines()
# Determine minimum indentation (first line doesn't count):
indent = sys.maxsize
for line in lines[1:]:
stripped = line.lstrip()
if stripped:
indent = min(indent, len(line) - len(stripped))
# Remove indentation (first line is special):
trimmed = [lines[0].strip()]
if indent < sys.maxsize:
for line in lines[1:]:
trimmed.append(line[indent:].rstrip())
# Strip off trailing and leading blank lines:
while trimmed and not trimmed[-1]:
trimmed.pop()
while trimmed and not trimmed[0]:
trimmed.pop(0)
# Return a single string:
return '\n'.join(trimmed)
def get_options(optlist):
''' get actual options '''
opts = []
for opt in optlist:
res = {
'desc': opt.help,
'options': opt._short_opts + opt._long_opts
}
if opt.action == 'store':
res['arg'] = opt.dest.upper()
opts.append(res)
return opts
def get_option_groups(option_parser):
groups = []
for option_group in option_parser.option_groups:
group_info = {}
group_info['desc'] = option_group.get_description()
group_info['options'] = option_group.option_list
group_info['group_obj'] = option_group
groups.append(group_info)
return groups
def opt_doc_list(cli):
''' iterate over options lists '''
results = []
for option_group in cli.parser.option_groups:
results.extend(get_options(option_group.option_list))
results.extend(get_options(cli.parser.option_list))
return results
# def opts_docs(cli, name):
def opts_docs(cli_class_name, cli_module_name):
''' generate doc structure from options '''
cli_name = 'ansible-%s' % cli_module_name
if cli_module_name == 'adhoc':
cli_name = 'ansible'
# WIth no action/subcommand
# shared opts set
# instantiate each cli and ask its options
cli_klass = getattr(__import__("ansible.cli.%s" % cli_module_name,
fromlist=[cli_class_name]), cli_class_name)
cli = cli_klass([])
# parse the common options
try:
cli.parse()
except:
pass
# base/common cli info
docs = {
'cli': cli_module_name,
'cli_name': cli_name,
'usage': cli.parser.usage,
'short_desc': cli.parser.description,
'long_desc': trim_docstring(cli.__doc__),
'actions': {},
}
option_info = {'option_names': [],
'options': [],
'groups': []}
for extras in ('ARGUMENTS'):
if hasattr(cli, extras):
docs[extras.lower()] = getattr(cli, extras)
common_opts = opt_doc_list(cli)
groups_info = get_option_groups(cli.parser)
shared_opt_names = []
for opt in common_opts:
shared_opt_names.extend(opt.get('options', []))
option_info['options'] = common_opts
option_info['option_names'] = shared_opt_names
option_info['groups'].extend(groups_info)
docs.update(option_info)
# now for each action/subcommand
# force populate parser with per action options
# use class attrs not the attrs on a instance (not that it matters here...)
for action in getattr(cli_klass, 'VALID_ACTIONS', ()):
# instantiate each cli and ask its options
action_cli_klass = getattr(__import__("ansible.cli.%s" % cli_module_name,
fromlist=[cli_class_name]), cli_class_name)
# init with args with action added?
cli = action_cli_klass([])
cli.args.append(action)
try:
cli.parse()
except:
pass
# FIXME/TODO: needed?
# avoid dupe errors
cli.parser.set_conflict_handler('resolve')
cli.set_action()
action_info = {'option_names': [],
'options': []}
# docs['actions'][action] = {}
# docs['actions'][action]['name'] = action
action_info['name'] = action
action_info['desc'] = trim_docstring(getattr(cli, 'execute_%s' % action).__doc__)
# docs['actions'][action]['desc'] = getattr(cli, 'execute_%s' % action).__doc__.strip()
action_doc_list = opt_doc_list(cli)
uncommon_options = []
for action_doc in action_doc_list:
# uncommon_options = []
option_aliases = action_doc.get('options', [])
for option_alias in option_aliases:
if option_alias in shared_opt_names:
continue
# TODO: use set
if option_alias not in action_info['option_names']:
action_info['option_names'].append(option_alias)
if action_doc in action_info['options']:
continue
uncommon_options.append(action_doc)
action_info['options'] = uncommon_options
docs['actions'][action] = action_info
docs['options'] = opt_doc_list(cli)
return docs
if __name__ == '__main__':
parser = generate_parser()
options, args = parser.parse_args()
template_file = options.template_file
template_path = os.path.expanduser(template_file)
template_dir = os.path.abspath(os.path.dirname(template_path))
template_basename = os.path.basename(template_file)
output_dir = os.path.abspath(options.output_dir)
output_format = options.output_format
cli_modules = args
# various cli parsing things checks sys.argv if the 'args' that are passed in are []
# so just remove any args so the cli modules dont try to parse them resulting in warnings
sys.argv = [sys.argv[0]]
# need to be in right dir
os.chdir(os.path.dirname(__file__))
allvars = {}
output = {}
cli_list = []
cli_bin_name_list = []
# for binary in os.listdir('../../lib/ansible/cli'):
for cli_module_name in cli_modules:
binary = os.path.basename(os.path.expanduser(cli_module_name))
if not binary.endswith('.py'):
continue
elif binary == '__init__.py':
continue
cli_name = os.path.splitext(binary)[0]
if cli_name == 'adhoc':
cli_class_name = 'AdHocCLI'
# myclass = 'AdHocCLI'
output[cli_name] = 'ansible.1.asciidoc.in'
cli_bin_name = 'ansible'
else:
# myclass = "%sCLI" % libname.capitalize()
cli_class_name = "%sCLI" % cli_name.capitalize()
output[cli_name] = 'ansible-%s.1.asciidoc.in' % cli_name
cli_bin_name = 'ansible-%s' % cli_name
# FIXME:
allvars[cli_name] = opts_docs(cli_class_name, cli_name)
cli_bin_name_list.append(cli_bin_name)
cli_list = allvars.keys()
doc_name_formats = {'man': '%s.1.asciidoc.in',
'rst': '%s.rst'}
for cli_name in cli_list:
# template it!
env = Environment(loader=FileSystemLoader(template_dir))
template = env.get_template(template_basename)
# add rest to vars
tvars = allvars[cli_name]
tvars['cli_list'] = cli_list
tvars['cli_bin_name_list'] = cli_bin_name_list
tvars['cli'] = cli_name
if '-i' in tvars['options']:
print('uses inventory')
manpage = template.render(tvars)
filename = os.path.join(output_dir, doc_name_formats[output_format] % tvars['cli_name'])
with open(filename, 'wb') as f:
f.write(to_bytes(manpage))
print("Wrote doc to %s" % filename)

View File

@ -1,629 +0,0 @@
#!/usr/bin/env python
# (c) 2012, Jan-Piet Mens <jpmens () gmail.com>
# (c) 2012-2014, Michael DeHaan <michael@ansible.com> and others
# (c) 2017 Ansible Project
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import datetime
import glob
import optparse
import os
import pprint
import re
import sys
import warnings
from collections import defaultdict
try:
from html import escape as html_escape
except ImportError:
# Python-3.2 or later
import cgi
def html_escape(text, quote=True):
return cgi.escape(text, quote)
import yaml
from jinja2 import Environment, FileSystemLoader
from six import iteritems, string_types
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_bytes
from ansible.utils import plugin_docs
#####################################################################################
# constants and paths
# if a module is added in a version of Ansible older than this, don't print the version added information
# in the module documentation because everyone is assumed to be running something newer than this already.
TO_OLD_TO_BE_NOTABLE = 1.3
# Get parent directory of the directory this script lives in
MODULEDIR = os.path.abspath(os.path.join(
os.path.dirname(os.path.realpath(__file__)), os.pardir, 'lib', 'ansible', 'modules'
))
# The name of the DOCUMENTATION template
EXAMPLE_YAML = os.path.abspath(os.path.join(
os.path.dirname(os.path.realpath(__file__)), os.pardir, 'examples', 'DOCUMENTATION.yml'
))
_ITALIC = re.compile(r"I\(([^)]+)\)")
_BOLD = re.compile(r"B\(([^)]+)\)")
_MODULE = re.compile(r"M\(([^)]+)\)")
_URL = re.compile(r"U\(([^)]+)\)")
_CONST = re.compile(r"C\(([^)]+)\)")
DEPRECATED = b" (D)"
def rst_ify(text):
''' convert symbols like I(this is in italics) to valid restructured text '''
try:
t = _ITALIC.sub(r'*' + r"\1" + r"*", text)
t = _BOLD.sub(r'**' + r"\1" + r"**", t)
t = _MODULE.sub(r':ref:`' + r"\1 <\1>" + r"`", t)
t = _URL.sub(r"\1", t)
t = _CONST.sub(r'``' + r"\1" + r"``", t)
except Exception as e:
raise AnsibleError("Could not process (%s) : %s" % (str(text), str(e)))
return t
def html_ify(text):
''' convert symbols like I(this is in italics) to valid HTML '''
t = html_escape(text)
t = _ITALIC.sub("<em>" + r"\1" + "</em>", t)
t = _BOLD.sub("<b>" + r"\1" + "</b>", t)
t = _MODULE.sub("<span class='module'>" + r"\1" + "</span>", t)
t = _URL.sub("<a href='" + r"\1" + "'>" + r"\1" + "</a>", t)
t = _CONST.sub("<code>" + r"\1" + "</code>", t)
return t
def rst_fmt(text, fmt):
''' helper for Jinja2 to do format strings '''
return fmt % (text)
def rst_xline(width, char="="):
''' return a restructured text line of a given length '''
return char * width
def write_data(text, output_dir, outputname, module=None):
''' dumps module output to a file or the screen, as requested '''
if output_dir is not None:
if module:
outputname = outputname % module
if not os.path.exists(output_dir):
os.makedirs(output_dir)
fname = os.path.join(output_dir, outputname)
fname = fname.replace(".py", "")
with open(fname, 'wb') as f:
f.write(to_bytes(text))
else:
print(text)
def get_module_info(module_dir, limit_to_modules=None, verbose=False):
'''
Returns information about modules and the categories that they belong to
:arg module_dir: file system path to the top of the modules directory
:kwarg limit_to_modules: If given, this is a list of module names to
generate information for. All other modules will be ignored.
:returns: Tuple of two dicts containing module_info, categories, and
aliases and a set listing deprecated modules:
:module_info: mapping of module names to information about them. The fields of the dict are:
:path: filesystem path to the module
:deprecated: boolean. True means the module is deprecated otherwise not.
:aliases: set of aliases to this module name
:metadata: The modules metadata (as recorded in the module)
:doc: The documentation structure for the module
:examples: The module's examples
:returndocs: The module's returndocs
:categories: maps category names to a dict. The dict contains at
least one key, '_modules' which contains a list of module names in
that category. Any other keys in the dict are subcategories with
the same structure.
'''
categories = dict()
module_info = defaultdict(dict)
# * windows powershell modules have documentation stubs in python docstring
# format (they are not executed) so skip the ps1 format files
# * One glob level for every module level that we're going to traverse
files = (
glob.glob("%s/*.py" % module_dir) +
glob.glob("%s/*/*.py" % module_dir) +
glob.glob("%s/*/*/*.py" % module_dir) +
glob.glob("%s/*/*/*/*.py" % module_dir)
)
for module_path in files:
# Do not list __init__.py files
if module_path.endswith('__init__.py'):
continue
# Do not list blacklisted modules
module = os.path.splitext(os.path.basename(module_path))[0]
if module in plugin_docs.BLACKLIST['MODULE'] or module == 'base':
continue
# If requested, limit module documentation building only to passed-in
# modules.
if limit_to_modules is not None and module.lower() not in limit_to_modules:
continue
deprecated = False
if module.startswith("_"):
if os.path.islink(module_path):
# Handle aliases
source = os.path.splitext(os.path.basename(os.path.realpath(module_path)))[0]
module = module.replace("_", "", 1)
aliases = module_info[source].get('aliases', set())
aliases.add(module)
# In case we just created this via get()'s fallback
module_info[source]['aliases'] = aliases
continue
else:
# Handle deprecations
module = module.replace("_", "", 1)
deprecated = True
#
# Regular module to process
#
category = categories
# Start at the second directory because we don't want the "vendor"
mod_path_only = os.path.dirname(module_path[len(module_dir):])
module_categories = []
# build up the categories that this module belongs to
for new_cat in mod_path_only.split('/')[1:]:
if new_cat not in category:
category[new_cat] = dict()
category[new_cat]['_modules'] = []
module_categories.append(new_cat)
category = category[new_cat]
category['_modules'].append(module)
# the category we will use in links (so list_of_all_plugins can point to plugins/action_plugins/*'
if module_categories:
primary_category = module_categories[0]
# use ansible core library to parse out doc metadata YAML and plaintext examples
doc, examples, returndocs, metadata = plugin_docs.get_docstring(module_path, verbose=verbose)
# save all the information
module_info[module] = {'path': module_path,
'deprecated': deprecated,
'aliases': set(),
'metadata': metadata,
'doc': doc,
'examples': examples,
'returndocs': returndocs,
'categories': module_categories,
'primary_category': primary_category,
}
# keep module tests out of becoming module docs
if 'test' in categories:
del categories['test']
return module_info, categories
def generate_parser():
''' generate an optparse parser '''
p = optparse.OptionParser(
version='%prog 1.0',
usage='usage: %prog [options] arg1 arg2',
description='Generate module documentation from metadata',
)
p.add_option("-A", "--ansible-version", action="store", dest="ansible_version", default="unknown", help="Ansible version number")
p.add_option("-M", "--module-dir", action="store", dest="module_dir", default=MODULEDIR, help="Ansible library path")
p.add_option("-P", "--plugin-type", action="store", dest="plugin_type", default='modules', help="The type of plugin (plugins, modules)")
p.add_option("-T", "--template-dir", action="store", dest="template_dir", default="hacking/templates", help="directory containing Jinja2 templates")
p.add_option("-t", "--type", action='store', dest='type', choices=['rst'], default='rst', help="Document type")
p.add_option("-v", "--verbose", action='store_true', default=False, help="Verbose")
p.add_option("-o", "--output-dir", action="store", dest="output_dir", default=None, help="Output directory for module files")
p.add_option("-I", "--includes-file", action="store", dest="includes_file", default=None, help="Create a file containing list of processed modules")
p.add_option("-l", "--limit-to-modules", action="store", dest="limit_to_modules", default=None,
help="Limit building module documentation to comma-separated list of modules. Specify non-existing module name for no modules.")
p.add_option('-V', action='version', help='Show version number and exit')
return p
def jinja2_environment(template_dir, typ, plugin_type):
env = Environment(loader=FileSystemLoader(template_dir),
variable_start_string="@{",
variable_end_string="}@",
trim_blocks=True)
env.globals['xline'] = rst_xline
templates = {}
if typ == 'rst':
env.filters['convert_symbols_to_format'] = rst_ify
env.filters['html_ify'] = html_ify
env.filters['fmt'] = rst_fmt
env.filters['xline'] = rst_xline
templates['plugin'] = env.get_template('plugin.rst.j2')
templates['category_list'] = env.get_template('%s_by_category.rst.j2' % plugin_type)
templates['support_list'] = env.get_template('%s_by_support.rst.j2' % plugin_type)
templates['list_of_CATEGORY_modules'] = env.get_template('list_of_CATEGORY_%s.rst.j2' % plugin_type)
else:
raise Exception("unknown module format type: %s" % typ)
return templates
def too_old(added):
if not added:
return False
try:
added_tokens = str(added).split(".")
readded = added_tokens[0] + "." + added_tokens[1]
added_float = float(readded)
except ValueError as e:
warnings.warn("Could not parse %s: %s" % (added, str(e)))
return False
return added_float < TO_OLD_TO_BE_NOTABLE
def process_modules(module_map, templates, outputname, output_dir, ansible_version, plugin_type):
for module in module_map:
# print("rendering: %s" % module)
# pprint.pprint(('process_modules module:', module))
fname = module_map[module]['path']
# pprint.pprint(('process_modules module_info: ', module_map[module]))
module_categories = module_map[module].get('categories', [])
# crash if module is missing documentation and not explicitly hidden from docs index
if module_map[module]['doc'] is None:
print("%s: ERROR: MODULE MISSING DOCUMENTATION" % (fname,))
_doc = {'module': module,
'version_added': '2.4',
'filename': fname}
module_map[module]['doc'] = _doc
# continue
# Going to reference this heavily so make a short name to reference it by
doc = module_map[module]['doc']
# pprint.pprint(('process_modules doc: ', doc))
# add some defaults for plugins that dont have most of the info
doc['module'] = doc.get('module', module)
doc['version_added'] = doc.get('version_added', 'historical')
doc['plugin_type'] = plugin_type
if module_map[module]['deprecated'] and 'deprecated' not in doc:
print("%s: WARNING: MODULE MISSING DEPRECATION DOCUMENTATION: %s" % (fname, 'deprecated'))
required_fields = ('short_description',)
for field in required_fields:
if field not in doc:
print("%s: WARNING: MODULE MISSING field '%s'" % (fname, field))
not_nullable_fields = ('short_description',)
for field in not_nullable_fields:
if field in doc and doc[field] in (None, ''):
print("%s: WARNING: MODULE field '%s' DOCUMENTATION is null/empty value=%s" % (fname, field, doc[field]))
if 'version_added' not in doc:
pprint.pprint(doc)
# sys.exit("*** ERROR: missing version_added in: %s ***\n" % module)
#
# The present template gets everything from doc so we spend most of this
# function moving data into doc for the template to reference
#
if module_map[module]['aliases']:
doc['aliases'] = module_map[module]['aliases']
# don't show version added information if it's too old to be called out
added = 0
if doc['version_added'] == 'historical':
del doc['version_added']
else:
added = doc['version_added']
# Strip old version_added for the module
if too_old(added):
del doc['version_added']
option_names = []
if 'options' in doc and doc['options']:
for (k, v) in iteritems(doc['options']):
# Error out if there's no description
if 'description' not in doc['options'][k]:
raise AnsibleError("Missing required description for option %s in %s " % (k, module))
# Error out if required isn't a boolean (people have been putting
# information on when something is required in here. Those need
# to go in the description instead).
required_value = doc['options'][k].get('required', False)
if not isinstance(required_value, bool):
raise AnsibleError("Invalid required value '%s' for option '%s' in '%s' (must be truthy)" % (required_value, k, module))
# Strip old version_added information for options
if 'version_added' in doc['options'][k] and too_old(doc['options'][k]['version_added']):
del doc['options'][k]['version_added']
# Make sure description is a list of lines for later formatting
if not isinstance(doc['options'][k]['description'], list):
doc['options'][k]['description'] = [doc['options'][k]['description']]
option_names.append(k)
option_names.sort()
doc['option_keys'] = option_names
doc['filename'] = fname
doc['docuri'] = doc['module'].replace('_', '-')
doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d')
doc['ansible_version'] = ansible_version
# check the 'deprecated' field in doc. We expect a dict potentially with 'why', 'version', and 'alternative' fields
# examples = module_map[module]['examples']
# print('\n\n%s: type of examples: %s\n' % (module, type(examples)))
# if examples and not isinstance(examples, (str, unicode, list)):
# raise TypeError('module %s examples is wrong type (%s): %s' % (module, type(examples), examples))
# use 'examples' for 'plainexamples' if 'examples' is a string
if isinstance(module_map[module]['examples'], string_types):
doc['plainexamples'] = module_map[module]['examples'] # plain text
else:
doc['plainexamples'] = ''
doc['metadata'] = module_map[module]['metadata']
# pprint.pprint(module_map[module]
if module_map[module]['returndocs']:
try:
doc['returndocs'] = yaml.safe_load(module_map[module]['returndocs'])
except Exception as e:
print("%s:%s:yaml error:%s:returndocs=%s" % (fname, module, e, module_map[module]['returndocs']))
doc['returndocs'] = None
else:
doc['returndocs'] = None
doc['author'] = doc.get('author', ['UNKNOWN'])
if isinstance(doc['author'], string_types):
doc['author'] = [doc['author']]
# print('about to template')
# pprint.pprint(doc)
text = templates['plugin'].render(doc)
# plugins get namespace dirs but modules do not
if plugin_type == 'plugins':
for module_category in module_categories:
category_output_dir = os.path.join(output_dir, 'plugins', '%s' % module_category)
write_data(text, category_output_dir, outputname, module)
else:
write_data(text, output_dir, outputname, module)
def process_categories(mod_info, categories, templates,
output_dir, output_name, plugin_type):
for category in sorted(categories.keys()):
if (plugin_type, category) == ('plugins', ''):
print('skipping unknown cat: %s' % category)
continue
module_map = categories[category]
category_filename = output_name % category
print("*** recording category %s in %s ***" % (category, category_filename))
# start a new category file
category_name = category.replace("_", " ")
category_title = category_name.title()
subcategories = dict((k, v) for k, v in module_map.items() if k != '_modules')
template_data = {'title': category_title,
'category_name': category_name,
'category': module_map,
'subcategories': subcategories,
'module_info': mod_info,
'plugin_type': plugin_type
}
text = templates['list_of_CATEGORY_modules'].render(template_data)
write_data(text, output_dir, category_filename)
def process_support_levels(mod_info, templates, output_dir, plugin_type):
supported_by = {'Ansible Core Team': {'slug': 'core_supported',
'modules': [],
'output': 'core_maintained.rst',
'blurb': "These are :doc:`modules maintained by the"
" Ansible Core Team<core_maintained>` and will always ship"
" with Ansible itself."},
'Ansible Network Team': {'slug': 'network_supported',
'modules': [],
'output': 'network_maintained.rst',
'blurb': "These are :doc:`modules maintained by the"
" Ansible Network Team<network_maintained>` in"
" a relationship similar to how the Ansible Core Team"
" maintains the Core modules."},
'Ansible Partners': {'slug': 'partner_supported',
'modules': [],
'output': 'partner_maintained.rst',
'blurb': """
Some examples of :doc:`Certified Modules<partner_maintained>` are those submitted by other
companies. Maintainers of these types of modules must watch for any issues reported or pull requests
raised against the module.
The Ansible Core Team will review all modules becoming certified. Core committers will review
proposed changes to existing Certified Modules once the community maintainers of the module have
approved the changes. Core committers will also ensure that any issues that arise due to Ansible
engine changes will be remediated. Also, it is strongly recommended (but not presently required)
for these types of modules to have unit tests.
These modules are currently shipped with Ansible, but might be shipped separately in the future.
"""},
'Ansible Community': {'slug': 'community_supported',
'modules': [],
'output': 'community_maintained.rst',
'blurb': """
These are :doc:`modules maintained by the Ansible Community<community_maintained>`. They **are
not** supported by the Ansible Core Team or by companies/partners associated to the module.
They are still fully usable, but the response rate to issues is purely up to the community. Best
effort support will be provided but is not covered under any support contracts.
These modules are currently shipped with Ansible, but will most likely be shipped separately in the future.
"""},
}
# only gen support pages for modules for now, need to split and namespace templates and generated docs
if plugin_type == 'plugins':
return
# Separate the modules by support_level
for module, info in mod_info.items():
if not info.get('metadata', None):
print('no metadata for %s' % module)
continue
if info['metadata']['supported_by'] == 'core':
supported_by['Ansible Core Team']['modules'].append(module)
elif info['metadata']['supported_by'] == 'network':
supported_by['Ansible Network Team']['modules'].append(module)
elif info['metadata']['supported_by'] == 'certified':
supported_by['Ansible Partners']['modules'].append(module)
elif info['metadata']['supported_by'] == 'community':
supported_by['Ansible Community']['modules'].append(module)
else:
raise AnsibleError('Unknown supported_by value: %s' % info['metadata']['supported_by'])
# Render the module lists
for maintainers, data in supported_by.items():
template_data = {'maintainers': maintainers,
'modules': data['modules'],
'slug': data['slug'],
'module_info': mod_info,
}
text = templates['support_list'].render(template_data)
write_data(text, output_dir, data['output'])
def validate_options(options):
''' validate option parser options '''
if not options.module_dir:
sys.exit("--module-dir is required", file=sys.stderr)
if not os.path.exists(options.module_dir):
sys.exit("--module-dir does not exist: %s" % options.module_dir, file=sys.stderr)
if not options.template_dir:
sys.exit("--template-dir must be specified")
def main():
p = generate_parser()
(options, args) = p.parse_args()
validate_options(options)
plugin_type = options.plugin_type
if plugin_type == 'modules':
templates = jinja2_environment(options.template_dir, options.type, plugin_type)
output_dir = options.output_dir
# trim trailing s off of plugin_type for plugin_type=='modules'. ie 'copy_module.rst'
outputname = '%s_' + '%s.rst' % plugin_type[:-1]
else:
templates = jinja2_environment(options.template_dir, options.type, 'plugins')
# for plugins, just use 'ssh.rst' vs 'ssh_module.rst'
outputname = '%s.rst'
output_dir = '%s/plugins/%s' % (options.output_dir, plugin_type)
# Convert passed-in limit_to_modules to None or list of modules.
if options.limit_to_modules is not None:
options.limit_to_modules = [s.lower() for s in options.limit_to_modules.split(",")]
mod_info, categories = get_module_info(options.module_dir, limit_to_modules=options.limit_to_modules, verbose=options.verbose)
categories['all'] = {'_modules': mod_info.keys()}
# pprint.pprint(categories)
# pprint.pprint(mod_info)
# pprint.pprint(dict(mod_info))
# Transform the data
if options.type == 'rst':
for key, record in mod_info.items():
# pprint.pprint(('record', record))
if record.get('doc', None):
short_desc = record['doc']['short_description']
if short_desc is None:
print('WARNING: short_description for %s is None' % key)
short_desc = ''
record['doc']['short_description'] = rst_ify(short_desc)
if plugin_type == 'modules':
# Write master category list
category_list_text = templates['category_list'].render(categories=sorted(categories.keys()))
category_index_name = '%s_by_category.rst' % plugin_type
write_data(category_list_text, output_dir, category_index_name)
# Render all the individual module pages
process_modules(mod_info, templates, outputname, output_dir, options.ansible_version, plugin_type)
# Render all the categories for modules
if plugin_type == 'modules':
category_list_name_template = 'list_of_%s_' + '%s.rst' % plugin_type
process_categories(mod_info, categories, templates, output_dir, category_list_name_template, plugin_type)
# Render all the categories for modules
process_support_levels(mod_info, templates, output_dir, plugin_type)
if __name__ == '__main__':
main()

View File

@ -1,12 +0,0 @@
#!/bin/bash -eu
cat <<- EOF > ../docsite/rst/dev_guide/testing/sanity/index.rst
Sanity Tests
============
The following sanity tests are available as \`\`--test\`\` options for \`\`ansible-test sanity\`\`:
$(for test in $(../../test/runner/ansible-test sanity --list-tests); do echo "- :doc:\`${test} <${test}>\`"; done)
This list is also available using \`\`ansible-test sanity --list-tests\`\`.
EOF

View File

@ -11,7 +11,5 @@ ansible*.xml
.buildinfo
objects.inv
.doctrees
rst/dev_guide/testing/sanity/index.rst
rst/modules/*.rst
rst/playbooks_keywords.rst
*.min.css

View File

@ -1,45 +1,20 @@
OS := $(shell uname -s)
SITELIB = $(shell python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"):
FORMATTER=../bin/plugin_formatter.py
TESTING_FORMATTER=../bin/testing_formatter.sh
DUMPER=../bin/dump_keywords.py
CONFIG_DUMPER=../bin/dump_config.py
GENERATE_CLI=../bin/generate_man.py
FORMATTER=../../hacking/module_formatter.py
DUMPER=../../hacking/dump_playbook_attributes.py
ifeq ($(shell echo $(OS) | egrep -ic 'Darwin|FreeBSD|OpenBSD|DragonFly'),1)
CPUS ?= $(shell sysctl hw.ncpu|awk '{print $$2}')
else
CPUS ?= $(shell nproc)
endif
MODULE_ARGS=
ifdef MODULES
MODULE_ARGS = -l $(MODULES)
endif
PLUGIN_ARGS=
ifdef PLUGINS
PLUGIN_ARGS = -l $(PLUGINS)
endif
DOC_PLUGINS ?= cache callback connection inventory lookup strategy vars
assertrst:
ifndef rst
$(error specify document or pattern with rst=somefile.rst)
endif
all: docs
docs: clean htmldocs
generate_rst: testing keywords modules plugins staticmin cli config
htmldocs: generate_rst
htmldocs: directives modules staticmin
CPUS=$(CPUS) $(MAKE) -f Makefile.sphinx html
singlehtmldocs: generate_rst
CPUS=$(CPUS) $(MAKE) -f Makefile.sphinx singlehtml
webdocs: docs
#TODO: leaving htmlout removal for those having older versions, should eventually be removed also
@ -47,7 +22,7 @@ clean:
-rm -rf htmlout
-rm -rf _build
-rm -f .buildinfo
-rm -f objects.inv
-rm -f *.inv
-rm -rf *.doctrees
@echo "Cleaning up minified css files"
find . -type f -name "*.min.css" -delete
@ -60,46 +35,15 @@ clean:
-rm rst/list_of_*.rst
-rm rst/*_by_category.rst
-rm rst/*_module.rst
-rm rst/*_plugin.rst
-rm rst/*_maintained.rst
-rm rst/playbooks_directives.rst
-rm rst/playbooks_keywords.rst
-rm rst/plugins/*/*.rst
-rm rst/config.rst
-rm rst/ansible-*.rst
-rm rst/ansible.rst
.PHONEY: docs clean
# TODO: make generate_man output dir cli option
cli: $(GENERATE_CLI)
PYTHONPATH=../../lib $(GENERATE_CLI) --template-file=../templates/cli_rst.j2 --output-dir=rst/ --output-format rst ../../lib/ansible/cli/*.py
directives: $(FORMATTER) ../../hacking/templates/rst.j2
PYTHONPATH=../../lib $(DUMPER) --template-dir=../../hacking/templates --output-dir=rst/
keywords: $(FORMATTER) ../templates/playbooks_keywords.rst.j2
PYTHONPATH=../../lib $(DUMPER) --template-dir=../templates --output-dir=rst/ -d ./keyword_desc.yml
config:
PYTHONPATH=../../lib $(CONFIG_DUMPER) --template-file=../templates/config.rst.j2 --output-dir=rst/ -d ../../lib/ansible/config/base.yml
modules: $(FORMATTER) ../templates/plugin.rst.j2
PYTHONPATH=../../lib $(FORMATTER) -t rst --template-dir=../templates --module-dir=../../lib/ansible/modules -o rst/ $(MODULE_ARGS)
plugins: $(FORMATTER) ../templates/plugin.rst.j2
@echo "looping over doc plugins"
for plugin in $(DOC_PLUGINS); \
do \
PYTHONPATH=../../lib $(FORMATTER) -t rst --plugin-type $$plugin --template-dir=../templates --module-dir=../../lib/ansible/plugins/$$plugin -o rst/ $(PLUGIN_ARGS); \
done
testing:
$(TESTING_FORMATTER)
modules: $(FORMATTER) ../../hacking/templates/rst.j2
PYTHONPATH=../../lib $(FORMATTER) -t rst --template-dir=../../hacking/templates --module-dir=../../lib/ansible/modules -o rst/
staticmin:
cat _themes/srtd/static/css/theme.css | sed -e 's/^[ ]*//g; s/[ ]*$$//g; s/\([:{;,]\) /\1/g; s/ {/{/g; s/\/\*.*\*\///g; /^$$/d' | sed -e :a -e '$$!N; s/\n\(.\)/\1/; ta' > _themes/srtd/static/css/theme.min.css
epub:
(CPUS=$(CPUS) make -f Makefile.sphinx epub)
htmlsingle: assertrst
sphinx-build -j $(CPUS) -b html -d _build/doctrees ./rst _build/html rst/$(rst)
@echo "Output is in _build/html/$(rst:.rst=.html)"

View File

@ -2,7 +2,7 @@
#
# You can set these variables from the command line.
SPHINXOPTS = -j $(CPUS) -n -w rst_warnings
SPHINXOPTS = -j $(CPUS)
SPHINXBUILD = sphinx-build
SPHINXPROJ = sdfsdf
SOURCEDIR = rst
@ -17,4 +17,4 @@ help:
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile.sphinx
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -14,12 +14,6 @@ such as link references, you may install sphinx and build the documentation by r
To include module documentation you'll need to run `make webdocs` at the top level of the repository. The generated
html files are in docsite/htmlout/.
To limit module documentation building to a specific module, run `MODULES=NAME
make webdocs` instead. This should make testing module documentation syntax much
faster. Instead of a single module, you can also specify a comma-separated list
of modules. In order to skip building documentation for all modules, specify
non-existing module name, for example `MODULES=none make webdocs`.
If you do not want to learn the reStructuredText format, you can also [file issues] about
documentation problems on the Ansible GitHub project.

View File

@ -0,0 +1,4 @@
{# Creates a banner at the top of the page for EOL versions. #}
<div id='banner' class='Admonition caution'>
<p>You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See <a href="https://docs.ansible.com/ansible/latest/index.html">the latest Ansible documentation</a>.</p>
</div>

View File

@ -1,11 +1,5 @@
<ul class="wy-breadcrumbs">
<li><a href="{{ pathto(master_doc) }}">Docs</a> &raquo;</li>
<li><a href="">{{ title }}</a></li>
{% if not pagename.endswith('_module') and (not 'list_of' in pagename) and (not 'category' in pagename) %}
<li class="wy-breadcrumbs-aside">
<a href="https://github.com/ansible/ansible/blob/devel/docs/docsite/rst/{{ pagename }}.rst" class="icon icon-github"> Edit on GitHub</a>
</li>
{% endif %}
</ul>
<hr/>

View File

@ -34,6 +34,9 @@
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
{% endif %}
<link rel="canonical" href="https://docs.ansible.com/ansible/latest/{{ pagename }}.html"/>
{# CSS #}
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css' rel='stylesheet' type='text/css'>
@ -140,7 +143,7 @@
</ul>
</div>
<a class="DocSite-nav" href="/">
<a class="DocSite-nav" href="http://docs.ansible.com/">
<img class="DocSiteNav-logo"
src="{{ pathto('_static/', 1) }}images/logo_invert.png"
alt="Ansible Logo">
@ -151,23 +154,23 @@
<div class="wy-grid-for-nav">
{# SIDE NAV, TOGGLES ON MOBILE #}
{# SIDE NAV TOGGLES ON MOBILE #}
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div style="background-color:#5bbdbf;height=80px;margin:'auto auto auto auto'">
<a class="DocSiteProduct-header DocSiteProduct-header--core" href="/">
<a class="DocSiteProduct-header DocSiteProduct-header--core" href="http://docs.ansible.com">
<div class="DocSiteProduct-productName">
<div class="DocSiteProduct-logoText">
Ansible
Ansible Core
<div class="DocSiteProduct-CurrentVersion" align="right">
devel
v2.3
</div>
</div>
</div>
</a>
<div class="DocSiteProduct-CheckVersionPara">For previous versions, see the <a class="DocSiteProduct-versionheader" href="/#coreversionselect">documentation archive.</a></div>
<div class="DocSiteProduct-CheckVersionPara">For previous versions, see the <a class="DocSiteProduct-versionheader" href="http://docs.ansible.com/">documentation archive.</a></div>
</div>
<div id="menu-id" class="wy-menu wy-menu-vertical" data-spy="affix">
@ -228,6 +231,7 @@
</div> -->
{% include "breadcrumbs.html" %}
{% include "ansible_eol_banner.html" %}
<div id="page-content">
{% block body %}{% endblock %}
</div>

View File

@ -4721,6 +4721,7 @@ span[id*='MathJax-Span'] {
margin-right: 10px;
}
.wy-menu-vertical a {
padding: 0;
}

226
docs/docsite/conf.py Normal file
View File

@ -0,0 +1,226 @@
# -*- coding: utf-8 -*-
#
# documentation build configuration file, created by
# sphinx-quickstart on Sat Sep 27 13:23:22 2008-2009.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed
# automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
import sys
import os
# pip install sphinx_rtd_theme
#import sphinx_rtd_theme
#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('some/directory'))
#
sys.path.insert(0, os.path.join('ansible', 'lib'))
sys.path.append(os.path.abspath('_themes'))
VERSION='2.2'
AUTHOR='Ansible, Inc'
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings.
# They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Later on, add 'sphinx.ext.viewcode' to the list if you want to have
# colorized code generated too for references.
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General substitutions.
project = 'Ansible Documentation'
copyright = "2013-2017 Ansible, Inc"
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = VERSION
# The full version, including alpha/beta/rc tags.
release = VERSION
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be
# searched for source files.
#exclude_dirs = []
# A list of glob-style patterns that should be excluded when looking
# for source files.
exclude_patterns = ['modules']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
highlight_language = 'YAML+Jinja'
#Substitutions, variables, entities, & shortcuts for text which do not need to link to anything.
#For titles which should be a link, use the intersphinx anchors set at the index, chapter, and section levels, such as qi_start_:
rst_epilog = """
.. |acapi| replace:: *Ansible Core API Guide*
.. |acrn| replace:: *Ansible Core Release Notes*
.. |ac| replace:: Ansible Core
.. |acversion| replace:: Ansible Core Version 2.1
.. |acversionshort| replace:: Ansible Core 2.1
.. |versionshortest| replace:: 2.2
.. |versiondev| replace:: 2.3
.. |pubdate| replace:: July 19, 2016
.. |rhel| replace:: Red Hat Enterprise Linux
"""
# Options for HTML output
# -----------------------
html_theme_path = ['_themes']
html_theme = 'srtd'
html_short_title = 'Ansible Documentation'
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
#html_style = 'solar.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'Ansible Documentation'
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
html_copy_source = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Poseidodoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class
# [howto/manual]).
latex_documents = [
('index', 'ansible.tex', 'Ansible 2.2 Documentation', AUTHOR, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
autoclass_content = 'both'

Binary file not shown.

View File

@ -1,57 +0,0 @@
accelerate: DEPRECATED, set to True to use accelerate connection plugin.
accelerate_ipv6: "DEPRECATED, set to True to force accelerate plugin to use ipv6 for it's connection."
accelerate_port: DEPRECATED, set to override default port use for accelerate connection.
action: "The 'action' to execute for a task, it normally translates into a C(module) or action plugin."
args: DEPRECATED, A secondary way to add arguments into a task, it takes a dictionary in which keys map to options and values .. well you get it.
always: List of tasks, in a block, that execute no matter if there is an error in the block or not.
always_run: DEPRECATED, forces a task to run even in check mode, use :term:`check_mode` directive instead.
any_errors_fatal: Force any un-handled task errors on any host to propagate to all hosts and end the play.
async: Run a task asyncronouslly if the C(action) supports this.
become: Boolean that controls if privilege escalation is used or not on :term:`Task` execution.
become_flags: A string of flag(s) to pass to the privilege escalation program when :term:`become` is True.
become_method: Which method of privilege escalation to use. i.e. sudo/su/etc.
become_user: "User that you 'become' after using privilege escalation, the remote/login user must have permissions to become this user."
block: List of tasks in a block.
changed_when: "Conditional expression that overrides the task's normal 'changed' status."
check_mode: "A boolean that controls if a task is executed in 'check' mode"
connection: Allows you to change the connection plugin used for tasks to execute on the target.
delay: Number of seconds to delay between retries, this setting is only used in combination with :term:`until`.
delegate_facts: Boolean that allows you to apply facts to delegated host instead of inventory_hostname.
delegate_to: Host to execute task instead of the target (inventory_hostname), connection vars from the delegated host will also be used for the task.
diff: "Toggle to make tasks return 'diff' information or not."
environment: A dictionary that gets converted into environment vars to be provided for the task upon execution.
fact_path: Set the fact path option for the fact gathering plugin controlled by :term:`gather_facts`.
failed_when: "Conditional expression that overrides the task's normal 'failed' status."
force_handlers: Will force notified handler execution for hosts even if they failed during the play, it will not trigger if the play itself fails.
gather_facts: "A boolean that controls if the play will automatically run the 'setup' task to gather facts for the hosts."
gather_subset: Allows you to pass subset options to the fact gathering plugin controlled by :term:`gather_facts`.
gather_timeout: Allows you to set the timeout for the fact gathering plugin controlled by :term:`gather_facts`.
handlers: "A section with tasks that are treated as handlers, these won't get executed normally, only when notified. After each section of tasks is complete."
hosts: "A list of groups, hosts or host pattern that translates into a list of hosts that are the play's target."
ignore_errors: Boolean that allows you to ignore task failures and continue with play. It does not affect connection errors.
loop_control: "Several keys here allow you to modify/set loop behaviour in a task see http://docs.ansible.com/ansible/latest/playbooks_loops.html#loop-control for details."
max_fail_percentage: can be used to abort the run after a given percentage of hosts in the current batch has failed.
name: "It's a name, works mostly for documentation, in the case of tasks/handlers it can be an identifier."
no_log: Boolean that controls information disclosure.
notify: "list of handlers to notify when the task returns a 'changed=True' status."
order: Controls the sorting of hosts as they are used for executing the play. Possible values are inventory (default), sorted, reverse_sorted, reverse_inventory and shuffle.
poll: Sets the polling interval in seconds for async tasks (default 10s).
port: Used to override the default port used in a connection.
post_tasks: A list of tasks to execute after the :term:`tasks` section.
pre_tasks: A list of tasks to execute before :term:`roles`.
remote_user: User used to log into the target via the connection plugin. AKA login user.
register: Name of variable that will contain task status and module return data.
rescue: List of tasks in a :term:`block` that run if there is a task error in the main :term:`block` list.
retries: "Number of retries before giving up in a :term:`until` loop. This setting is only used in combination with :term:`until`."
roles: List of roles to be imported into the play
run_once: Boolean that will bypass the host loop, forcing the task to execute on the first host available and will also apply any facts to all active hosts.
serial: Defines the 'batch' of hosts to execute the current play until the end.
strategy: Allows you to choose the connection plugin to use for the play.
tags: Tags applied to the task or included tasks, this allows selecting subsets of tasks from the command line.
tasks: Main list of tasks to execute in the play, they run after :term:`roles` and before :term:`post_tasks`.
until: "This keyword implies a ':term:`retries` loop' that will go on until the condition supplied here is met or we hit the :term:`retries` limit."
vars: Dictionary/map of variables
vars_files: List of files that contain vars to include in the play.
vars_prompt: list of variables to prompt for.
vault_password: Secret used to decrypt vaulted files or variables.
when: Conditional expression, determines if an iteration of a task is run or not.

Binary file not shown.

Binary file not shown.

View File

@ -1,11 +0,0 @@
Command Line Tools
==================
Most users are familiar with `ansible` and `ansible-playbook`, but those are not the only utilities Ansible provides.
Below you is a complete list of Ansible utilities. Each page contains a description of the utility and a listing of supported parameters.
.. toctree:: :maxdepth: 1
:glob:
ansible
ansible-*

View File

@ -3,7 +3,7 @@ Committers Guidelines (for people with commit rights to Ansible on GitHub)
These are the guidelines for people with commit access to Ansible. Committers are essentially acting as members of the Ansible Core team, although not necessarily as an employee of Ansible and Red Hat. Please read the guidelines before you commit.
These guidelines apply to everyone. At the same time, this ISN'T a process document. So just use good judgement. You've been given commit access because we trust your judgement.
These guidelines apply to everyone. At the same time, this ISN’T a process document. So just use good judgement. You’ve been given commit access because we trust your judgement.
That said, use the trust wisely.
@ -12,25 +12,25 @@ If you abuse the trust and break components and builds, etc., the trust level fa
Features, High Level Design, and Roadmap
========================================
As a core team member, you are an integral part of the team that develops the roadmap. Please be engaged, and push for the features and fixes that you want to see. Also keep in mind that Red Hat, as a company, will commit to certain features, fixes, APIs, etc. for various releases. Red Hat, the company, and the Ansible team must get these committed features (etc.) completed and released as scheduled. Obligations to users, the community, and customers must come first. Because of these commitments, a feature you want to develop yourself may not get into a release if it impacts a lot of other parts within Ansible.
As a core team member, you are an integral part of the team that develops the roadmap. Please be engaged, and push for the features and fixes that you want to see. Also keep in mind that Red Hat, as a company, will commit to certain features, fixes, APIs, etc. for various releases. Red Hat, the company, and the Ansible team must get these committed features (etc.) completed and released as scheduled. Obligations to users, the community, and customers must come first. Because of these commitments, a feature you want to develop yourself many not get into a release if it impacts a lot of other parts within Ansible.
Any other new features and changes to high level design should go through the proposal process (TBD), to ensure the community and core team have had a chance to review the idea and approve it. The core team has sole responsibility for merging new features based on proposals.
Our Workflow on GitHub
======================
As a committer, you may already know this, but our workflow forms a lot of our team policies. Please ensure you're aware of the following workflow steps:
As a committer, you may already know this, but our workflow forms a lot of our team policies. Please ensure you’re aware of the following workflow steps:
* Fork the repository upon which you want to do some work to your own personal repository
* Work on the specific branch upon which you need to commit
* Create a Pull Request back to the Ansible repository and tag the people you would like to review; assign someone as the primary "owner" of your request
* Create a Pull Request back to the Ansible repository and tag the people you would like to review; assign someone as the primary “owner” of your request
* Adjust code as necessary based on the Comments provided
* Ask someone on the Core Team to do a final review and merge
Addendum to workflow for Committers:
------------------------------------
The Core Team is aware that this can be a difficult process at times. Sometimes, the team breaks the rules: Direct commits, merging their own PRs. This section is a set of guidelines. If you're changing a comma in a doc, or making a very minor change, you can use your best judgement. This is another trust thing. The process is critical for any major change, but for little things or getting something done quickly, use your best judgement and make sure people on the team are aware of your work.
The Core Team is aware that this can be a difficult process at times. Sometimes, the team breaks the rules: Direct commits, merging their own PRs. This section is a set of guidelines. If you’re changing a comma in a doc, or making a very minor change, you can use your best judgement. This is another trust thing. The process is critical for any major change, but for little things or getting something done quickly, use your best judgement and make sure people on the team are aware of your work.
Roles on Core
=============
@ -39,14 +39,14 @@ Roles on Core
General Rules
=============
Individuals with direct commit access to ansible/ansible are entrusted with powers that allow them to do a broad variety of things--probably more than we can write down. Rather than rules, treat these as general *guidelines*, individuals with this power are expected to use their best judgement.
Individuals with direct commit access to ansible/ansible (+core, + extras) are entrusted with powers that allow them to do a broad variety of things--probably more than we can write down. Rather than rules, treat these as general *guidelines*, individuals with this power are expected to use their best judgement.
* Don't
* Don’t
- Commit directly.
- Merge your own PRs. Someone else should have a chance to review and approve the PR merge. If you are a Core Committer, you have a small amount of leeway here for very minor changes.
- Forget about alternate environments. Consider the alternatives--yes, people have bad environments, but they are the ones who need us the most.
- Drag your community team members down. Always discuss the technical merits, but you should never address the person's limitations (you can later go for beers and call them idiots, but not in IRC/Github/etc.).
- Drag your community team members down. Always discuss the technical merits, but you should never address the person’s limitations (you can later go for beers and call them idiots, but not in IRC/Github/etc.).
- Forget about the maintenance burden. Some things are really cool to have, but they might not be worth shoehorning in if the maintenance burden is too great.
- Break playbooks. Always keep backwards compatibility in mind.
- Forget to keep it simple. Complexity breeds all kinds of problems.
@ -55,7 +55,7 @@ Individuals with direct commit access to ansible/ansible are entrusted with powe
- Squash, avoid merges whenever possible, use github's squash commits or cherry pick if needed (bisect thanks you).
- Be active. Committers who have no activity on the project (through merges, triage, commits, etc.) will have their permissions suspended.
- Consider backwards compatibility (goes back to "don't break existing playbooks").
- Consider backwards compatibility (goes back to "don’t break existing playbooks").
- Write tests. PRs with tests are looked at with more priority than PRs without tests that should have them included. While not all changes require tests, be sure to add them for bug fixes or functionality changes.
- Discuss with other committers, specially when you are unsure of something.
- Document! If your PR is a new feature or a change to behavior, make sure you've updated all associated documentation or have notified the right people to do so. It also helps to add the version of Core against which this documentation is compatible (to avoid confusion with stable versus devel docs, for backwards compatibility, etc.).
@ -114,13 +114,11 @@ Individuals who've been asked to become a part of this group have generally been
+---------------------+----------------------+--------------------+----------------------+
| Trond Hindenes | trondhindenes | | |
+---------------------+----------------------+--------------------+----------------------+
| Jon Hawkesworth | jhawkesworth | jhawkesworth | |
| Jon Hawkesworth | jhawkseworth | jhawkseworth | |
+---------------------+----------------------+--------------------+----------------------+
| Will Thames | willthames | willthames | |
| Will Thames | wilthames | willthames | |
+---------------------+----------------------+--------------------+----------------------+
| Ryan Brown | ryansb | ryansb | |
+---------------------+----------------------+--------------------+----------------------+
| Adrian Likins | alikins | alikins | |
+---------------------+----------------------+--------------------+----------------------+
| Dag Wieers | dagwieers | dagwieers | dag@wieers.com |
+---------------------+----------------------+--------------------+----------------------+

View File

@ -3,10 +3,10 @@ Return Values
.. contents:: Topics
Ansible modules normally return a data structure that can be registered into a variable, or seen directly when output by
Ansible modules normally return a data structure that can be registered into a variable, or seen directly when output by
the `ansible` program. Each module can optionally document its own unique return values (visible through ansible-doc and https://docs.ansible.com).
This document covers return values common to all modules.
This document covers return values common to all modules.
.. note:: Some of these keys might be set by Ansible itself once it processes the module's return information.
@ -54,7 +54,7 @@ Some modules execute command line utilities or are geared for executing commands
stderr_lines
````````````
When `stderr` is returned we also always provide this field which is a list of strings, one item per line from the original.
When c(stderr) is returned we also always provide this field which is a list of strings, one item per line from the original.
stdout
``````
@ -62,7 +62,7 @@ Some modules execute command line utilities or are geared for executing commands
stdout_lines
````````````
When `stdout` is returned, Ansible always provides a list of strings, each containing one item per line from the original output.
When c(stdout) is returned, Ansible always provides a list of strings, each containing one item per line from the original output.
.. _internal_return_values:

View File

@ -2,7 +2,7 @@ Community Information & Contributing
````````````````````````````````````
Ansible is an open source project designed to bring together administrators and developers of all kinds to collaborate on building
IT automation solutions that work well for them.
IT automation solutions that work well for them.
Should you wish to get more involved -- whether in terms of just asking a question, helping other users, introducing new people to Ansible, or helping with the software or documentation, we welcome your contributions to the project.
@ -16,7 +16,7 @@ I've Got A Question
We're happy to help!
Ansible questions are best asked on the `Ansible Google Group Mailing List <http://groups.google.com/group/ansible-project>`_.
Ansible questions are best asked on the `Ansible Google Group Mailing List <http://groups.google.com/group/ansible-project>`_.
This is a very large high-traffic list for answering questions and sharing tips
and tricks. Anyone can join, and email delivery is optional if you just want to read the group online. To cut down on spam, your first post is moderated, though posts are approved quickly.
@ -42,10 +42,10 @@ This is a low-traffic read-only list, where we'll share release announcements an
I'd Like To Help Share and Promote Ansible
------------------------------------------
You can help share Ansible with others by telling friends and colleagues, writing a blog post,
or presenting at user groups (like DevOps groups or the local LUG).
You can help share Ansible with others by telling friends and colleagues, writing a blog post,
or presenting at user groups (like DevOps groups or the local LUG).
You are also welcome to share slides on speakerdeck, sign up for a free account and tag it "Ansible". On Twitter,
You are also welcome to share slides on speakerdeck, sign up for a free account and tag it “Ansible”. On Twitter,
you can also share things with #ansible and may wish to `follow us <https://twitter.com/ansible>`_.
I'd Like To Help Ansible Move Faster
@ -73,31 +73,31 @@ more quickly.
Do not use the issue tracker for "how do I do this" type questions. These are great candidates
for IRC or the mailing list instead where things are likely to be more of a discussion.
To be respectful of reviewers' time and allow us to help everyone efficiently, please
To be respectful of reviewers' time and allow us to help everyone efficiently, please
provide minimal well-reduced and well-commented examples versus sharing your entire production
playbook. Include playbook snippets and output where possible.
playbook. Include playbook snippets and output where possible.
When sharing YAML in playbooks, formatting can be preserved by using `code blocks <https://help.github.com/articles/creating-and-highlighting-code-blocks/>`_.
For multiple-file content, we encourage use of gist.github.com. Online pastebin content can expire, so it's nice to have things around for a longer term if they
are referenced in a ticket.
If you are not sure if something is a bug yet, you are welcome to ask about something on
the mailing list or IRC first.
If you are not sure if something is a bug yet, you are welcome to ask about something on
the mailing list or IRC first.
As we are a very high volume project, if you determine that
As we are a very high volume project, if you determine that
you do have a bug, please be sure to open the issue yourself to ensure we have a record of
it. Don't rely on someone else in the community to file the bug report for you.
it. Don’t rely on someone else in the community to file the bug report for you.
It may take some time to get to your report, see our information about priority flags below.
I'd Like To Help With Documentation
-----------------------------------
Ansible documentation is a community project too!
Ansible documentation is a community project too!
If you would like to help with the
documentation, whether correcting a typo or improving a section, or maybe even
If you would like to help with the
documentation, whether correcting a typo or improving a section, or maybe even
documenting a new feature, submit a GitHub pull request to the code that
lives in the ``docsite/rst`` subdirectory of the project for most pages, and there is an "Edit on GitHub"
link up on those.
@ -107,9 +107,9 @@ Module documentation is generated from a ``DOCUMENTATION`` structure embedded in
For more information on module documentation see `How to document modules <http://docs.ansible.com/ansible/dev_guide/developing_modules_documenting.html>`_.
Aside from modules, the main docs are in restructured text
format.
format.
If you aren't comfortable with restructured text, you can also open a ticket on
If you aren’t comfortable with restructured text, you can also open a ticket on
GitHub about any errors you spot or sections you would like to see added. For more information
on creating pull requests, please refer to the
`GitHub help guide <https://help.github.com/articles/using-pull-requests>`_.
@ -155,7 +155,7 @@ If you make a mistake you do not need to close your PR. Instead, create a clean
with ``--force`` to overwrite the existing branch (permissible in this case as no one else should be using that
branch as reference). Code comments won't be lost, they just won't be attached to the existing branch.
We'll then review your contributions and engage with you about questions and so on.
We’ll then review your contributions and engage with you about questions and so on.
Because we have a very large and active community it may take awhile to get your contributions
in! See the notes about priorities in a later section for understanding our work queue.
@ -172,14 +172,14 @@ are interested in writing new modules to be included in the core Ansible distrib
to the `module development documentation <http://docs.ansible.com/developing_modules.html>`_.
Ansible's aesthetic encourages simple, readable code and consistent,
conservatively extending, backwards-compatible improvements. When contributing code to Ansible,
conservatively extending, backwards-compatible improvements. When contributing code to Ansible,
please observe the following guidelines:
- Code developed for Ansible needs to support Python2-2.6 or higher and Python3-3.5 or higher.
- Use a 4-space indent, not tabs.
- We do not enforce 80 column lines; up to 160 columns are acceptable.
- We do not accept 'style only' pull requests unless the code is nearly unreadable.
- We are not strictly compliant with PEP8. See :doc:`dev_guide/testing_pep8` for more information.
- We are "PEP8ish", but not strictly compliant, see :doc:`testing_pep8` for more information.
You can also contribute by testing and revising other requests, especially if it is one you are interested
in using. Please keep your comments clear and to the point, courteous and constructive, tickets are not a
@ -228,7 +228,7 @@ To subscribe to a group from a non-google account, you can send an email to the
IRC Meetings
------------
The Ansible community holds regular IRC meetings on various topics, and anyone who is interested is invited to
The Ansible community holds regular IRC meetings on various topics, and anyone who is interested is invited to
participate. For more information about Ansible meetings, consult the `meeting schedule and agenda page <https://github.com/ansible/community/blob/master/meetings/README.md>`_.
Release Numbering
@ -286,7 +286,7 @@ These labels don't really have a definition - they are a simple ordering. Howev
affecting a major module (yum, apt, etc) is likely to be prioritized higher than a module
affecting a smaller number of users.
Since we place a strong emphasis on testing and code review, it may take a few months for a minor feature to get merged. This doesn't mean that we'll be exhausting all of the higher-priority queues before getting to your ticket; we will also take periodic sweeps through the lower priority queues and give them some attention as well, particularly in the area of new module changes.
Since we place a strong emphasis on testing and code review, it may take a few months for a minor feature to get merged. This doesn't mean that we'll be exhausting all of the higher-priority queues before getting to your ticket; we will also take periodic sweeps through the lower priority queues and give them some attention as well, particularly in the area of new module changes.
Every bit of effort helps - if you're wishing to expedite the inclusion of a P3 feature pull request for instance, the best thing you can do is help close P2 bug reports.

View File

@ -41,9 +41,9 @@ Each module has at least one assigned maintainer, listed in a `maintainer's file
.. _Ansibullbot: https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md
.. _maintainer's file: https://github.com/ansible/ansible/blob/devel/.github/BOTMETA.yml
Some modules have no community maintainers assigned. In this case, the maintainer is listed as ``$team_ansible``. Ultimately, it's our goal to have at least one community maintainer for every module.
Some modules have no community maintainers assigned. In this case, the maintainer is listed as ``$team_ansible``. Ultimately, it’s our goal to have at least one community maintainer for every module.
The maintainer's job is to review PRs and decide whether that PR should be merged (``shipit``) or revised (``needs_revision``).
The maintainer’s job is to review PRs and decide whether that PR should be merged (``shipit``) or revised (``needs_revision``).
The ultimate goal of any pull request is to reach **shipit** status, where the Core team then decides whether the PR is ready to be merged. Not every PR that reaches the **shipit** label is actually ready to be merged, but the better our reviewers are, and the better our guidelines are, the more likely it will be that a PR that reaches **shipit** will be mergeable.
@ -54,7 +54,7 @@ Workflow
Ansibullbot runs continuously. You can generally expect to see changes to your issue or pull request within thirty minutes. Ansibullbot examines every open pull request in the repositories, and enforces state roughly according to the following workflow:
- If a pull request has no workflow labels, it's considered **new**. Files in the pull request are identified, and the maintainers of those files are pinged by the bot, along with instructions on how to review the pull request. (Note: sometimes we strip labels from a pull request to "reboot" this process.)
- If a pull request has no workflow labels, it’s considered **new**. Files in the pull request are identified, and the maintainers of those files are pinged by the bot, along with instructions on how to review the pull request. (Note: sometimes we strip labels from a pull request to “reboot” this process.)
- If the module maintainer is not ``$team_ansible``, the pull request then goes into the **community_review** state.
- If the module maintainer is ``$team_ansible``, the pull request then goes into the **core_review** state (and probably sits for a while).
- If the pull request is in **community_review** and has received comments from the maintainer:
@ -110,4 +110,4 @@ Special Labels
- **new_plugin**: this is for new modules or plugins that are not yet in Ansible.
**Note:** `new_plugin` kicks off a completely separate process, and frankly it doesn't work very well at present. We're working our best to improve this process.
**Note:** `new_plugin` kicks off a completely separate process, and frankly it doesn’t work very well at present. We’re working our best to improve this process.

View File

@ -15,13 +15,13 @@ In addition to the information below, module maintainers should be familiar with
Maintainer Responsibilities
===========================
When you contribute a new module to the [ansible/ansible](https://github.com/ansible/ansible) repository, you become the maintainer for that module once it has been merged. Maintainership empowers you with the authority to accept, reject, or request revisions to pull requests on your module -- but as they say, "with great power comes great responsibility."
When you contribute a new module to the `ansible/ansible <https://github.com/ansible/ansible>`_ repository, you become the maintainer for that module once it has been merged. Maintainership empowers you with the authority to accept, reject, or request revisions to pull requests on your module -- but as they say, "with great power comes great responsibility."
Maintainers of Ansible modules are expected to provide feedback, responses, or actions on pull requests or issues to the module(s) they maintain in a reasonably timely manner.
It is also recommended that you occasionally revisit the [contribution guidelines](https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md), as they are continually refined. Occasionally, you may be requested to update your module to move it closer to the general accepted standard requirements. We hope for this to be infrequent, and will always be a request with a fair amount of lead time (ie: not by tomorrow!).
It is also recommended that you occasionally revisit the `contribution guidelines <https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md>`_, as they are continually refined. Occasionally, you may be requested to update your module to move it closer to the general accepted standard requirements. We hope for this to be infrequent, and will always be a request with a fair amount of lead time (ie: not by tomorrow!).
Finally, following the [ansible-devel](https://groups.google.com/forum/#!forum/ansible-devel) mailing list can be a great way to participate in the broader Ansible community, and a place where you can influence the overall direction, quality, and goals of Ansible and its modules. If you're not on this relatively low-volume list, please join us here: https://groups.google.com/forum/#!forum/ansible-devel
Finally, following the `ansible-devel <https://groups.google.com/forum/#!forum/ansible-devel>`_ mailing list can be a great way to participate in the broader Ansible community, and a place where you can influence the overall direction, quality, and goals of Ansible and its modules. If you're not on this relatively low-volume list, please join us here: https://groups.google.com/forum/#!forum/ansible-devel
The Ansible community hopes that you will find that maintaining your module is as rewarding for you as having the module is for the wider community.
@ -31,21 +31,21 @@ Pull Requests, Issues, and Workflow
Pull Requests
-------------
Module pull requests are located in the [main Ansible repository](https://github.com/ansible/ansible/pulls).
Module pull requests are located in the `main Ansible repository <https://github.com/ansible/ansible/pulls>`_.
Because of the high volume of pull requests, notification of PRs to specific modules are routed by an automated bot to the appropriate maintainer for handling. It is recommended that you set an appropriate notification process to receive notifications which mention your GitHub ID.
Issues
------
Issues for modules, including bug reports, documentation bug reports, and feature requests, are tracked in the [ansible repository](https://github.com/ansible/ansible/issues).
Issues for modules, including bug reports, documentation bug reports, and feature requests, are tracked in the `ansible repository <https://github.com/ansible/ansible/issues>`_.
Issues for modules are routed to their maintainers via an automated process. This process is still being refined, and currently depends upon the issue creator to provide adequate details (specifically, providing the proper module name) in order to route it correctly. If you are a maintainer of a specific module, it is recommended that you periodically search module issues for issues which mention your module's name (or some variation on that name), as well as setting an appropriate notification process for receiving notification of mentions of your GitHub ID.
PR Workflow
-----------
Automated routing of pull requests is handled by a tool called [Ansibot](https://github.com/ansible/ansibullbot).
Automated routing of pull requests is handled by a tool called `Ansibot <https://github.com/ansible/ansibullbot>`_.
Being moderately familiar with how the workflow behind the bot operates can be helpful to you, and -- should things go awry -- your feedback can be helpful to the folks that continually help Ansibullbot to evolve.

View File

@ -16,5 +16,3 @@ of some of the most popular of these tools.
- `Ansigenome <https://github.com/nickjj/ansigenome>`_ is a command line tool designed to help you manage your Ansible roles.
- `Awesome Ansible <https://github.com/jdauphant/awesome-ansible>`_ is a collaboratively curated list of awesome Ansible resources.
- `Ansible Inventory Grapher <http://github.com/willthames/ansible-inventory-grapher>_` can be used to visually display inventory inheritance hierarchies and at what level a variable is defined in inventory.

View File

@ -25,7 +25,7 @@ For multiple-file content, we encourage use of gist.github.com. Online pastebin
If you are not sure if something is a bug yet, you are welcome to ask about something on the mailing list or IRC first.
As we are a very high volume project, if you determine that you do have a bug, please be sure to open the issue yourself to ensure we have a record of it. Don't rely on someone else in the community to file the bug report for you.
As we are a very high volume project, if you determine that you do have a bug, please be sure to open the issue yourself to ensure we have a record of it. Don’t rely on someone else in the community to file the bug report for you.
Requesting a feature
====================

View File

@ -17,19 +17,19 @@ import sys
import os
# pip install sphinx_rtd_theme
# import sphinx_rtd_theme
# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
#import sphinx_rtd_theme
#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
# sys.path.append(os.path.abspath('some/directory'))
#sys.path.append(os.path.abspath('some/directory'))
#
sys.path.insert(0, os.path.join('ansible', 'lib'))
sys.path.append(os.path.abspath('_themes'))
VERSION = '2.4'
AUTHOR = 'Ansible, Inc'
VERSION='2.2'
AUTHOR='Ansible, Inc'
# General configuration
@ -38,7 +38,7 @@ AUTHOR = 'Ansible, Inc'
# Add any Sphinx extension module names here, as strings.
# They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
extensions = ['sphinx.ext.autodoc']
# Later on, add 'sphinx.ext.viewcode' to the list if you want to have
# colorized code generated too for references.
@ -55,7 +55,7 @@ master_doc = 'index'
# General substitutions.
project = 'Ansible Documentation'
copyright = "2013-2017 Ansible, Inc"
copyright = "2013-2016 Ansible, Inc"
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
@ -67,16 +67,16 @@ release = VERSION
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
# unused_docs = []
#unused_docs = []
# List of directories, relative to source directories, that shouldn't be
# searched for source files.
# exclude_dirs = []
#exclude_dirs = []
# A list of glob-style patterns that should be excluded when looking
# for source files.
@ -84,26 +84,26 @@ exclude_patterns = ['modules']
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
highlight_language = 'YAML+Jinja'
# Substitutions, variables, entities, & shortcuts for text which do not need to link to anything.
# For titles which should be a link, use the intersphinx anchors set at the index, chapter, and section levels, such as qi_start_:
#Substitutions, variables, entities, & shortcuts for text which do not need to link to anything.
#For titles which should be a link, use the intersphinx anchors set at the index, chapter, and section levels, such as qi_start_:
rst_epilog = """
.. |acapi| replace:: *Ansible Core API Guide*
.. |acrn| replace:: *Ansible Core Release Notes*
@ -128,28 +128,28 @@ html_short_title = 'Ansible Documentation'
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
# html_style = 'solar.css'
#html_style = 'solar.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = 'Ansible Documentation'
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
#html_short_title = None
# The name of an image file (within the static path) to place at the top of
# the sidebar.
# html_logo = None
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = 'favicon.ico'
#html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['.static']
#html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
@ -157,23 +157,23 @@ html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
#html_additional_pages = {}
# If false, no module index is generated.
# html_use_modindex = True
#html_use_modindex = True
# If false, no index is generated.
# html_use_index = True
#html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
#html_split_index = False
# If true, the reST sources are included in the HTML build as _sources/<name>.
html_copy_source = False
@ -181,10 +181,10 @@ html_copy_source = False
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = ''
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Poseidodoc'
@ -194,37 +194,34 @@ htmlhelp_basename = 'Poseidodoc'
# ------------------------
# The paper size ('letter' or 'a4').
# latex_paper_size = 'letter'
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
# latex_font_size = '10pt'
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class
# [howto/manual]).
latex_documents = [
('index', 'ansible.tex', 'Ansible 2.2 Documentation', AUTHOR, 'manual'),
('index', 'ansible.tex', 'Ansible 1.2 Documentation',
AUTHOR, 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
# latex_preamble = ''
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
# latex_appendices = []
#latex_appendices = []
# If false, no module index is generated.
# latex_use_modindex = True
#latex_use_modindex = True
autoclass_content = 'both'
intersphinx_mapping = {'python': ('https://docs.python.org/2/', (None, '../python2-2.7.13.inv')),
'python3': ('https://docs.python.org/3/', (None, '../python3-3.6.2.inv')),
'jinja2': ('http://jinja.pocoo.org/docs/', (None, '../jinja2-2.9.7.inv'))}

Some files were not shown because too many files have changed in this diff Show More