Compare commits

...

130 Commits

Author SHA1 Message Date
0a07068054 New release v2.7.0 2018-10-03 20:27:28 -07:00
4fb5aa00a6 updates latest in docs conf.py (#46400)
(cherry picked from commit ba9348883b)
2018-10-03 22:16:46 -05:00
a1d1276b6e disable gather facts and update playbook output (#46409) (#46418)
* disable facts gather and update playbook output

* fix output

(cherry picked from commit a1fae193c7)
2018-10-02 16:23:10 -05:00
d81ed54ae6 Updates release & maintenance version docs for 2.7 (#46414)
(cherry picked from commit 04b726dc14)
2018-10-02 16:20:36 -05:00
649403c3a1 yes, we do run validate_modules in Shippable (#46280) (#46283)
(cherry picked from commit 66eb5681f4)
2018-09-28 13:32:49 -05:00
4ae2f96902 fix wording for silencing a sensu client (#46250) (#46267)
(cherry picked from commit dae2172045)
2018-09-28 11:08:29 -05:00
ac2ff94d43 Meraki scenario guide - Changed section markup types (#46158) (#46263)
* Changed section markup types, small fixes for style
- Add dashes per style guide
- Add TOC in case this grows

(cherry picked from commit a690917b5f)
2018-09-28 11:08:11 -05:00
6e86b317a9 Clean up Vault docs in User Guide. (#46188) (#46270)
- Fix spelling of 'separate' and 'algorithm'
- Fix indentation of nested list in payload format
- Fix mysterious refernce to 'b_pkey1'.
- Fix reference to newline as '\n': the backslash is lost when rendered
to the docs website. Specify the hex value for newline instead of the
backslash escape.

(cherry picked from commit ab96bbdef9)
2018-09-28 10:42:46 -05:00
61f95149b9 Set release to a post release 2018-09-27 18:09:31 -07:00
35b290f0c9 New release 2.7.0rc4 2018-09-27 16:38:00 -07:00
11c7ddcb70 [stable-2.7] Update the minimum python versions to install (#46230)
* Update the minimum python versions to install

This will prevent modern pip from installing ansible-2.7.x in
python-2.6.  Users will get the Ansible-2.6.x maintenance releases
instead.
(cherry picked from commit ccf41bb)

Co-authored-by: Toshio Kuratomi <a.badger@gmail.com>
2018-09-27 15:35:54 -07:00
742e15d03b skip installing linux-image-extra in CI as it shouldn't be needed (#46101)
(cherry picked from commit 40379b76b1)
2018-09-27 12:59:13 -07:00
37df3796e1 Fix and re-enable sts_assume_role integration tests (#46026)
* Fix the STS assume role error message assertion when the role to assume does not exist.

(cherry picked from commit 18dc928e28)
2018-09-27 12:58:06 -07:00
7cce4dfbb0 add skip/docker alias to skip tests when running on Docker (#45955)
* add skip/docker alias to skip tests when running on Docker

* changed warning message wording

(cherry picked from commit 27c10fa502)
2018-09-27 12:50:06 -07:00
dc66eb07d0 [backport-2.7] Meraki scenario guide (#41827) (#45494)
* Meraki scenario guide (#41827)
(cherry picked from commit ec3ce1f39c)
2018-09-26 09:18:30 -05:00
2368c2e30b Revert "winrm: add further conditional to using pexect for kerb auth (#45952)"
This reverts commit 918d45f957.

Unintentionally merged before 2.7.0 final.
2018-09-25 13:52:38 -07:00
918d45f957 winrm: add further conditional to using pexect for kerb auth (#45952)
(cherry picked from commit d6251e5b27)
2018-09-25 13:49:27 -07:00
ab1b602053 Update synchronize.py, mention variable ansible_rsync_path needed for different local rsync binary (#41870) (#46110)
* Update synchronize.py

If you want a different rsync binary on the local side, you need to set task variable ansible_rsync_path.
See examples.

Variable ansible_rsync_path looks to not be documented anywhere. If documented, needs to be said that is does not belong to synchronise options, instead belongs to tasks. (Sorry, I have no better wording)
(cherry picked from commit c44de1069c)
2018-09-25 11:22:07 -05:00
518c90dc68 Added documentation for collectstatic --clear. (#42007) (#45860)
* Added documentation for collectstatic --clear.

Added a description of the --clear argument used with the Django management
command, collectstatic. (When #1810 added this feature the documentation
was not updated).
(cherry picked from commit f964277628)
2018-09-25 11:05:15 -05:00
0d40e4bd23 inventory/tower: authors -< author so Doc can pick it up (#45936) (#45972)
(cherry picked from commit a7bf505474)
2018-09-25 11:01:15 -05:00
adba21d8d2 The sshkey option is available in version 2.7 and above (#46103) (#46107)
(cherry picked from commit 8213096b7f)
2018-09-25 11:00:50 -05:00
e85c485129 spotinst_aws_elastigroup elastic_ips example (#41190) (#46111)
* Update spotinst_aws_elastigroup.py
(cherry picked from commit c11c3506cd)
2018-09-25 10:56:31 -05:00
8712f0f7f4 Update sl_vm.py (#43966) (#46109)
* Update sl_vm.py
Updated the list of softlayer datacenters
(cherry picked from commit d1688adefc)
2018-09-25 08:54:13 -05:00
8f93a0ec67 Update developing_modules_general_aci.rst (#46042) 2018-09-22 19:56:25 -05:00
73bc121e11 added note about cli execution of include_x (#45227) (#45999)
(cherry picked from commit 03d8b68549)
2018-09-21 14:53:29 -05:00
f28abce4a2 Update short description for NetApp E-Series modules. (#45820) (#45864)
Update short description according to new standards
(cherry picked from commit 205693a3f9)
2018-09-21 14:04:43 -05:00
3d88063c40 NetApp Bulk Doc changes (#45856) (#45866)
* Doc changes
* fix ansibot issue & spacing
(cherry picked from commit e3ec9e5345)
2018-09-21 14:02:43 -05:00
2474a4c9bd Misc typo fixes (#45969) (#45978)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 0ecbd50c3b)
2018-09-21 13:56:35 -05:00
aa703eddef Add docs for say.py to indicate how to list voices (#37737) (#45979)
* Update say.py
(cherry picked from commit 0677dabad4)
2018-09-21 13:55:33 -05:00
d34ed1d942 Update to post release so we can tell when someone is running from a checkout 2018-09-20 20:11:14 -07:00
2a33276385 New release 2.7.0rc3 2018-09-20 18:07:04 -07:00
6e6825e79f append AWS region to test instance file (#45877)
(cherry picked from commit 582a4dfa13)
2018-09-20 12:24:58 -07:00
0c81145fd3 [WIP] Backport/2.7/second batch (#45927)
* Update influxdb_database.py (#39984)
(cherry picked from commit 049a462058)

* Link to the Galaxy platforms list from the meta file template (#34046)
(cherry picked from commit fa18d45eb3)

* fix gce_backend_service examples for healthchecks (#31134)
(cherry picked from commit e26d758d6f)

* Clarify the creates and removes options (#45485)
(cherry picked from commit bf90a44468)

* lineinfile note belongs in changelog for 2.6, not 2.7 (#45517)
(cherry picked from commit 228fee4f3a)

* Update keycloak_client.py (#43547)
(cherry picked from commit cb460dee74)

* The keyword 'cloud' has been deprecated in favor of the 'profile' keyword by os-client-config. (#31389)
(cherry picked from commit 17ca0a9bd9)

* Clarified documentation for the unsafe_writes option (#27471)
(cherry picked from commit dd5d191d7a)
2018-09-20 14:10:39 -05:00
bf09c869a2 Update fileglob.py (#45558)
* Update fileglob.py

Closes #45557

* Update fileglob.py

(cherry picked from commit cc477ec920)
2018-09-20 12:06:02 -07:00
7a6d873f0a go back to FreeBSD 11.1 for tests due to 11.2 stability issues (#45872)
(cherry picked from commit a7d372c3ba)
2018-09-20 12:04:08 -07:00
ceb474bb9e [WIP] Backport/2.7/batch port (#45859)
Batch of docs backports:

* docs: Clarify include_task v import_tasks with conditionals (#43856)
(cherry picked from commit 6be42a2a0e)

* Add single quotes around package name (#45152)
(cherry picked from commit 0d81386144)

* prefer ansible_facts namespace and dict notation (#44980)
(cherry picked from commit 44510448b0)

* fix cherrypick conflict - scenario_guides

* Update implicit_localhost.rst (#45455)
(cherry picked from commit f68cd1acc6)

* updated fbsd install instructions (#45309)
(cherry picked from commit e9c2695ce7)

* Change "Defaulting Undefined Variables" (#41379)
(cherry picked from commit e35c4be1c1)

* adds license details to dev guide pages (#45574)
(cherry picked from commit 6e68d77f6d)

* FAQ: fix a typo, add link to 'vars' lookup (#42412)
(cherry picked from commit 95649dc793)

* Fix link and toctree (#45595)
(cherry picked from commit 6999bf318f)

* Improve the local toctree (and title) (#45590)
(cherry picked from commit afea00fa9f)

* Add undocumented configuration parameter and explain in porting guide (#36059)
(cherry picked from commit a892a6ef03)

* Simplify PPA installation for Ubuntu (#45690)
(cherry picked from commit 78e9f452a5)

* adding git+ssh uri scheme (#36025)
(cherry picked from commit 84a4257774)

* Add workaround for non-standard kerberos environments (#41465)
(cherry picked from commit 4e532e0ad9)

* Restore license agreement (#45809)
(cherry picked from commit f430f60541)

* partial cherry-pick - lenovo doc update PR 45483
2018-09-19 22:02:01 -05:00
7cc699f068 Explain disk size in mount and add example (#41681)
* Explain disk size in mount and add example

- Explain mount with 8GB
- Add new example to start container with mount

* Removed trailing whitespace

(cherry picked from commit f85065dabf)
2018-09-19 14:42:55 -07:00
6b2c653a64 Update postgresql_user.py (#45777)
<!--- Your description here -->
Add expires example.
+label: docsite_pr
(cherry picked from commit 61f2791d95)
2018-09-19 14:42:09 -07:00
2008e9d28c [2.7] Fix collections.deque import in compat module (#45837)
(cherry picked from commit a978d7f283)

Co-authored-by: Sviatoslav Sydorenko <wk@sydorenko.org.ua>
2018-09-19 13:50:55 -07:00
e881ea8957 Remove placeboify from unit tests that are not calling AWS (i.e. creating a recording) (#45754)
(cherry picked from commit 2167ce6cb6)
2018-09-19 13:32:02 -07:00
af4971fd1a [aws unit test utils] only create a recordings directory when the env var is set (#45752)
* Only create placebo recording test directories when the environment variable PLACEBO_RECORD is set
(cherry picked from commit 5467ac3454)
2018-09-19 13:28:00 -07:00
98e31e98c8 ec2_group: fix regression for targets that are a list containing strings and lists (#45594)
* Fix targets that may be a list containing strings and lists which worked prior to 2.6.

* Add ec2_group integration tests for lists of nested targets

* changelog

* Add diff mode support for lists of targets containing strings and lists.

(cherry picked from commit d7ca3f2bd3)
2018-09-19 13:20:31 -07:00
79cebbf933 These won't get upgraded to bool if ansible doesn't know they are
Adapted from #45736, the other change came from a commit that will not
be backported
2018-09-19 13:15:43 -07:00
92f7429fb6 hashi_vault lookup: add integration tests (#44814)
* hashi_vault lookup: add integration tests

* hashi_vault lookup tests: use ansible-ci-files

(cherry picked from commit 9984c0fd40)
2018-09-19 12:57:22 -07:00
934190f02e More bigip software fixes
Fixes problems related to token timeout. Adds cleanup of tokens.

(cherry picked from commit 604b95aab2)
2018-09-19 12:35:21 -07:00
9b4bb04d07 [2.7]fix nxos_facts indefinite hang for text based output (#45846)
* fix nxos_facts indefinite hang for text based output (#45845)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit 1b0c4fde86)
2018-09-19 09:00:53 -07:00
23f70d9745 Backport of 45588 (#45670) 2018-09-17 11:57:12 -05:00
0c411eeca6 Add .post0 to version so we know when someone is running from a checkout 2018-09-13 16:46:02 -07:00
6fe6d04489 New release v2.7.0rc2 2018-09-13 11:41:10 -07:00
eb882a144b Clarify what "performance improvement" means in changelog for deepish-copy (#45606) 2018-09-13 10:29:48 -04:00
b52148d65d [2.7] Exclude the whole ansible_failed_task block (#45587)
It has lots of FieldAttributes that won't serialize.
Also the connection doesn't care.
(cherry picked from commit 3d0f19d)

Co-authored-by: Nathaniel Case <this.is@nathanielca.se>
2018-09-13 06:47:10 -07:00
25349b89dd Fixes bugs in the bigip_software modules (#45577)
This patch makes hotfix code work, where before, only base images
were working

(cherry picked from commit e266a24263)
2018-09-12 14:30:34 -07:00
186f4effd3 [2.7] eos: Don't error on VLAN missing warning (#45433)
(cherry picked from commit eaf01d3)

Co-authored-by: Nathaniel Case <this.is@nathanielca.se>
2018-09-12 12:47:29 -07:00
e16d36f0f7 Backport: fix the autoscale resource id #45477 (#45532)
* fix the autoscale resource id (#45477)

* fix the autoscale resource id

* Update main.yml

(cherry picked from commit fa04387550)
2018-09-12 12:46:16 -07:00
9a0f1d8915 VMware: Fix wait_for_task backoff behavior
Signed-off-by: Harald Albers <github@albersweb.de>

(cherry picked from commit 796d8b5dc8)
2018-09-12 12:43:26 -07:00
426d4bf8d6 Update RHEL and FreeBSD versions used for tests:
- RHEL 7.4 -> 7.5
- FreeBSD 11.1 -> 11.2

(cherry picked from commit c50d6f1944)
2018-09-12 10:19:20 -07:00
c1d8efa469 Add docs on how to write changelog fragments (#42428) (#45570)
* Add docs on how to write changelog fragments

* Add link to new style changelog

Remove redundant mention of old style changelog

(cherry picked from commit 5d6f844eba)
2018-09-12 11:44:00 -05:00
c41681b888 [backport-2.7] Fix remote checksums when paths have leading dots (#45287) (#45501)
* Fix remote checksums when paths have leading dots (#45287)

* Fix remote checksums with paths have leading dots

* Fix result recorded from the wrong file

* Add changelog fragment

(cherry picked from commit 600c7ac108)
2018-09-12 08:05:25 -07:00
99171a9c6f [stable-2.7] Fix logic to not re-download existing files when force=no (#45495) (#45509)
* [stable-2.7] Fix logic to not re-download existing files when force=no (#45495)

* Fix logic to not re-download existing files when force=no. Fixes #45491

* Reduce logic complexity.
(cherry picked from commit 5785de582f)

Co-authored-by: Matt Martz <matt@sivel.net>

* Backport of get_url fix cannot use result

result was only added in 2.8+
2018-09-12 07:28:54 -07:00
c8fe1126a1 Update default container to version 1.2.0.
(cherry picked from commit d478a4c3f6)
2018-09-11 15:45:21 -07:00
4a8a931d0f Reduce cost of Azure DB tests.
(cherry picked from commit ed49f37957)
2018-09-11 15:45:21 -07:00
59a2d880bc Fix ACI unit test on Python 3.7.0.
The previous logic was only needed for pre-release versions of 3.7.

(cherry picked from commit c0bf9815c9)
2018-09-11 15:45:21 -07:00
66cfb3d91e Avoid duplicate Azure storage account types.
(cherry picked from commit ae4d5e3257)
2018-09-11 15:45:21 -07:00
f3b394cf4c update porting guides (#40784)
* update porting guides

With PR #40532 `shade` library was retired and replaced with direct use
of `openstacksdk`. Porting guides and doc about dynamic inventory were
not updated.

(cherry picked from commit 8ae14bebda)
2018-09-11 14:35:16 -07:00
4c080f649b [aws] cloudfront_distribution - fix method name, backport/2.7/45498 (#45512)
* [AWS] cloudfront_distribution - fix method name from 'validate_distribution_id_from_caller_reference' to 'validate_distribution_from_caller_reference' and set distribution_id to the distribution's key 'Id' (#45498)

(cherry picked from commit e5269c047c)

* changelog
2018-09-11 14:34:35 -07:00
d9d1c40932 win_group_membership - fix random issue with CI on 2012 R2 (#45462)
(cherry picked from commit 3371a779b6)
2018-09-11 07:05:18 -07:00
d559213b31 fix Ansible.ModuleUtils.FileUtil to respect ErrorAction if running in a try/catch (#45451)
(cherry picked from commit d4ce1b9f31)
2018-09-10 17:38:40 -07:00
f2d5954d11 win_say - fix up syntax and test issues (#45450)
(cherry picked from commit c9c141fb6a)
2018-09-10 17:37:42 -07:00
89ab0b5d32 reordered windows test groups for better efficiency (#45445)
(cherry picked from commit 25ae4f2b73)
2018-09-10 17:36:59 -07:00
d956b6c64e [stable-2.7] Don't pass file_name to DataLoader.load in script inventory plugin (#45428)
* Don't pass file_name to DataLoader.load in script inventory plugin. Fixes #34164

* Add changelog fragment
(cherry picked from commit 263b9fa)

Co-authored-by: Matt Martz <matt@sivel.net>
2018-09-10 17:36:22 -07:00
e354047258 Set defaults from params after loading files, allowing params to override (#45442)
* Set defaults from params after loading files, allowing params to override (#44142)

* Set defaults from params after loading files, allowing params to override

* cleanup, add some comments

(cherry picked from commit aa01d9d243)

* Add client_from_kubeconfig function back for 2.7.0 since it's late in the 2.7 cycle to remove module_util code.
2018-09-10 17:34:30 -07:00
47410bdf5c meraki_mr_l3_firewall - Integration test fix (#45366)
* Fix integration test as wrong module was called

* Create block section for failures on integration test for mr_l3_firewall integration test

(cherry picked from commit 6c67674eab)
2018-09-10 09:51:31 -07:00
07b87c2ab7 meraki_network - Fix enabling my.meraki.com (#45352)
* Fix enabling my.meraki.com
- A parameter of "no" wouldn't be picked up
- Check for False in addition to whether it exists

* Clean up disable_my_meraki parameter check

(cherry picked from commit afbf72cfeb)
2018-09-10 09:50:12 -07:00
e74a681337 Use a sensible default for k8s merge_type (#45284)
* Use a sensible default for k8s merge_type

The sensible default for merge_type is `['strategic-merge', 'merge'].
However, we can't make this the default default, as we need to support
users who are using openshift 0.6.0, where the merge_type parameter is
unsupported.

* Refactor k8s test suite for merge_type tests

Allow tests with pre-merge-type openshift and post-merge-type
openshift.

(cherry picked from commit 1463c2e4a8)
2018-09-10 09:46:45 -07:00
b8c053ad1f Corrects documentation for parameters and examples (#45311)
Documentation for the bigiq modules was a little out of date.
This patch corrects the examples and parameters.

(cherry picked from commit e21b99b098)
2018-09-10 09:34:10 -07:00
3e14a34744 [stable-2.7] Ensure loop with delegate_to can short circuit the same as without delegate_to. Fixes #45189 (#45231)
(cherry picked from commit 2ac647d)

Co-authored-by: Matt Martz <matt@sivel.net>
2018-09-07 13:01:55 -07:00
1301d4edc8 rewrite of the developer guide, part 1 (#45179) (#45349)
(cherry picked from commit 9a76441c02)
2018-09-07 10:35:13 -05:00
e7e345da7e Correct version_added for strategy host_pinned (#45333)
(cherry picked from commit 97fcc3ef66)
2018-09-07 07:12:40 -07:00
2fcae8b367 Cherrypick stable2.7 44802 (#45332)
* fix blob in non-public azure cloud (#44802)

(cherry picked from commit b58141555d)
2018-09-07 07:12:06 -07:00
351bb3dd9a [2.7] Add ambiguous command check as the error message is not persistent on nexus devices (#45341)
* Add ambiguous command check as the error message is not persistent on nexus devices (#45337)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit f18856d0e2)

* cli_config module doc update (#45345)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit d5bfd93e28)
2018-09-07 07:09:25 -07:00
fdb9c6d5af Switch version number so that we can tell when someone is running from source 2018-09-06 20:06:00 -07:00
0202339461 New release 2.7.0rc1 2018-09-06 18:44:59 -07:00
283859ec88 Changelog for AWS bugfixes (#45319)
* Add changelog for AWS backports
2018-09-06 13:29:22 -07:00
c96a440063 Fix backwards compatibility without providing prefix since boto3 does more parameter validation than boto (#45308)
Use .get() instead of assuming a rule has a Transitions or Filter key (both of which are optional)

(cherry picked from commit 8b341619ae)
2018-09-06 13:28:52 -07:00
d8c687f638 check for change of role arn in ecs task definition (#44942)
* check role arn for ecs task definition

If the task role in a ECS task definition changes ansible should create a new revsion of the task definition.

(cherry picked from commit 71c4355d58)
2018-09-06 13:28:31 -07:00
26a96c72b2 Fix callback config typos (#45316)
* plugins/callbacks : fix some key documentation (#45267)

These are supposed to be a dictionary with section/key entries;
correct a few typos.

(cherry picked from commit c34e0f5e11)

* backport of #45267
2018-09-06 13:27:59 -07:00
Rob
08542720e5 Fix health check configurations being ignored - #43244 (#43247)
* Fix health check configurations being ignored - #43244

* Ensure health_check_protocol is not None before check

* Simplify long indented if statement

(cherry picked from commit 7e426b0381)
2018-09-06 12:55:01 -07:00
0e2642e392 [aws] ec2_metadata_facts URL encode the metadata URL to avoid errors (#43394)
- If a field in the URL has a space it would result in a 400 without making it URL safe
- Fixes #42371 and #43378

(cherry picked from commit 4ce09ea62d)
2018-09-06 12:54:08 -07:00
c60baf0ca7 [aws] lambda_policy fix update when principal is an account number (#44871)
Fix KeyError on update when principal is an account number
(cherry picked from commit 1f3e7ea061)
2018-09-06 12:44:34 -07:00
55eebfc6b7 [aws] ec2_group multi-account and peered VPC bugfix (#45296)
* Add tests to replicate bug #44788 

* Handle when userId is same account due to in-account peering

* Module defaults for main.yml

* Turn off VPC peering tests in CI
2018-09-06 12:43:31 -07:00
d3225b0494 Fix diff_ignore_lines option issue for candidate configuration (#45201)
* Fix diff_ignore_lines option issue for candidate configuration

*  diff_ignore_lines option is to handle the running config fetch from
   remote host and ignore the lines that are auto updated eg: commit time and date
*  This option should not be used while processing candidate (input) configuration

* Fix review comment

(cherry picked from commit a3c137c1ab)
2018-09-06 11:53:27 -07:00
22f50e416d correct and clarify deprecation (#45234)
* correct and clarify deprecation

(cherry picked from commit 64c594d226)
2018-09-06 11:36:28 -07:00
6391f4f4c3 Backport 2.7 - Select image facts by region (#45297)
* Select image facts by region

* fix version numbers since this is being backported

Signed-off-by: Adam Miller <admiller@redhat.com>
2018-09-06 11:35:12 -07:00
0c6c29900d iosxr dci failure on devel/2.7 (#45268)
(cherry picked from commit 23d54ed1d4)
2018-09-06 10:34:23 -07:00
f0eebf9187 Fix ec2_group for numbered protocols (GRE) (#42765)
* Fix spurious `changed=True` when int is passed as tag

* Fix for all AWS module using compare_aws_tags

* Handle improperly stringified protocols and allow inconsistency between None/-1 on non-tcp protocols

* Add integration test that reproduces the same bug

* Return false if the comparsison is not equal

(cherry picked from commit 20f21779d3)
2018-09-06 10:32:52 -07:00
66759810a0 elb_target_group - prevent a KeyError exception (#45169)
Ensure ports to integers after allowing the key 'Targets' to be available in params

(cherry picked from commit 038fd0d0f2)
2018-09-06 10:30:28 -07:00
6d49cd643c [aws] Add suboptions to aws_application_scaling_policy (#43042)
* [aws] Add suboptions to aws_application_scaling_policy

Fixes #42917

* Remove any suboptions that are None

(cherry picked from commit 9d1bf32825)
2018-09-06 10:27:02 -07:00
c89d9d5c8f ec2 inventory: python 3.7 compatibility (#43716)
ec2 inventory script was throwing errors when using Python 3.7:

TypeError: option values must be strings

This changes the None ConfigParser options to empty strings instead.

(cherry picked from commit 505ce6ccf6)
2018-09-06 10:24:42 -07:00
cc4854fdad ec2_vpc_route_table - allow routes to be created if the CIDR already … (#45178)
* ec2_vpc_route_table - allow routes to be created if the CIDR already exists but its 'Origin' is 'EnableVgwRoutePropagation' (which cannot be replaced). (#43417)

Fixes #43415
(cherry picked from commit a6c97f2243)
2018-09-06 10:22:10 -07:00
264c7c22fb Updates documentation formatting and dependencies (#45252)
The documentation formatting was a bit incorrect and the dependencies
mentioned were out of date. This fixes that.

(cherry picked from commit 4154cab278)
2018-09-06 10:15:52 -07:00
37d977c3b8 fix nxos terminal plugin
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2018-09-06 10:09:27 -07:00
03cdcc7d58 fix python26 nxos terminal plugin bug (#45271)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit c98494d5bf)
2018-09-06 10:09:27 -07:00
3b46dd144b terminal plugin nxos, iosxr changelog
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
2018-09-06 10:09:27 -07:00
c1c9d88ebc fix Python 2.6 regex bug terminal plugin nxos, iosxr (#45135)
Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit ab3cd10dfe)
2018-09-06 10:09:27 -07:00
2a8ffbc0ed Fix netconf module and plugin issues (#45140)
* Fix netconf netconf issues

*  Identifier is optional for get_schema api
*  Fix dispatch api mandatory argument check
*  Add save option handling to copy config from target datastore
   to startup datastore if supported
*  Validate config in check-mode or if validate option set to true

* Copy config if check-mode is not enabled

(cherry picked from commit 455dfbe732)
2018-09-06 10:04:59 -07:00
ceb90f6632 Fix sshkeyfilename is None not str (#44893)
(cherry picked from commit 177fbea351)
2018-09-06 10:02:44 -07:00
25025d8246 Add a table of contents to the generated changelog (#45046)
(cherry picked from commit fdb51b34da)
2018-09-06 09:56:18 -07:00
ddb6471d64 Docs updated and review comments addressed (#45133)
(cherry picked from commit 3beeeffef9)
2018-09-06 09:55:56 -07:00
c5f6aa69a1 Backport of 45091 2018-09-06 09:53:36 -07:00
055c3e8d0d Backport of 45088 2018-09-06 09:50:15 -07:00
82f8c2add9 [2.7] docker_*: changelogs (#45056)
* Add changelog entry for #16748.

* Changelog entry for #33579.

* Added changelog for #42380.

* Added changelog for #42641.

* Adding changelog entry for #42857.

* Added changelog for #44808.
2018-09-06 09:39:34 -07:00
e857157072 Improve dnf group output for clarity
Add note about group removal bug upstream dnf

Signed-off-by: Adam Miller <admiller@redhat.com>
2018-09-06 09:27:37 -07:00
576700a8a1 Remove obsolete default container.
(cherry picked from commit 4173a30941)
2018-09-05 19:21:06 -07:00
e47f53e4ff Switch default test container to quay.io.
(cherry picked from commit 3f8edb440a)
2018-09-05 19:21:06 -07:00
b73a7bbf39 Fixes for ansible-test sanity import test. (#45249)
* Fix import test on Python 3.7.
* Fix path processing in import sanity test.

(cherry picked from commit 6fb333faff)
2018-09-05 19:21:06 -07:00
3514a5d1b9 Fix ansible-test virtualenv use in import test.
(cherry picked from commit 998badbda5)
2018-09-05 19:21:06 -07:00
cc5d880a61 Skip ipaddr test that fails on Python 3.7+.
(cherry picked from commit f7979e4938)
2018-09-05 19:21:06 -07:00
f9cf4b2d8a Update test constraints. (#44975)
- Limit virtualenv version on Python 2.6.
- Limit pyopenssl version on Python 2.6.
- Pin pyfmg version to keep unit tests passing.

(cherry picked from commit b3a3e8ba7b)
2018-09-05 19:21:06 -07:00
07161cf6d3 Fixing typo in acme_certificate docs. (#45082) (#45084) 2018-09-05 09:04:09 -05:00
bebda470a1 Update porting_guide_2.7.rst (#45215)
changing changelogs url link
2018-09-05 08:52:29 -05:00
6586d6faff Add rds_instance to AWS module_defaults group (#45168)
(cherry picked from commit 617b8df5e6)
2018-09-04 13:38:55 -04:00
0a7d5ebd73 fixed formatting (#45164) (#45174)
(cherry picked from commit 58ca82fa1c)
(cherry picked from commit fe119c18ef)
2018-09-04 11:41:17 -05:00
1d06a86481 Add licence and boilerplate to Online module_utils 2018-09-04 06:30:59 -07:00
4fff85d66f [stable-2.7] Add an user facts module for Online (#44709)
(cherry picked from commit 5cf9644003)

Co-authored-by: Rémy Léone <remy.leone@gmail.com>
2018-09-04 06:30:59 -07:00
8a8da98546 Change release for the period until 2.7.0rc1 2018-08-31 19:56:41 -07:00
097aaeb733 Update changelogs for 2.7.0b1 2018-08-31 14:40:47 -07:00
77ed7545fa Add a summary for 2.7.0b1 2018-08-31 14:36:48 -07:00
8323524e9f Rename the 2.7.0a1 summary.
I didn't realize these summary files need to be created unique for the
minor releases too
2018-08-31 11:41:34 -07:00
9376c41c61 Update version number for 2.7.0beta1 2018-08-31 11:16:39 -07:00
f414424735 Update the docsite Version to 2.7 2018-08-31 11:04:24 -07:00
351 changed files with 5020 additions and 4090 deletions

View File

@ -1,4 +1,9 @@
releases:
2.7.0:
codename: In the Light
fragments:
- v2.7.0_summary.yaml
release_date: '2018-10-03'
2.7.0.a1:
codename: In the Light
fragments:
@ -94,7 +99,7 @@ releases:
- user-module-backup-shadow.yaml
- user_freebsd_always_changed_bugfix.yaml
- v2.7.0-initial-commit.yaml
- v2.7.0_summary.yaml
- v2.7.0a1_summary.yaml
- vars_prompt-allow-prompting-for-play-vars.yaml
- vault-errors.yaml
- vultr_modules_renamed.yml
@ -303,3 +308,142 @@ releases:
- grafana_dashboard
- nios_next_network
release_date: '2018-08-27'
2.7.0b1:
codename: In the Light
fragments:
- blockdoc.yml
- delegate-to-get-vars-no-task.yaml
- gcp_service_account_home_path.yaml
- include-apply-insert-order.yaml
- include-double-handler.yaml
- loop-cache-fix.yaml
- no-dynamic-import-tasks.yaml
- onepassword_unlock_vault.yaml
- plugins-accept-only-valid-args.yaml
- urls-if-modified-since.yaml
- v2.7.0b1_summary.yaml
- win_disk_image-mount-paths.yaml
- win_psexec_command_arg.yaml
- win_psexec_session-selection.yaml
- win_uri-json.yml
- win_wait_for-timeout.yaml
modules:
- azure_rm_autoscale
- azure_rm_autoscale_facts
- azure_rm_containerregistry_facts
- azure_rm_sqlfirewallrule
- azure_rm_trafficmanagerendpoint
- azure_rm_trafficmanagerendpoint_facts
- azure_rm_trafficmanagerprofile
- azure_rm_trafficmanagerprofile_facts
- azure_rm_webapp_facts
- cpm_user
- elb_target_facts
- fmgr_provisioning
- ftd_configuration
- ftd_file_download
- ftd_file_upload
- gcp_compute_router
- gcp_spanner_database
- gcp_spanner_instance
- gcp_sql_database
- gcp_sql_instance
- gcp_sql_user
- ibm_sa_host
- ibm_sa_pool
- na_elementsw_access_group
- na_elementsw_account
- na_elementsw_admin_users
- na_elementsw_check_connections
- na_elementsw_cluster
- na_elementsw_drive
- na_elementsw_ldap
- na_elementsw_network_interfaces
- na_elementsw_node
- na_elementsw_snapshot
- na_elementsw_snapshot_restore
- na_elementsw_volume_clone
- na_ontap_autosupport
- na_ontap_cluster_peer
- na_ontap_command
- na_ontap_disks
- na_ontap_firewall_policy
- na_ontap_gather_facts
- na_ontap_motd
- na_ontap_node
- netapp_e_alerts
- netapp_e_asup
- netapp_e_auditlog
- netapp_e_global
- netapp_e_iscsi_interface
- netapp_e_iscsi_target
- netapp_e_ldap
- netapp_e_mgmt_interface
- netapp_e_syslog
- onepassword_facts
- opx_cps
- purefb_facts
- rds_instance
- redfish_command
- redfish_config
- tower_credential_type
- tower_settings
- tower_workflow_template
- vmware_host_ntp_facts
- win_wait_for_process
- win_xml
plugins:
lookup:
- cpm_metering
release_date: '2018-08-31'
2.7.0rc1:
codename: In the Light
fragments:
- 16748-docker_container-memory.yaml
- 33579-docker_container-log_driver.yaml
- 42380-docker_container-check-mode.yaml
- 42641-44812-docker-env-variables.yaml
- 42857-docker_container-working_dir.yaml
- 44808-docker_container-idempotency.yaml
- aws_bugfix_backports.yml
- cb_fix_config.yml
- dnf-group-removal.yaml
- ec2_vpc_route_table_replace_route_fix.yaml
- elb_target_group_fix_KeyError.yaml
- systemd_user_dep_fixes.yml
- terminal_plugin_nxos_iosxr.yaml
- v2.7.0rc1_summary.yaml
modules:
- online_user_facts
release_date: '2018-09-06'
2.7.0rc2:
codename: In the Light
fragments:
- 45501-get_url-better_checksums.yaml
- aws_cloudfront_distribution_fix_nonexistent_method_name.yaml
- azure-storage-cloud-environment.yaml
- azure_autoscale.yaml
- get-url-fix-idempotency.yaml
- loop_undefined_delegate_to.yaml
- nxos_ambiguous_command_check.yaml
- script-module-no-file-path.yaml
- v2.7.0rc2_summary.yaml
- vmware_wait_for_task_fix.yaml
- win_group_membership-com-marshal.yaml
- win_say-fix.yaml
plugins:
strategy:
- host_pinned
release_date: '2018-09-13'
2.7.0rc3:
codename: In the Light
fragments:
- ec2_group_fix_target_containing_list_within_list.yaml
- fix_nxos_facts_indefinite_hang.yaml
- v2.7.0rc3_summary.yaml
release_date: '2018-09-20'
2.7.0rc4:
codename: In the Light
fragments:
- v2.7.0rc4_summary.yaml
release_date: '2018-09-27'

View File

@ -2,8 +2,11 @@
Ansible 2.7 "In the Light" Release Notes
========================================
v2.7.0.a1
=========
.. contents:: Topics
v2.7.0
======
Release Summary
---------------
@ -42,8 +45,10 @@ Minor Changes
- Explicit encoding for the output of the template module, to be able to generate non-utf8 files from a utf-8 template. (https://github.com/ansible/proposals/issues/121)
- File locking feature added, making it possible to gain exclusive access to given file through module_utils.common.file.FileLock (https://github.com/ansible/ansible/issues/29962)
- Fix dnf handling of autoremove to be compatible with yum
- Fix timer in exponential backoff algorithm in vmware.py.
- Fixed group action idempotent transactions in dnf backend
- Fixed group actions in check mode to report correct changed state
- GCP Modules will do home path expansion on service account file paths
- In Ansible-2.4 and above, Ansible passes the temporary directory a module should use to the module. This is done via a module parameter (_ansible_tmpdir). An earlier version of this which was also prototyped in Ansible-2.4 development used an environment variable, ANSIBLE_REMOTE_TMP to pass this information to the module instead. When we switched to using a module parameter, the environment variable was left in by mistake. Ansible-2.7 removes that variable. Any third party modules which relied on it should use the module parameter instead.
- New config options `display_ok_hosts` and `display_failed_stderr` (along with the existing `display_skipped_hosts` option) allow more fine-grained control over the way that ansible displays output from a playbook (https://github.com/ansible/ansible/pull/41058)
- Removed an unnecessary import from the AnsiballZ wrapper
@ -53,15 +58,19 @@ Minor Changes
- The acme_account and acme_certificate modules now support two backends: the Python cryptograpy module or the OpenSSL binary. By default, the modules detect if a new enough cryptography module is available and use it, with the OpenSSL binary being a fallback. If the detection fails for some reason, the OpenSSL binary backend can be explicitly selected by setting select_crypto_backend to openssl.
- The apt, ec2_elb_lb, elb_classic_lb, and unarchive modules have been ported away from using __file__. This is futureproofing as__file__ won't work if we switch to using python -m to invoke modules in the future or if we figure out a way to make a module never touch disk for pipelining purposes.
- The password_hash filter supports all parameters of passlib. This allows users to provide a rounds parameter. (https://github.com/ansible/ansible/issues/15326)
- action plugins strictly accept valid parameters and report invalid parameters
- allow user to customize default ansible-console prompt/msg default color
- aws_caller_facts - The module now outputs the "account_alias" as well
- aws_rds - Add new inventory plugin for RDS instances and clusters to match behavior in the ec2 inventory script.
- command module - Add support for check mode when passing creates or removes arguments. (https://github.com/ansible/ansible/pull/40428)
- dnf - group removal does not work if group was installed with Ansible because of dnf upstream bug https://bugzilla.redhat.com/show_bug.cgi?id=1620324
- ec2_group - Add diff mode support with and without check mode. This feature is preview and may change when a common framework is adopted for AWS modules.
- elasticsearch_plugin - Add the possibility to use the elasticsearch_plugin installation batch mode to install plugins with advanced privileges without user interaction.
- gather_subset - removed deprecated functionality for using comma separated list with gather_subset (https://github.com/ansible/ansible/pull/44320)
- get_url - implement [expend checksum format to <algorithm>:(<checksum>|<url>)] (https://github.com/ansible/ansible/issues/27617)
- import_tasks - Do not allow import_tasks to transition to dynamic if the file is missing (https://github.com/ansible/ansible/issues/44822)
- lineinfile - add warning when using an empty regexp (https://github.com/ansible/ansible/issues/29443)
- onepassword/onepassword_raw - accept subdomain and vault_password to allow Ansible to unlock 1Password vaults
- password_hash is not restricted to the subset provided by crypt.crypt (https://github.com/ansible/ansible/issues/17266)
- passwordstore - Add backup option when overwriting password (off by default)
- puppet - Add support for --debug, --verbose, --summarize https://github.com/ansible/ansible/issues/37986
@ -84,6 +93,8 @@ Minor Changes
- win_chocolatey - Removed the need to manually escape double quotes in the proxy username and password
- win_chocolatey - Will no longer upgrade Chocolatey in check mode
- win_chocolatey - set the rc return value to always be returned, default to 0 https://github.com/ansible/ansible/issues/41758
- win_disk_image - return a list of mount paths with the return value ``mount_paths``, this will always be a list and contain all mount points in an image
- win_psexec - Added the ``session`` option to specify a session to start the process in
- winrm - change the _reset() method to use reset() that is part of ConnectionBase
Deprecated Features
@ -91,6 +102,7 @@ Deprecated Features
- Modules will no longer be able to rely on the __file__ attribute pointing to a real file. If your third party module is using __file__ for something it should be changed before 2.8. See the 2.7 porting guide for more information.
- The `skippy`, `full_skip`, `actionable`, and `stderr` callback plugins have been deprecated in favor of config options that influence the behavior of the `default` callback plugin (https://github.com/ansible/ansible/pull/41058)
- win_disk_image - the return value ``mount_path`` is deprecated and will be removed in 2.11, this can be accessed through ``mount_paths[0]`` instead.
Removed Features (previously deprecated)
----------------------------------------
@ -105,18 +117,31 @@ Bugfixes
- **Security Fix** - Some connection exceptions would cause no_log specified on a task to be ignored. If this happened, the task information, including any private information could have been displayed to stdout and (if enabled, not the default) logged to a log file specified in ansible.cfg's log_path. Additionally, sites which redirected stdout from ansible runs to a log file may have stored that private information onto disk that way as well. (https://github.com/ansible/ansible/pull/41414)
- **Security Fix** - avoid loading host/group vars from cwd when not specifying a playbook or playbook base dir
- **Security Fix** - avoid using ansible.cfg in a world writable dir.
- Add ambiguous command check as the error message is not persistent on nexus devices (https://github.com/ansible/ansible/pull/45337).
- Add argspec to aws_application_scaling_policy module to handle metric specifications, scaling cooldowns, and target values. https://github.com/ansible/ansible/pull/45235
- Additional checks ensure that there is always a result of hashing passwords in the password_hash filter and vars_prompt, otherwise an error is returned. Some modules (like user module) interprets None as no password at all, which can be dangerous if the password given above is passed directly into those modules.
- Allow arbitrary ``log_driver`` for docker_container (https://github.com/ansible/ansible/pull/33579).
- Avoids deprecated functionality of passlib with newer library versions.
- Changed the admin_users config option to not include "admin" by default as admin is frequently used for a non-privileged account (https://github.com/ansible/ansible/pull/41164)
- Fix alt linux detection/matching
- Fix an atomic_move error that is 'true', but misleading. Now we show all 3 files involved and clarify what happened.
- Fix ec2_group support for multi-account and peered VPC security groups. Reported in https://github.com/ansible/ansible/issue/44788 and fixed in https://github.com/ansible/ansible/pull/45296
- Fix ecs_taskdefinition handling of changed role_arn. If the task role in a ECS task definition changes ansible should create a new revsion of the task definition. https://github.com/ansible/ansible/pull/45317
- Fix glob path of rc.d Some distribtuions like SUSE has the rc%.d directories under /etc/init.d
- Fix health check parameter handling in elb_target_group per https://github.com/ansible/ansible/issues/43244 about health_check_port. Fixed in https://github.com/ansible/ansible/pull/45314
- Fix lambda_policy updates when principal is an account number. Backport of https://github.com/ansible/ansible/pull/44871
- Fix lxd module to be idempotent when the given configuration for the lxd container has not changed (https://github.com/ansible/ansible/pull/38166)
- Fix python2.6 `nothing to repeat` nxos terminal plugin bug (https://github.com/ansible/ansible/pull/45271).
- Fix s3_lifecycle module backwards compatibility without providing prefix. Blank prefixes regression was introduced in boto3 rewrite. https://github.com/ansible/ansible/pull/45318
- Fix terminal plugin regex nxos, iosxr (https://github.com/ansible/ansible/pull/45135).
- Fix the mount module's handling of swap entries in fstab (https://github.com/ansible/ansible/pull/42837)
- Fixed an issue where ``ansible_facts.pkg_mgr`` would incorrectly set to ``zypper`` on Debian/Ubuntu systems that happened to have the command installed.
- Fixed runtime module to be able to handle syslog_facility properly when python systemd module installed in a target system. (https://github.com/ansible/ansible/pull/41078)
- Grafana dashboard module compatible with grafana 5 (https://github.com/ansible/ansible/pull/41249)
- On Python2, loading config values from environment variables could lead to a traceback if there were nonascii characters present. Converted them to text strings so that no traceback will occur (https://github.com/ansible/ansible/pull/43468)
- Remove spurious `changed=True` returns when ec2_group module is used with numeric ports. https://github.com/ansible/ansible/pull/45240
- Support key names that contain spaces in ec2_metadata_facts module. https://github.com/ansible/ansible/pull/45313
- The docker_* modules respect the DOCKER_* environment variables again (https://github.com/ansible/ansible/pull/42641).
- The fix for `CVE-2018-10875 <https://access.redhat.com/security/cve/cve-2018-10875>`__ prints out a warning message about skipping a config file from a world writable current working directory. However, if the user explicitly specifies that the config file should be used via the ANSIBLE_CONFIG environment variable then Ansible would honor that but still print out the warning message. This has been fixed so that Ansible honors the user's explicit wishes and does not print a warning message in that circumstance.
- The fix for `CVE-2018-10875 <https://access.redhat.com/security/cve/cve-2018-10875>`__ prints out a warning message about skipping a config file from a world writable current working directory. However, if the user is in a world writable current working directory which does not contain a config file, it should not print a warning message. This release fixes that extaneous warning.
- The ssh connection plugin was categorizing all 255 exit statuses as an ssh error but modules can return exit code 255 as well. The connection plugin has now been changed to know that certain instances of exit code 255 are not ssh-related. (https://github.com/ansible/ansible/pull/41716)
@ -127,21 +152,43 @@ Bugfixes
- authorized_key now have an option for following symlinks, default behaviour (False) can be changed by setting follow True/False
- basic.py - catch ValueError in case a FIPS enabled platform raises this exception - https://github.com/ansible/ansible/issues/44447
- become runas - changed runas process so it does not create a temporary file on the disk during execution
- cloudfront_distribution - replace call to nonexistent method 'validate_distribution_id_from_caller_reference' with 'validate_distribution_from_caller_reference' and set the distribution_id variable to the distribution's 'Id' key.
- corrected and clarified 'user' option deprecation in systemd module in favor of 'scope' option.
- delegate_to - ensure if we get a non-Task object in _get_delegated_vars, we return early (https://github.com/ansible/ansible/pull/44934)
- docker_container: fixing ``working_dir`` idempotency problem (https://github.com/ansible/ansible/pull/42857)
- docker_container: makes unit parsing for memory sizes more consistent, and fixes idempotency problem when ``kernel_memory`` is set (see https://github.com/ansible/ansible/pull/16748 and https://github.com/ansible/ansible/issues/42692)
- ec2_group - Sanitize the ingress and egress rules before operating on them by flattening any lists within lists describing the target CIDR(s) into a list of strings. Prior to Ansible 2.6 the ec2_group module accepted a list of strings, a list of lists, or a combination of strings and lists within a list. https://github.com/ansible/ansible/pull/45594
- ec2_vpc_route_table - check the origin before replacing routes. Routes with the origin 'EnableVgwRoutePropagation' may not be replaced.
- elasticsearch_plugin - Improve error messages and show stderr of elasticsearch commands
- elb_application_lb - Fix a dangerous behavior of deleting an ELB if state was omitted from the task. Now state defaults to 'present', which is typical throughout AWS modules.
- elb_target_group - cast target ports to integers before making API calls after the key 'Targets' is in params.
- file module - The touch subcommand had its diff output broken during the 2.6.x development cycle. The patch to fix that broke check mode. This is now fixed (https://github.com/ansible/ansible/issues/42111)
- file module - The touch subcommand had its diff output broken during the 2.6.x development cycle. This is now fixed (https://github.com/ansible/ansible/issues/41755)
- fix async for the aws_s3 module by adding async support to the action plugin (https://github.com/ansible/ansible/pull/40826)
- fix azure storage blob cannot create blob container in non-public azure cloud environment. (https://github.com/ansible/ansible/issues/35223)
- fix azure_rm_autoscale module can use dict to identify target (https://github.com/ansible/ansible/pull/45477)
- fix decrypting vault files for the aws_s3 module (https://github.com/ansible/ansible/pull/39634)
- fix default SSL version for docker modules https://github.com/ansible/ansible/issues/42897
- fix for the bundled selectors module (used in the ssh and local connection plugins) when a syscall is restarted after being interrupted by a signal (https://github.com/ansible/ansible/issues/41630)
- fix mail module for python 3.7.0 (https://github.com/ansible/ansible/pull/44552)
- fix nxos_facts indefinite hang for text based output (https://github.com/ansible/ansible/pull/45845).
- fix the enable_snat parameter that is only supposed to be used by an user with the right policies. https://github.com/ansible/ansible/pull/44418
- fix the remote tmp folder permissions issue when becoming a non admin user - https://github.com/ansible/ansible/issues/41340, https://github.com/ansible/ansible/issues/42117
- fixed typo in config that prevented keys matching
- fixes docker_container check and debug mode (https://github.com/ansible/ansible/pull/42380)
- flatten filter - use better method of type checking allowing flattening of mutable and non-mutable sequences (https://github.com/ansible/ansible/pull/44331)
- gce_net - Fix sorting of allowed ports (https://github.com/ansible/ansible/pull/41567)
- get_url - Don't re-download files unnecessarily when force=no (https://github.com/ansible/ansible/issues/45491)
- get_url - fix the bug that get_url does not change mode when checksum matches (https://github.com/ansible/ansible/issues/29614)
- get_url - support remote checksum files with paths specified with leading dots (`./path/to/file`)
- get_url / uri - Use custom rfc2822 date format function instead of locale specific strftime (https://github.com/ansible/ansible/issues/44857)
- improved block docs
- improves docker_container idempotency (https://github.com/ansible/ansible/pull/44808)
- include - Change order of where the new block is inserted with apply so that apply args are not applied to the include also (https://github.com/ansible/ansible/pull/44912)
- includes - ensure we do not double register handlers from includes to prevent exception (https://github.com/ansible/ansible/issues/44848)
- inventory - When using an inventory directory, ensure extension comparison uses text types (https://github.com/ansible/ansible/pull/42475)
- loop - Ensure that a loop with a when condition that evaluates to false and delegate_to, will short circuit if the loop references an undefined variable. This matches the behavior in the same scenario without delegate_to (https://github.com/ansible/ansible/issues/45189)
- loop - Ensure we only cache the loop when the task had a loop and delegate_to was templated (https://github.com/ansible/ansible/issues/44874)
- made irc module python3 compatible https://github.com/ansible/ansible/issues/42256
- nclu - no longer runs net on empty lines in templates (https://github.com/ansible/ansible/pull/43024)
- nicer message when we are missing interpreter
@ -151,6 +198,7 @@ Bugfixes
- plugins/inventory/openstack.py - Do not create group with empty name if region is not set
- preseve delegation info on nolog https://github.com/ansible/ansible/issues/42344
- remove ambiguity when it comes to 'the source'
- script inventory plugin - Don't pass file_name to DataLoader.load, which will prevent misleading error messages (https://github.com/ansible/ansible/issues/34164)
- urls - Only assume GET method if data is empty, otherwise POST
- user - Strip trailing comments in /etc/default/passwd (https://github.com/ansible/ansible/pull/43931)
- user - fix bug that resulted in module always reporting a change when specifiying the home directory on FreeBSD (https://github.com/ansible/ansible/issues/42484)
@ -164,15 +212,20 @@ Bugfixes
- win_domain - fixes typo in one of the AD cmdlets https://github.com/ansible/ansible/issues/41536
- win_domain_computer - fixed deletion of computer active directory object that have dependent objects (https://github.com/ansible/ansible/pull/44500)
- win_domain_controller - ensure the Netlogon service is up and running after promoting host to controller - https://github.com/ansible/ansible/issues/39235
- win_group_membership - fix intermittent issue where it failed to convert the ADSI object to the .NET object after using it once
- win_iis_webapppool - redirect some module output to null so Ansible can read the output JSON https://github.com/ansible/ansible/issues/40874
- win_lineinfile - changed `-Path` to `-LiteralPath` so that square brackes in the path are interpreted literally - https://github.com/ansible/ansible/issues/44508
- win_psexec - changed code to not escape the command option when building the args - https://github.com/ansible/ansible/issues/43839
- win_reboot - fix for handling an already scheduled reboot and other minor log formatting issues
- win_reboot - fix issue when overridding connection timeout hung the post reboot uptime check - https://github.com/ansible/ansible/issues/42185 https://github.com/ansible/ansible/issues/42294
- win_reboot - handle post reboots when running test_command - https://github.com/ansible/ansible/issues/41713
- win_say - fix syntax error in module and get tests working
- win_security_policy - allows an empty string to reset a policy value https://github.com/ansible/ansible/issues/40869
- win_updates - Fixed issue where running win_updates on async fails without any error
- win_updates - fixed module return value is lost in error in some cases (https://github.com/ansible/ansible/pull/42647)
- win_uri: Fix support for JSON output when charset is set
- win_user - Use LogonUser to validate the password as it does not rely on SMB/RPC to be available https://github.com/ansible/ansible/issues/24884
- win_wait_for - fix issue where timeout doesn't wait unless state=drained - https://github.com/ansible/ansible/issues/43446
- winrm - ensure pexpect is set to not echo the input on a failure and have a manual sanity check afterwards https://github.com/ansible/ansible/issues/41865
- winrm - running async with become on a Server 2008 or 2008 R2 host will now work
@ -199,10 +252,16 @@ Inventory
Lookup
~~~~~~
- cpm_metering - Get Power and Current data from WTI OOB/Combo and PDU devices
- cpm_status - Get status and parameters from WTI OOB and PDU devices.
- grafana_dashboard - list or search grafana dashboards
- nios_next_network - Return the next available network range for a network-container
Strategy
~~~~~~~~
- host_pinned - Executes tasks on each host without interruption
New Modules
-----------
@ -214,6 +273,8 @@ amazon
- aws_eks_cluster - Manage Elastic Kubernetes Service Clusters
- cloudformation_stack_set - Manage groups of CloudFormation stacks
- elb_target_facts - Gathers which target groups a target is associated with.
- rds_instance - Manage RDS instances
azure
^^^^^
@ -221,6 +282,9 @@ azure
- azure_rm_appgateway - Manage Application Gateway instance.
- azure_rm_appserviceplan - Manage App Service Plan
- azure_rm_appserviceplan_facts - Get azure app service plan facts.
- azure_rm_autoscale - Manage Azure autoscale setting.
- azure_rm_autoscale_facts - Get Azure Auto Scale Setting facts.
- azure_rm_containerregistry_facts - Get Azure Container Registry facts.
- azure_rm_mysqldatabase_facts - Get Azure MySQL Database facts.
- azure_rm_mysqlserver_facts - Get Azure MySQL Server facts.
- azure_rm_postgresqldatabase_facts - Get Azure PostgreSQL Database facts.
@ -228,8 +292,14 @@ azure
- azure_rm_route - Manage Azure route resource.
- azure_rm_routetable - Manage Azure route table resource.
- azure_rm_routetable_facts - Get route table facts.
- azure_rm_sqlfirewallrule - Manage Firewall Rule instance.
- azure_rm_trafficmanagerendpoint - Manage Azure Traffic Manager endpoint.
- azure_rm_trafficmanagerendpoint_facts - Get Azure Traffic Manager endpoint facts
- azure_rm_trafficmanagerprofile - Manage Azure Traffic Manager profile.
- azure_rm_trafficmanagerprofile_facts - Get Azure Traffic Manager profile facts
- azure_rm_virtualmachine_facts - Get virtual machine facts.
- azure_rm_webapp - Manage Web App instance.
- azure_rm_webapp_facts - Get azure web app facts.
cloudstack
^^^^^^^^^^
@ -263,6 +333,7 @@ google
- gcp_compute_instance_template_facts - Gather facts for GCP InstanceTemplate
- gcp_compute_network_facts - Gather facts for GCP Network
- gcp_compute_route_facts - Gather facts for GCP Route
- gcp_compute_router - Creates a GCP Router
- gcp_compute_router_facts - Gather facts for GCP Router
- gcp_compute_ssl_certificate_facts - Gather facts for GCP SslCertificate
- gcp_compute_ssl_policy - Creates a GCP SslPolicy
@ -278,6 +349,16 @@ google
- gcp_compute_url_map_facts - Gather facts for GCP UrlMap
- gcp_compute_vpn_tunnel - Creates a GCP VpnTunnel
- gcp_compute_vpn_tunnel_facts - Gather facts for GCP VpnTunnel
- gcp_spanner_database - Creates a GCP Database
- gcp_spanner_instance - Creates a GCP Instance
- gcp_sql_database - Creates a GCP Database
- gcp_sql_instance - Creates a GCP Instance
- gcp_sql_user - Creates a GCP User
online
^^^^^^
- online_user_facts - Gather facts about Online user.
openstack
^^^^^^^^^
@ -312,6 +393,7 @@ vmware
- vmware_guest_custom_attribute_defs - Manage custom attributes definitions for virtual machine from VMWare
- vmware_guest_custom_attributes - Manage custom attributes from VMWare for the given virtual machine
- vmware_guest_move - Moves virtual machines in vCenter
- vmware_host_ntp_facts - Gathers facts about NTP configuration on an ESXi host
- vmware_host_ssl_facts - Gather facts of ESXi host system about SSL
- vmware_local_role_facts - Gather facts about local roles on an ESXi host
@ -356,6 +438,8 @@ acme
Identity
~~~~~~~~
- onepassword_facts - Fetch facts from 1Password items
ipa
^^^
@ -429,6 +513,18 @@ f5
- bigip_tunnel - Manage tunnels on a BIG-IP
- bigiq_utility_license_assignment - Manage utility license assignment on BIG-IPs from a BIG-IQ
fortimanager
^^^^^^^^^^^^
- fmgr_provisioning - Provision devices via FortiMananger
ftd
^^^
- ftd_configuration - Manages configuration on Cisco FTD devices over REST API
- ftd_file_download - Downloads files from Cisco FTD devices over HTTP(S)
- ftd_file_upload - Uploads files to Cisco FTD devices over HTTP(S)
meraki
^^^^^^
@ -457,6 +553,11 @@ onyx
- onyx_igmp - Configures IGMP globl parameters
opx
^^^
- opx_cps - CPS operations on networking device running Openswitch (OPX)
panos
^^^^^
@ -485,11 +586,18 @@ cobbler
^^^^^^^
- cobbler_sync - Sync Cobbler
- cobbler_system - Manage system ojects in Cobbler
- cobbler_system - Manage system objects in Cobbler
cpm
^^^
- cpm_user - Get various status and parameters from WTI OOB and PDU devices
redfish
^^^^^^^
- redfish_command - Manages Out-Of-Band controllers using Redfish APIs
- redfish_config - Manages Out-Of-Band controllers using Redfish APIs
- redfish_facts - Manages Out-Of-Band controllers using Redfish APIs
ucs
@ -511,24 +619,60 @@ emc
ibm
^^^
- ibm_sa_host - Adds hosts to or removes them from IBM Spectrum Accelerate storage systems.
- ibm_sa_pool - Handles pools on an IBM Spectrum Accelerate storage array.
- ibm_sa_vol - Handle volumes on an IBM Spectrum Accelerate storage array
netapp
^^^^^^
- na_elementsw_access_group - NetApp Element Software Manage Access Groups
- na_elementsw_account - NetApp Element Software Manage Accounts
- na_elementsw_admin_users - NetApp Element Software Manage Admin Users
- na_elementsw_backup - NetApp Element Software Create Backups
- na_elementsw_check_connections - NetApp Element Software Check connectivity to MVIP and SVIP.
- na_elementsw_cluster - NetApp Element Software Create Cluster
- na_elementsw_cluster_pair - NetApp Element Software Manage Cluster Pair
- na_elementsw_drive - NetApp Element Software Manage Node Drives
- na_elementsw_ldap - NetApp Element Software Manage ldap admin users
- na_elementsw_network_interfaces - NetApp Element Software Configure Node Network Interfaces
- na_elementsw_node - NetApp Element Software Node Operation
- na_elementsw_snapshot - NetApp Element Software Manage Snapshots
- na_elementsw_snapshot_restore - NetApp Element Software Restore Snapshot
- na_elementsw_snapshot_schedule - NetApp Element Software Snapshot Schedules
- na_elementsw_vlan - NetApp Element Software Manage VLAN
- na_elementsw_volume - NetApp Element Software Manage Volumes
- na_elementsw_volume_clone - NetApp Element Software Create Volume Clone
- na_elementsw_volume_pair - NetApp Element Software Volume Pair
- na_ontap_cg_snapshot - Create consistency group snapshot
- na_ontap_autosupport - NetApp ONTAP manage Autosupport
- na_ontap_cg_snapshot - NetApp ONTAP manage consistency group snapshot
- na_ontap_cluster_peer - NetApp ONTAP Manage Cluster peering
- na_ontap_command - NetApp ONTAP Run any cli command
- na_ontap_disks - NetApp ONTAP Assign disks to nodes
- na_ontap_dns - NetApp ONTAP Create, delete, modify DNS servers.
- na_ontap_fcp - NetApp ONTAP Start, Stop and Enable FCP services.
- na_ontap_firewall_policy - NetApp ONTAP Manage a firewall policy
- na_ontap_gather_facts - NetApp information gatherer
- na_ontap_motd - Setup motd on cDOT
- na_ontap_node - NetApp ONTAP Rename a node.
- na_ontap_snapmirror - NetApp ONTAP Manage SnapMirror
- na_ontap_software_update - NetApp ONTAP Update software
- na_ontap_svm_options - NetApp ONTAP Modify Options
- na_ontap_vserver_peer - Manage NetApp Vserver peering
- na_ontap_software_update - NetApp ONTAP Update Software
- na_ontap_svm_options - NetApp ONTAP Modify SVM Options
- na_ontap_vserver_peer - NetApp ONTAP Vserver peering
- netapp_e_alerts - NetApp E-Series manage email notification settings
- netapp_e_asup - NetApp E-Series manage auto-support settings
- netapp_e_auditlog - NetApp E-Series manage audit-log configuration
- netapp_e_global - NetApp E-Series manage global settings configuration
- netapp_e_iscsi_interface - NetApp E-Series manage iSCSI interface configuration
- netapp_e_iscsi_target - NetApp E-Series manage iSCSI target configuration
- netapp_e_ldap - NetApp E-Series manage LDAP integration to use for authentication
- netapp_e_mgmt_interface - NetApp E-Series management interface configuration
- netapp_e_syslog - NetApp E-Series manage syslog settings
purestorage
^^^^^^^^^^^
- purefb_facts - Collect facts from Pure Storage FlashBlade
System
~~~~~~
@ -543,7 +687,10 @@ Web Infrastructure
ansible_tower
^^^^^^^^^^^^^
- tower_credential_type - Create, update, or destroy custom Ansible Tower credential type.
- tower_inventory_source - create, update, or destroy Ansible Tower inventory source.
- tower_settings - Modify Ansible Tower settings.
- tower_workflow_template - create, update, or destroy Ansible Tower workflow template.
Windows
~~~~~~~
@ -551,3 +698,5 @@ Windows
- win_chocolatey_config - Manages Chocolatey config settings
- win_chocolatey_feature - Manages Chocolatey features
- win_chocolatey_source - Manages Chocolatey sources
- win_wait_for_process - Waits for a process to exist or not exist before continuing.
- win_xml - Add XML fragment to an XML parent

View File

@ -0,0 +1,5 @@
bugfixes:
- "docker_container: makes unit parsing for memory sizes more consistent, and
fixes idempotency problem when ``kernel_memory`` is set (see
https://github.com/ansible/ansible/pull/16748 and
https://github.com/ansible/ansible/issues/42692)"

View File

@ -0,0 +1,2 @@
bugfixes:
- "Allow arbitrary ``log_driver`` for docker_container (https://github.com/ansible/ansible/pull/33579)."

View File

@ -0,0 +1,2 @@
bugfixes:
- "fixes docker_container check and debug mode (https://github.com/ansible/ansible/pull/42380)"

View File

@ -0,0 +1,2 @@
bugfixes:
- "The docker_* modules respect the DOCKER_* environment variables again (https://github.com/ansible/ansible/pull/42641)."

View File

@ -0,0 +1,2 @@
bugfixes:
- "docker_container: fixing ``working_dir`` idempotency problem (https://github.com/ansible/ansible/pull/42857)"

View File

@ -0,0 +1,2 @@
bugfixes:
- "improves docker_container idempotency (https://github.com/ansible/ansible/pull/44808)"

View File

@ -0,0 +1,2 @@
bugfixes:
- get_url - support remote checksum files with paths specified with leading dots (`./path/to/file`)

View File

@ -0,0 +1,22 @@
bugfixes:
- Fix lambda_policy updates when principal is an account number. Backport of
https://github.com/ansible/ansible/pull/44871
- Support key names that contain spaces in ec2_metadata_facts module.
https://github.com/ansible/ansible/pull/45313
- Fix ec2_group support for multi-account and peered VPC security groups.
Reported in https://github.com/ansible/ansible/issue/44788 and fixed in
https://github.com/ansible/ansible/pull/45296
- Fix s3_lifecycle module backwards compatibility without providing prefix.
Blank prefixes regression was introduced in boto3 rewrite.
https://github.com/ansible/ansible/pull/45318
- Fix ecs_taskdefinition handling of changed role_arn. If the task role in a
ECS task definition changes ansible should create a new revsion of the task
definition. https://github.com/ansible/ansible/pull/45317
- Fix health check parameter handling in elb_target_group per
https://github.com/ansible/ansible/issues/43244 about health_check_port.
Fixed in https://github.com/ansible/ansible/pull/45314
- Remove spurious `changed=True` returns when ec2_group module is used with
numeric ports. https://github.com/ansible/ansible/pull/45240
- Add argspec to aws_application_scaling_policy module to handle metric
specifications, scaling cooldowns, and target values.
https://github.com/ansible/ansible/pull/45235

View File

@ -0,0 +1,5 @@
---
bugfixes:
- cloudfront_distribution - replace call to nonexistent method 'validate_distribution_id_from_caller_reference'
with 'validate_distribution_from_caller_reference' and set the distribution_id variable to the distribution's
'Id' key.

View File

@ -0,0 +1,3 @@
---
bugfixes:
- fix azure storage blob cannot create blob container in non-public azure cloud environment. (https://github.com/ansible/ansible/issues/35223)

View File

@ -0,0 +1,3 @@
---
bugfixes:
- fix azure_rm_autoscale module can use dict to identify target (https://github.com/ansible/ansible/pull/45477)

View File

@ -0,0 +1,2 @@
bugfixes:
- fixed typo in config that prevented keys matching

View File

@ -0,0 +1,3 @@
---
minor_changes:
- "dnf - group removal does not work if group was installed with Ansible because of dnf upstream bug https://bugzilla.redhat.com/show_bug.cgi?id=1620324"

View File

@ -0,0 +1,6 @@
---
bugfixes:
- ec2_group - Sanitize the ingress and egress rules before operating on them by flattening any lists
within lists describing the target CIDR(s) into a list of strings. Prior to Ansible 2.6 the ec2_group
module accepted a list of strings, a list of lists, or a combination of strings and lists within a list.
https://github.com/ansible/ansible/pull/45594

View File

@ -0,0 +1,4 @@
---
bugfixes:
- ec2_vpc_route_table - check the origin before replacing routes.
Routes with the origin 'EnableVgwRoutePropagation' may not be replaced.

View File

@ -0,0 +1,3 @@
---
bugfixes:
- elb_target_group - cast target ports to integers before making API calls after the key 'Targets' is in params.

View File

@ -0,0 +1,2 @@
bugfixes:
- fix nxos_facts indefinite hang for text based output (https://github.com/ansible/ansible/pull/45845).

View File

@ -0,0 +1,2 @@
bugfixes:
- get_url - Don't re-download files unnecessarily when force=no (https://github.com/ansible/ansible/issues/45491)

View File

@ -0,0 +1,4 @@
bugfixes:
- loop - Ensure that a loop with a when condition that evaluates to false and delegate_to, will short circuit if the
loop references an undefined variable. This matches the behavior in the same scenario without delegate_to
(https://github.com/ansible/ansible/issues/45189)

View File

@ -0,0 +1,2 @@
bugfixes:
- Add ambiguous command check as the error message is not persistent on nexus devices (https://github.com/ansible/ansible/pull/45337).

View File

@ -0,0 +1,2 @@
bugfixes:
- script inventory plugin - Don't pass file_name to DataLoader.load, which will prevent misleading error messages (https://github.com/ansible/ansible/issues/34164)

View File

@ -0,0 +1,2 @@
bugfixes:
- corrected and clarified 'user' option deprecation in systemd module in favor of 'scope' option.

View File

@ -0,0 +1,3 @@
bugfixes:
- Fix terminal plugin regex nxos, iosxr (https://github.com/ansible/ansible/pull/45135).
- Fix python2.6 `nothing to repeat` nxos terminal plugin bug (https://github.com/ansible/ansible/pull/45271).

View File

@ -1,4 +1,4 @@
---
release_summary: |
| Release Date: 2018-10-04
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__
| Release Date: 2018-10-04
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,4 @@
---
release_summary: |
| Release Date: 2018-08-31
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,3 @@
release_summary: |
| Release Date: 2018-08-31
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,4 @@
---
release_summary: |
| Release Date: 2018-09-06
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,3 @@
release_summary: |
| Release Date: 2018-09-13
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,3 @@
release_summary: |
| Release Date: 2018-09-20
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__

View File

@ -0,0 +1,8 @@
release_summary: |
| Release Date: 2018-09-27
| `Porting Guide <https://docs.ansible.com/ansible/devel/porting_guides.html>`__
bugfixes:
- Change the pypi metadata to specify that Python-2.7 or greater is needed on
the controller. This will prevent pip from installing or upgrading to Ansible-2.7
when run under Python-2.6. Python-2.6 users will get Ansible-2.6.x updates instead.

View File

@ -0,0 +1,3 @@
---
minor_changes:
- Fix timer in exponential backoff algorithm in vmware.py.

View File

@ -0,0 +1,2 @@
bugfixes:
- win_group_membership - fix intermittent issue where it failed to convert the ADSI object to the .NET object after using it once

View File

@ -0,0 +1,2 @@
bugfixes:
- win_say - fix syntax error in module and get tests working

View File

@ -21,9 +21,9 @@ servers_suffix = _servers
#
# By default, final JSON is built based on all available info in consul.
# Suffixes means that services groups will be added in addition to basic infromation. See servers_suffix for additional info
# Suffixes means that services groups will be added in addition to basic information. See servers_suffix for additional info
# There are cases when speed is preferable than having services groups
# False value will reduce script execution time dragtically.
# False value will reduce script execution time drastically.
#
suffixes = true
@ -45,7 +45,7 @@ kv_groups=ansible/groups
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
# based on the service availability
#
# !!!! if availability is true, suffixes also must be true. !!!!
#

View File

@ -187,16 +187,16 @@ DEFAULTS = {
'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,
'aws_access_key_id': '',
'aws_secret_access_key': '',
'aws_security_token': '',
'boto_profile': '',
'cache_max_age': '300',
'cache_path': '~/.ansible/tmp',
'destination_variable': 'public_dns_name',
'elasticache': 'True',
'eucalyptus': 'False',
'eucalyptus_host': None,
'eucalyptus_host': '',
'expand_csv_tags': 'False',
'group_by_ami_id': 'True',
'group_by_availability_zone': 'True',
@ -218,19 +218,19 @@ DEFAULTS = {
'group_by_tag_keys': 'True',
'group_by_tag_none': 'True',
'group_by_vpc_id': 'True',
'hostname_variable': None,
'iam_role': None,
'hostname_variable': '',
'iam_role': '',
'include_rds_clusters': 'False',
'nested_groups': 'False',
'pattern_exclude': None,
'pattern_include': None,
'pattern_exclude': '',
'pattern_include': '',
'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,
'route53_hostnames': '',
'stack_filters': 'False',
'vpc_destination_variable': 'ip_address'
}

View File

@ -6,7 +6,7 @@ clouds:
username: fb886a9b-c37b-442a-9be3-964bed961e04
password: fantastic-password1
rax:
cloud: rackspace
profile: rackspace
auth:
username: example
password: spectacular-password

View File

@ -156,7 +156,7 @@
<div class="DocSiteProduct-logoText">
Ansible
<div class="DocSiteProduct-CurrentVersion" align="right">
devel
2.7
</div>
</div>
</div>

View File

@ -1,24 +1,25 @@
.. _community_committer_guidelines:
Committers Guidelines (for people with commit rights to Ansible on GitHub)
``````````````````````````````````````````````````````````````````````````
*********************
Committers Guidelines
*********************
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 are the guidelines for people with commit privileges on the Ansible GitHub repository. Committers are essentially acting as members of the Ansible Core team, although not necessarily as employees 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.
That said, use the trust wisely.
That said, use the trust wisely.
If you abuse the trust and break components and builds, etc., the trust level falls and you may be asked not to commit or you may lose access to do so.
If you abuse the trust and break components and builds, etc., the trust level falls and you may be asked not to commit or you may lose your commit privileges.
Features, High Level Design, and Roadmap
Features, high-level design, and roadmap
========================================
As a core team member, you are an integral part of the team that develops the :ref:`roadmap <roadmaps>`. 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.
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
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:
@ -29,19 +30,19 @@ As a committer, you may already know this, but our workflow forms a lot of our t
* 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:
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 by making direct commits or 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
=============
* Core Committers: Fine to do PRs for most things, but we should have a timebox. Hanging PRs may merge on the judgement of these devs.
* Module Owners: Module Owners own specific modules and have indirect commit access via the current module PR mechanisms.
* Core committers: Fine to do PRs for most things, but we should have a timebox. Hanging PRs may merge on the judgement of these devs.
* :ref:`Module maintainers <maintainers>`: Module maintainers own specific modules and have indirect commit access via the current module PR mechanisms.
General Rules
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 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
@ -64,11 +65,12 @@ Individuals with direct commit access to ansible/ansible are entrusted with powe
- Consider scope, sometimes a fix can be generalized
- Keep it simple, then things are maintainable, debuggable and intelligible.
Committers are expected to continue to follow the same community and contribution guidelines followed by the rest of the Ansible community.
Committers are expected to continue to follow the same community and contribution guidelines followed by the rest of the Ansible community.
People
======
Individuals who've been asked to become a part of this group have generally been contributing in significant ways to the Ansible community for some time. Should they agree, they are requested to add their names and GitHub IDs to this file, in the section below, via a pull request. Doing so indicates that these individuals agree to act in the ways that their fellow committers trust that they will act.
+---------------------+----------------------+--------------------+----------------------+

View File

@ -11,7 +11,7 @@ Code of Conduct
Please read and understand the :ref:`code_of_conduct`.
Mailing List Information
Mailing list information
========================
Ansible has several mailing lists. Your first post to the mailing list will be moderated (to reduce spam), so please allow up to a day or so for your first post to appear.
@ -28,12 +28,12 @@ Ansible has several mailing lists. Your first post to the mailing list will be
To subscribe to a group from a non-Google account, you can send an email to the subscription address requesting the subscription. For example: `ansible-devel+subscribe@googlegroups.com`
IRC Channel
===========
IRC channels
============
Ansible has several IRC channels on Freenode (irc.freenode.net).
General Channels
General channels
----------------
- ``#ansible`` - For general use questions and support.
@ -41,8 +41,8 @@ General Channels
- ``#ansible-meeting`` - For public community meetings. We will generally announce these on one or more of the above mailing lists. See the `meeting schedule and agenda page <https://github.com/ansible/community/blob/master/meetings/README.md>`_
- ``#ansible-notices`` - Mostly bot output from things like GitHub, etc.
Working Group
-------------
Working groups
--------------
- ``#ansible-aws`` - For discussions on Amazon Web Services.
- ``#ansible-community`` - Channel for discussing Ansible Community related things.
@ -54,20 +54,20 @@ Working Group
- ``#ansible-windows`` - For discussions on Ansible & Windows.
Language specific channels
Language-specific channels
--------------------------
- ``#ansible-es`` - Channel for Spanish speaking Ansible community.
- ``#ansible-fr`` - Channel for French speaking Ansible community.
IRC Meetings
IRC meetings
------------
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>`_.
Tower Support Questions
Tower support questions
========================
Ansible `Tower <https://www.ansible.com/products/tower>`_ is a UI, Server, and REST endpoint for Ansible.

View File

@ -0,0 +1,7 @@
.. _contributor_license_agreement:
******************************
Contributors License Agreement
******************************
By contributing you agree that these contributions are your own (or approved by your employer) and you grant a full, complete, irrevocable copyright license to all users and developers of the project, present and future, pursuant to the license of the project.

View File

@ -1,7 +1,8 @@
.. _community_development_process:
*******************************
The Ansible Development Process
===============================
*******************************
.. contents:: Topics
@ -63,7 +64,7 @@ pull request to backport the change to a previous stable branch.
git cherry-pick -x [SHA_FROM_DEVEL]
#. Add a changelog entry for the change, and commit it.
#. Add a :ref:`changelog fragment <changelogs_how_to>` for the change, and commit it.
#. Push your feature branch to your fork on GitHub:

View File

@ -1,22 +1,23 @@
*************
GitHub Admins
=============
*************
.. contents:: Topics
GitHub Admins have more permissions on GitHub than normal contributors. There are
GitHub Admins have more permissions on GitHub than normal contributors or even committers. There are
a few responsibilities that come with that increased power.
Add and Remove Committers
-------------------------
Adding and removing committers
==============================
The Ansible Team will periodically review who is actively contributing to Ansible to grant or revoke
contributors' ability to commit on their own. GitHub Admins are the people who have the power to
actually manage the GitHub permissions.
Change Branch Permissions for Release
-------------------------------------
Changing branch permissions for releases
========================================
When we make releases we make people go through a :ref:`release_managers` to push commits to that
branch. The GitHub admins are responsible for setting the branch so only the Release Manager can

View File

@ -1,5 +1,6 @@
How To Help
===========
***************
How can I help?
***************
.. contents:: Topics
@ -8,7 +9,7 @@ Thanks for being interested in helping the Ansible project!
There are many ways to help the Ansible project...but first, please read and understand the :ref:`code_of_conduct`.
Become a power user
-------------------
===================
A great way to help the Ansible project is to become a power user:
@ -21,21 +22,21 @@ A great way to help the Ansible project is to become a power user:
When you become a power user, your ability and opportunities to help the Ansible project in other ways will multiply quickly.
Ask and answer questions online
-------------------------------
===============================
There are many forums online where Ansible users ask and answer questions. Reach out and communicate with your fellow Ansible users.
You can find the official :ref:`Ansible communication channels <communication>`.
Participate in your local meetup
--------------------------------
================================
There are Ansible meetups `all over the world <https://www.meetup.com/topics/ansible/>`_. Join your local meetup. Attend regularly. Ask good questions. Volunteer to give a presentation about how you use Ansible.
If there isn't a meetup near you, we'll be happy to help you `start one <https://www.ansible.com/community/events/ansible-meetups>`_.
File and verify issues
----------------------
======================
All software has bugs, and Ansible is no exception. When you find a bug, you can help tremendously by :ref:`telling us about it <reporting_bugs_and_features>`.
@ -43,31 +44,31 @@ All software has bugs, and Ansible is no exception. When you find a bug, you can
If you should discover that the bug you're trying to file already exists in an issue, you can help by verifying the behavior of the reported bug with a comment in that issue, or by reporting any additional information.
Review and submit pull requests
-------------------------------
===============================
As you become more familiar with how Ansible works, you may be able to fix issues or develop new features yourself. If you think you've got a solution to a bug you've found in Ansible, or if you've got a new feature that you've written and would like to share with millions of Ansible users, read all about the :ref:`Ansible development process <community_development_process>` to learn how to get your code accepted into Ansible.
Another good way to help is to review pull requests that other Ansible users have submitted. The Ansible community keeps a full list of `open pull requests by file <https://ansible.sivel.net/pr/byfile.html>`_, so if there's a particular module or plug-in that particularly interests you, you can easily keep track of all the relevant new pull requests and provide testing or feedback.
Become a module maintainer
--------------------------
==========================
Once you've learned about the development process and have contributed code to a particular module, we encourage you to become a maintainer of that module. There are hundreds of different modules in Ansible, and the vast majority of them are written and maintained entirely by members of the Ansible community.
To learn more about the responsibilities of being an Ansible module maintainer, please read our :ref:`module maintainer guidelines <maintainers>`.
Join a working group
--------------------
====================
Working groups are a way for Ansible community members to self-organize around particular topics of interest. We have working groups around various topics. To join or create a working group, please read the `Ansible working group guidelines <https://github.com/ansible/community/blob/master/WORKING-GROUPS.md>`_.
Teach Ansible to others
-----------------------
=======================
We're working on a standardized Ansible workshop called `Lightbulb <https://github.com/ansible/lightbulb>`_ that can provide a good hands-on introduction to Ansible usage and concepts.
Social media
------------
============
If you like Ansible and just want to spread the good word, feel free to share on your social media platform of choice, and let us know by using ``@ansible`` or ``#ansible``. We'll be looking for you.

View File

@ -10,19 +10,24 @@ The purpose of this guide is to teach you everything you need to know about bein
To get started, please read and understand the :ref:`code_of_conduct`, and then select one of the following topics.
.. toctree::
:maxdepth: 2
code_of_conduct
development_process
reporting_bugs_and_features
how_can_I_help
reporting_bugs_and_features
communication
development_process
contributor_license_agreement
triage_process
other_tools_and_programs
../dev_guide/style_guide/index
.. toctree::
:caption: Guidelines for specific types of contributors
:maxdepth: 2
committer_guidelines
maintainers
release_managers
communication
other_tools_and_programs
github_admins

View File

@ -14,7 +14,7 @@ In addition to the information below, module maintainers should be familiar with
* Documentation on :ref:`module development <developing_modules>`
Maintainer Responsibilities
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."
@ -27,10 +27,10 @@ Finally, following the `ansible-devel <https://groups.google.com/forum/#!forum/a
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.
Pull Requests, Issues, and Workflow
Pull requests, issues, and workflow
===================================
Pull Requests
Pull requests
-------------
Module pull requests are located in the `main Ansible repository <https://github.com/ansible/ansible/pulls>`_.
@ -44,7 +44,7 @@ Issues for modules, including bug reports, documentation bug reports, and featur
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
PR workflow
-----------
Automated routing of pull requests is handled by a tool called `Ansibot <https://github.com/ansible/ansibullbot>`_.
@ -58,8 +58,8 @@ Maintainers (BOTMETA.yml)
The full list of maintainers is located in `BOTMETA.yml <https://github.com/ansible/ansible/blob/devel/.github/BOTMETA.yml>`_.
Changing Maintainership
-----------------------
Adding and removing maintainers
===============================
Communities change over time, and no one maintains a module forever. If you'd like to propose an additional maintainer for your module, please submit a PR to ``BOTMETA.yml`` with the GitHub username of the new maintainer.

View File

@ -1,3 +1,5 @@
.. _other_tools_and_programs:
########################
Other Tools And Programs
########################

View File

@ -1,23 +1,22 @@
.. _release_managers:
Release Managers
================
**************************
Release manager guidelines
**************************
.. contents:: Topics
The release manager's purpose is to ensure a smooth release. To achieve that goal, they need to
coordinate between:
* Developers with Commit privileges on the `Ansible github repository <https://github.com/ansible/ansible/>`_
* Developers with commit privileges on the `Ansible GitHub repository <https://github.com/ansible/ansible/>`_
* Contributors without commit privileges
* The community
* Ansible documentation team
* Ansible Tower team
Pre-releases: What and Why
--------------------------
Pre-releases: what and why
==========================
Pre-releases exist to draw testers. They give people who don't feel comfortable running from source
control a means to get an early version of the code to test and give us feedback. To ensure we get
@ -35,18 +34,18 @@ back those changes to give people time to test between. People cannot test what
we have to get those tarballs out there even if people feel they have to install more frequently.
What is Beta?
~~~~~~~~~~~~~
Beta releases
-------------
In a Beta release, we know there are still bugs. We will continue to accept fixes for these.
In a beta release, we know there are still bugs. We will continue to accept fixes for these.
Although we review these fixes, sometimes they can be invasive or potentially destabilize other
areas of the code.
During the beta, we will no longer accept feature submissions.
What is a Release Candidate?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Release candidates
------------------
In a release candidate, we've fixed all known blockers. Any remaining bugfixes are
ones that we are willing to leave out of the release. At this point we need user testing to
@ -74,8 +73,8 @@ The last RC should be as close to the final as possible. The following things ma
(like the Tower Team) which would want to test the code.
Release Process
===============
Ansible release process
=======================
The release process is kept in a `separate document
<https://docs.google.com/document/d/10EWLkMesi9s_CK_GmbZlE_ZLhuQr6TBrdMLKo5dnMAI/edit#heading=h.ooo3izcel3cz>`_

View File

@ -6,7 +6,7 @@ Reporting Bugs And Requesting Features
.. contents:: Topics
Reporting A Bug
Reporting a bug
===============
Ansible practices responsible disclosure - if this is a security related bug, email `security@ansible.com <mailto:security@ansible.com>`_ instead of filing a ticket or posting to the Google Group and you will receive a prompt response.

View File

@ -28,7 +28,7 @@ import os
sys.path.insert(0, os.path.join('ansible', 'lib'))
sys.path.append(os.path.abspath(os.path.join('..', '_extensions')))
VERSION = '2.6'
VERSION = '2.7'
AUTHOR = 'Ansible, Inc'

View File

@ -0,0 +1,149 @@
.. _debugging:
*****************
Debugging modules
*****************
Debugging (local)
=================
To break into a module running on ``localhost`` and step through with the debugger:
- Set a breakpoint in the module: ``import pdb; pdb.set_trace()``
- Run the module on the local machine: ``$ python -m pdb ./my_new_test_module.py ./args.json``
Debugging (remote)
==================
To debug a module running on a remote target (i.e. not ``localhost``):
#. On your controller machine (running Ansible) set ``ANSIBLE_KEEP_REMOTE_FILES=1`` to tell Ansible to retain the modules it sends to the remote machine instead of removing them after you playbook runs.
#. Run your playbook targeting the remote machine and specify ``-vvvv`` (verbose) to display the remote location Ansible is using for the modules (among many other things).
#. Take note of the directory Ansible used to store modules on the remote host. This directory is usually under the home directory of your ``ansible_ssh_user``, in the form ``~/.ansible/tmp/ansible-tmp-...``.
#. SSH into the remote target after the playbook runs.
#. Navigate to the directory you noted in step 3.
#. Extract the module you want to debug from the zipped file that Ansible sent to the remote host: ``$ python my_test_module.py explode``. Ansible will expand the module into ``./debug-dir``. You can optionally run the zipped file by specifying ``python my_test_module.py``.
#. Navigate to the debug directory: ``$ cd debug-dir``.
#. Modify or set a breakpoint in ``ansible_module_my_test_module.py``.
#. Ensure that the unzipped module is executable: ``$ chmod 755 ansible_module_my_test_module.py``.
#. Run the unzipped module directly, passing the ``args`` file that contains the params that were originally passed: ``$ ./ansible_module_my_test_module.py args``. This approach is good for reproducing behavior as well as modifying the parameters for debugging.
.. _debugging_ansiblemodule_based_modules:
Debugging AnsibleModule-based modules
=====================================
.. tip::
If you're using the :file:`hacking/test-module` script then most of this
is taken care of for you. If you need to do some debugging of the module
on the remote machine that the module will actually run on or when the
module is used in a playbook then you may need to use this information
instead of relying on test-module.
Starting with Ansible 2.1, AnsibleModule-based modules are put together as
a zip file consisting of the module file and the various python module
boilerplate inside of a wrapper script instead of as a single file with all of
the code concatenated together. Without some help, this can be harder to
debug as the file needs to be extracted from the wrapper in order to see
what's actually going on in the module. Luckily the wrapper script provides
some helper methods to do just that.
If you are using Ansible with the :envvar:`ANSIBLE_KEEP_REMOTE_FILES`
environment variables to keep the remote module file, here's a sample of how
your debugging session will start:
.. code-block:: shell-session
$ ANSIBLE_KEEP_REMOTE_FILES=1 ansible localhost -m ping -a 'data=debugging_session' -vvv
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: badger
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" )'
<127.0.0.1> PUT /var/tmp/tmpjdbJ1w TO /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping
<127.0.0.1> EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping'
localhost | SUCCESS => {
"changed": false,
"invocation": {
"module_args": {
"data": "debugging_session"
},
"module_name": "ping"
},
"ping": "debugging_session"
}
Setting :envvar:`ANSIBLE_KEEP_REMOTE_FILES` to ``1`` tells Ansible to keep the
remote module files instead of deleting them after the module finishes
executing. Giving Ansible the ``-vvv`` option makes Ansible more verbose.
That way it prints the file name of the temporary module file for you to see.
If you want to examine the wrapper file you can. It will show a small python
script with a large, base64 encoded string. The string contains the module
that is going to be executed. Run the wrapper's explode command to turn the
string into some python files that you can work with:
.. code-block:: shell-session
$ python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping explode
Module expanded into:
/home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/debug_dir
When you look into the debug_dir you'll see a directory structure like this::
├── ansible_module_ping.py
├── args
└── ansible
├── __init__.py
└── module_utils
├── basic.py
└── __init__.py
* :file:`ansible_module_ping.py` is the code for the module itself. The name
is based on the name of the module with a prefix so that we don't clash with
any other python module names. You can modify this code to see what effect
it would have on your module.
* The :file:`args` file contains a JSON string. The string is a dictionary
containing the module arguments and other variables that Ansible passes into
the module to change its behaviour. If you want to modify the parameters
that are passed to the module, this is the file to do it in.
* The :file:`ansible` directory contains code from
:mod:`ansible.module_utils` that is used by the module. Ansible includes
files for any :`module:`ansible.module_utils` imports in the module but not
any files from any other module. So if your module uses
:mod:`ansible.module_utils.url` Ansible will include it for you, but if
your module includes :mod:`requests` then you'll have to make sure that
the python requests library is installed on the system before running the
module. You can modify files in this directory if you suspect that the
module is having a problem in some of this boilerplate code rather than in
the module code you have written.
Once you edit the code or arguments in the exploded tree you need some way to
run it. There's a separate wrapper subcommand for this:
.. code-block:: shell-session
$ python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping execute
{"invocation": {"module_args": {"data": "debugging_session"}}, "changed": false, "ping": "debugging_session"}
This subcommand takes care of setting the PYTHONPATH to use the exploded
:file:`debug_dir/ansible/module_utils` directory and invoking the script using
the arguments in the :file:`args` file. You can continue to run it like this
until you understand the problem. Then you can copy it back into your real
module file and test that the real module works via :command:`ansible` or
:command:`ansible-playbook`.
.. note::
The wrapper provides one more subcommand, ``excommunicate``. This
subcommand is very similar to ``execute`` in that it invokes the exploded
module on the arguments in the :file:`args`. The way it does this is
different, however. ``excommunicate`` imports the :func:`main`
function from the module and then calls that. This makes excommunicate
execute the module in the wrapper's process. This may be useful for
running the module under some graphical debuggers but it is very different
from the way the module is executed by Ansible itself. Some modules may
not work with ``excommunicate`` or may behave differently than when used
with Ansible normally. Those are not bugs in the module; they're
limitations of ``excommunicate``. Use at your own risk.

View File

@ -1,18 +1,19 @@
.. _developing_api:
**********
Python API
==========
**********
.. contents:: Topics
.. note:: This API is intended for internal Ansible use. Ansible may make changes to this API at any time that could break backward compatibility with older versions of the API. Because of this, external use is not supported by Ansible.
.. note:: This API is intended for internal Ansible use. Ansible may make changes to this API at any time that could break backward compatibility with older versions of the API. Because of this, external use is not supported by Ansible.
There are several ways to use Ansible from an API perspective. You can use
the Ansible Python API to control nodes, you can extend Ansible to respond to various Python events, you can
write plugins, and you can plug in inventory data from external data sources. This document
gives a basic overview and examples of the Ansible execution and playbook API.
If you would like to use Ansible programmatically from a language other than Python, trigger events asynchronously,
If you would like to use Ansible programmatically from a language other than Python, trigger events asynchronously,
or have access control and logging demands, please see the `Ansible Tower documentation <https://docs.ansible.com/ansible-tower/>`_.
.. note:: Because Ansible relies on forking processes, this API is not thread safe.
@ -20,7 +21,7 @@ or have access control and logging demands, please see the `Ansible Tower docume
.. _python_api_example:
Python API example
------------------
==================
This example is a simple demonstration that shows how to minimally run a couple of tasks::
@ -100,7 +101,7 @@ This example is a simple demonstration that shows how to minimally run a couple
# we always need to cleanup child procs and the structres we use to communicate with them
if tqm is not None:
tqm.cleanup()
# Remove ansible tmpdir
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
@ -122,4 +123,3 @@ command line tools (``lib/ansible/cli/``) is `available on Github <https://githu
Mailing list for development topics
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -1,5 +1,6 @@
**********************************
Developing the Ansible Core Engine
==================================
**********************************
Although many of the pieces of the Ansible Core Engine are plugins that can be
swapped out via playbook directives or configuration, there are still pieces
@ -21,4 +22,3 @@ those pieces work together.
The development mailing list
`irc.freenode.net <http://irc.freenode.net>`_
#ansible-devel IRC chat channel

View File

@ -1,7 +1,8 @@
.. _developing_inventory:
Developing Dynamic Inventory
============================
****************************
Developing dynamic inventory
****************************
.. contents:: Topics
:local:
@ -11,9 +12,9 @@ including cloud sources, using the supplied :ref:`inventory plugins <inventory_p
If the source you want is not currently covered by existing plugins, you can create your own as with any other plugin type.
In previous versions you had to create a script or program that can output JSON in the correct format when invoked with the proper arguments.
You can still use and write inventory scripts, as we ensured backwards compatiblity via the :ref:`script inventory plugin <script_inventory>`
You can still use and write inventory scripts, as we ensured backwards compatibility via the :ref:`script inventory plugin <script_inventory>`
and there is no restriction on the programming language used.
If you choose to write a script, however, you will need to implement some features youself.
If you choose to write a script, however, you will need to implement some features yourself.
i.e caching, configuration management, dynamic variable and group composition, etc.
While with :ref:`inventory plugins <inventory_plugins>` you can leverage the Ansible codebase to add these common features.
@ -21,7 +22,7 @@ While with :ref:`inventory plugins <inventory_plugins>` you can leverage the Ans
.. _inventory_sources:
Inventory sources
-----------------
=================
Inventory sources are strings (i.e what you pass to ``-i`` in the command line),
they can represent a path to a file/script or just be the raw data for the plugin to use.
@ -44,11 +45,10 @@ Here are some plugins and the type of source they use:
+--------------------------------------------+--------------------------------------+
.. _developing_inventory_inventory_plugins:
Inventory Plugins
-----------------
Inventory plugins
=================
Like most plugin types (except modules) they must be developed in Python, since they execute on the controller they should match the same requirements :ref:`control_machine_requirements`.
@ -61,8 +61,8 @@ When using the 'persistent' cache, inventory plugins can also use the configured
.. _developing_an_inventory_plugin:
Developing an Inventory Plugin
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Developing an inventory plugin
------------------------------
The first thing you want to do is use the base class:
@ -91,7 +91,7 @@ For the bulk of the work in the plugin, We mostly want to deal with 2 methods ``
.. _inventory_plugin_verify_file:
verify_file
"""""""""""
^^^^^^^^^^^
This method is used by Ansible to make a quick determination if the inventory source is usable by the plugin. It does not need to be 100% accurate as there might be overlap in what plugins can handle and Ansible will try the enabled plugins (in order) by default.
@ -128,7 +128,7 @@ This method is just to expedite the inventory process and avoid uneccessary pars
.. _inventory_plugin_parse:
parse
"""""
^^^^^
This method does the bulk of the work in the plugin.
@ -194,8 +194,8 @@ For examples on how to implement an inventory plug in, see the source code here:
.. _inventory_source_common_format:
inventory source common format
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Inventory source common format
------------------------------
To simplify development, most plugins use a mostly standard configuration file as the inventory source, YAML based and with just one required field ``plugin`` which should contain the name of the plugin that is expected to consume the file.
Depending on other common features used, other fields might be needed, but each plugin can also add it's own custom options as needed.
@ -204,7 +204,7 @@ For example, if you use the integrated caching, ``cache_plugin``, ``cache_timeou
.. _inventory_development_auto:
The 'auto' plugin
^^^^^^^^^^^^^^^^^
-----------------
Since Ansible 2.5, we include the :ref:`auto inventory plugin <auto_inventory>` enabled by default, which itself just loads other plugins if they use the common YAML configuration format that specifies a ``plugin`` field that matches an inventory plugin name, this makes it easier to use your plugin w/o having to update configurations.
@ -212,8 +212,8 @@ Since Ansible 2.5, we include the :ref:`auto inventory plugin <auto_inventory>`
.. _inventory_scripts:
.. _developing_inventory_scripts:
Inventory Scripts
-----------------
Inventory scripts
=================
Even though we now have inventory plugins, we still support inventory scripts, not only for backwards compatibility but also to allow users to leverage other programming languages.
@ -221,7 +221,7 @@ Even though we now have inventory plugins, we still support inventory scripts, n
.. _inventory_script_conventions:
Inventory script conventions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
----------------------------
Inventory scripts must accept the ``--list`` and ``--host <hostname>`` arguments, other arguments are allowed but Ansible will not use them.
They might still be useful for when executing the scripts directly.
@ -264,8 +264,8 @@ Printing variables is optional. If the script does not do this, it should print
.. _inventory_script_tuning:
Tuning the External Inventory Script
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Tuning the external inventory script
------------------------------------
.. versionadded:: 1.3

View File

@ -0,0 +1,95 @@
.. _using_local_modules_and_plugins:
.. _developing_locally:
**********************************
Adding modules and plugins locally
**********************************
.. contents:: Topics
:local:
The easiest, quickest, and most popular way to extend Ansible is to copy or write a module or a plugin for local use. You can store local modules and plugins on your Ansible control node for use within your team or organization. You can also share a local plugin or module by embedding it in a role and publishing it on Ansible Galaxy. If you've been using roles off Galaxy, you may have been using local modules and plugins without even realizing it. If you're using a local module or plugin that already exists, this page is all you need.
Extending Ansible with local modules and plugins offers lots of shortcuts:
* You can copy other people's modules and plugins.
* If you're writing a new module, you can choose any programming language you like.
* You don't have to clone the main Ansible repo.
* You don't have to open a pull request.
* You don't have to add tests (though we recommend that you do!).
To save a local module or plugin so Ansible can find and use it, drop the module or plugin in the correct "magic" directory. For local modules, use the name of the file as the module name: for example, if the module file is ``~/.ansible/plugins/modules/local_users.py``, use ``local_users`` as the module name.
.. _modules_vs_plugins:
Modules and plugins: what's the difference?
===========================================
If you're looking to add local functionality to Ansible, you may be wondering whether you need a module or a plugin. Here's a quick overview of the differences:
* Modules are reusable, standalone scripts that can be used by the Ansible API, the :command:`ansible` command, or the :command:`ansible-playbook` command. Modules provide a defined interface, accepting arguments and returning information to Ansible by printing a JSON string to stdout before exiting.
* Plugins are shared code that can be used by any module. They provide abilities like cacheing information or copying files that are useful for many modules.
.. _local_modules:
Adding a module locally
=======================
Ansible automatically loads all executable files found in certain directories as modules, so you can create or add a local module in any of these locations:
* any directory added to the ``ANSIBLE_LIBRARY`` environment variable (``$ANSIBLE_LIBRARY`` takes a colon-separated list like ``$PATH``)
* ``~/.ansible/plugins/modules/``
* ``/usr/share/ansible/plugins/modules/``
Once you save your module file in one of these locations, Ansible will load it and you can use it in any local task, playbook, or role.
To confirm that ``my_custom_module`` is available:
* type ``ansible-doc -t module my_custom_module``. You should see the documentation for that module.
To use a local module only in certain playbooks:
* store it in a sub-directory called ``library`` in the directory that contains the playbook(s)
To use a local module only in a single role:
* store it in a sub-directory called ``library`` within that role
.. _distributing_plugins:
.. _local_plugins:
Adding a plugin locally
=======================
Ansible loads plugins automatically too, loading each type of plugin separately from a directory named for the type of plugin. Here's the full list of plugin directory names:
* action_plugins*
* cache_plugins
* callback_plugins
* connection_plugins
* filter_plugins*
* inventory_plugins
* lookup_plugins
* shell_plugins
* strategy_plugins
* test_plugins*
* vars_plugins
You can create or add a local plugin in any of these locations:
* any directory added to the relevant ``ANSIBLE_plugin_type_PLUGINS`` environment variable (these variables, such as ``$ANSIBLE_INVENTORY_PLUGINS`` and ``$ANSIBLE_VARS_PLUGINS`` take colon-separated lists like ``$PATH``)
* the directory named for the correct ``plugin_type`` within ``~/.ansible/plugins/`` - for example, ``~/.ansible/plugins/callback_plugins``
* the directory named for the correct ``plugin_type`` within ``/usr/share/ansible/plugins/`` - for example, ``/usr/share/ansible/plugins/plugin_type/action_plugins``
Once your plugin file is in one of these locations, Ansible will load it and you can use it in a any local module, task, playbook, or role.
To confirm that ``plugins/plugin_type/my_custom_plugin`` is available:
* type ``ansible-doc -t <plugin_type> my_custom_lookup_plugin``. For example, ``ansible-doc -t lookup my_custom_lookup_plugin``. You should see the documentation for that plugin. This works for all plugin types except the ones marked with ``*`` in the list above - see :ref:`ansible-doc` for more details.
To use your local plugin only in certain playbooks:
* store it in a sub-directory for the correct ``plugin_type`` (for example, ``callback_plugins`` or ``inventory_plugins``) in the directory that contains the playbook(s)
To use your local plugin only in a single role:
* store it in a sub-directory for the correct ``plugin_type`` (for example, ``cache_plugins`` or ``strategy_plugins``) within that role
When shipped as part of a role, the plugin will be available as soon as the role is called in the play.

View File

@ -1,14 +1,17 @@
.. _appendix_module_utilities:
**************************
Appendix: Module Utilities
``````````````````````````
**************************
Ansible provides a number of module utilities that provide helper functions that you can use when developing your own modules. The `basic.py` module utility provides the main entry point for accessing the Ansible library, and all Ansible modules must, at minimum, import from basic.py::
Ansible provides a number of module utilities that provide helper functions that you can use when developing your own modules. The ``basic.py`` module utility provides the main entry point for accessing the Ansible library, and all Python Ansible modules must, at minimum, import ``AnsibleModule``::
from ansible.module_utils.basic import *
from ansible.module_utils.basic import AnsibleModule
The following is a list of module_utils files and a general description. The module utility source code lives in the `./lib/module_utils` directory under your main Ansible path - for more details on any specific module utility, please see the source code.
The following is a list of ``module_utils`` files and a general description. The module utility source code lives in the ``./lib/ansible/module_utils`` directory under your main Ansible path - for more details on any specific module utility, please see the source code.
.. include:: shared_snippets/licensing.txt
- api.py - Adds shared support for generic API modules.
- azure_rm_common.py - Definitions and utilities for Microsoft Azure Resource Manager template deployments.

View File

@ -1,110 +1,63 @@
.. _developing_modules:
Developing Modules
==================
.. contents:: Topics
.. _module_dev_welcome:
Welcome
```````
This section discusses how to develop, debug, review, and test modules.
Ansible modules are reusable, standalone scripts that can be used by the Ansible API,
or by the :command:`ansible` or :command:`ansible-playbook` programs. They
return information to ansible by printing a JSON string to stdout before
exiting. They take arguments in one of several ways which we'll go into
as we work through this tutorial.
See :ref:`all_modules` for a list of existing modules.
Modules can be written in any language and are found in the path specified
by :envvar:`ANSIBLE_LIBRARY` or the ``--module-path`` command line option or
in the :envvar:`library section of the Ansible configuration file <ANSIBLE_LIBRARY>`.
.. _module_dev_should_you:
Should You Develop A Module?
````````````````````````````
Before diving into the work of creating a new module, you should think about whether you actually *should*
develop a module. Ask the following questions:
****************************
Should you develop a module?
****************************
Developing Ansible modules is easy, but often it isn't necessary. Before you start writing a new module, ask:
1. Does a similar module already exist?
There are a lot of existing modules available, you should check out the list of existing modules at :ref:`modules`
An existing module may cover the functionality you want. Ansible Core includes thousands of modules. Search our :ref:`list of existing modules <all_modules>` to see if there's a module that does what you need.
2. Has someone already worked on a similar Pull Request?
2. Does a Pull Request already exist?
It's possible that someone has already started developing a similar PR. There are a few ways to find open module Pull Requests:
An existing Pull Request may cover the functionality you want. If someone else has already started developing a similar module, you can review and test it. There are a few ways to find open module Pull Requests:
* `GitHub new module PRs <https://github.com/ansible/ansible/labels/new_module>`_
* `All updates to modules <https://github.com/ansible/ansible/labels/module>`_
* `New module PRs listed by directory <https://ansible.sivel.net/pr/byfile.html>`_ search for `lib/ansible/modules/`
If you find an existing PR that looks like it addresses the issue you are trying to solve, please provide feedback on the PR - this will speed up getting the PR merged.
If you find an existing PR that looks like it addresses your needs, please provide feedback on the PR. Community feedback speeds up the review and merge process.
3. Should you use or develop an action plugin instead?
Action plugins get run on the master instead of on the target. For modules like file/copy/template, some of the work needs to be done on the master before the module executes on the target. Action plugins execute first on the master and can then execute the normal module on the target if necessary.
For more information about action plugins, read the :ref:`action plugins documentation <developing_plugins>`.
An action plugin may be the best way to get the functionality you want. Action plugins run on the control node instead of on the managed node, and their functionality is available to all modules. For more information about developing plugins, read the :ref:`developing plugins page <developing_plugins>`.
4. Should you use a role instead?
Check out the :ref:`roles documentation<playbooks_reuse_roles>`.
A combination of existing modules may cover the functionality you want. You can write a role for this type of use case. Check out the :ref:`roles documentation<playbooks_reuse_roles>`.
5. Should you write multiple modules instead of one module?
The following guidelines will help you determine if your module attempts to do too much, and should likely be broken into several smaller modules.
The functionality you want may be too large for a single module. If you want to connect Ansible to a new cloud provider, database, or network platform, you may need to :ref:`develop a related group of modules<developing_modules_in_groups>`.
* Modules should have a concise and well defined functionality. Basically, follow the UNIX philosophy of doing one thing well.
* Modules should not require that a user know all the underlying options of an api/tool to be used. For instance, if the legal values for a required module parameter cannot be documented, that's a sign that the module would be rejected.
* Modules should not require that a user know all the underlying options of an API/tool to be used. For instance, if the legal values for a required module parameter cannot be documented, that's a sign that the module would be rejected.
* Modules should typically encompass much of the logic for interacting with a resource. A lightweight wrapper around an API that does not contain much logic would likely cause users to offload too much logic into a playbook, and for this reason the module would be rejected. Instead try creating multiple modules for interacting with smaller individual pieces of the API.
If your use case isn't covered by an existing module, an open PR, an action plugin, or a role, and you don't need to create multiple modules, then you're ready to start developing a new module. Choose from the topics below for next steps:
.. _developing_modules_all:
How To Develop A Module
```````````````````````
The following topics will discuss how to develop and work with modules:
:doc:`developing_program_flow_modules`
A description of Ansible's module architecture.
:doc:`developing_modules_general`
A general overview of how to develop, debug, and test modules.
:doc:`developing_modules_general_windows`
A general overview of how to develop, debug and test Windows modules.
:doc:`developing_modules_documenting`
How to include in-line documentation in your module.
:doc:`developing_modules_best_practices`
Best practices, recommendations, and things to avoid.
:doc:`developing_modules_checklist`
Checklist for contributing your module to Ansible.
:doc:`testing`
Developing unit and integration tests.
:ref:`developing_python_3`
Adding Python 3 support to modules (all new modules must be Python-2.6 and Python-3.5 compatible).
:doc:`developing_modules_in_groups`
A guide for partners wanting to submit multiple modules.
* I want to :ref:`get started on a new module <developing_modules_general>`.
* I want to review :ref:`tips and conventions for developing good modules <developing_modules_best_practices>`.
* I want to :ref:`write a Windows module <developing_modules_general_windows>`.
* I want :ref:`an overview of Ansible's architecture <developing_program_flow_modules>`.
* I want to :ref:`document my module <developing_modules_documenting>`.
* I want to :ref:`contribute my module back to Ansible Core <developing_modules_checklist>`.
* I want to :ref:`add unit and integration tests to my module <developing_testing>`.
* I want to :ref:`add Python 3 support to my module <developing_python_3>`.
* I want to :ref:`write multiple modules <developing_modules_in_groups>`.
.. seealso::
:ref:`all_modules`
Learn about available modules
:doc:`developing_plugins`
Learn about developing plugins
:doc:`developing_api`
Learn about the Python API for playbook and task execution
`GitHub modules directory <https://github.com/ansible/ansible/tree/devel/lib/ansible/modules>`_
Browse module source code
`Mailing List <https://groups.google.com/group/ansible-devel>`_
Development mailing list
`irc.freenode.net <http://irc.freenode.net>`_
#ansible IRC chat channel

View File

@ -1,197 +1,143 @@
.. _developing_modules_best_practices:
.. _module_dev_conventions:
Conventions, Best Practices, and Pitfalls
`````````````````````````````````````````
*******************************
Conventions, tips, and pitfalls
*******************************
As a reminder from the example code above, here are some basic conventions
and guidelines:
.. contents:: Topics
:local:
* If the module is addressing an object, the parameter for that object should be called 'name' whenever possible, or accept 'name' as an alias.
As you design and develop modules, follow these basic conventions and tips for clean, usable code:
* If you have a company module that returns facts specific to your installations, a good name for this module is `site_facts`.
Scoping your module(s)
======================
* Modules accepting boolean status should generally accept 'yes', 'no', 'true', 'false', or anything else a user may likely throw at them. The AnsibleModule common code supports this with "type='bool'".
Especially if you want to contribute your module(s) back to Ansible Core, make sure each module includes enough logic and functionality, but not too much. If you're finding these guidelines tricky, consider :ref:`whether you really need to write a module <module_dev_should_you>` at all.
* Include a minimum of dependencies if possible. If there are dependencies, document them at the top of the module file, and have the module raise JSON error messages when the import fails.
* Each module should have a concise and well-defined functionality. Basically, follow the UNIX philosophy of doing one thing well.
* Do not add ``list`` or ``info`` state options to an existing module - create a new ``_facts`` module.
* Modules should not require that a user know all the underlying options of an API/tool to be used. For instance, if the legal values for a required module parameter cannot be documented, the module does not belong in Ansible Core.
* Modules should encompass much of the logic for interacting with a resource. A lightweight wrapper around a complex API forces users to offload too much logic into their playbooks. If you want to connect Ansible to a complex API, :ref:`create multiple modules <developing_modules_in_groups>` that interact with smaller individual pieces of the API.
* Avoid creating a module that does the work of other modules; this leads to code duplication and divergence, and makes things less uniform, unpredictable and harder to maintain. Modules should be the building blocks. If you are asking 'how can I have a module execute other modules' ... you want to write a role.
* Modules must be self-contained in one file to be auto-transferred by ansible.
Designing module interfaces
===========================
* If packaging modules in an RPM, they only need to be installed on the control machine and should be dropped into /usr/share/ansible. This is entirely optional and up to you.
* If your module is addressing an object, the parameter for that object should be called ``name`` whenever possible, or accept ``name`` as an alias.
* Modules accepting boolean status should accept ``yes``, ``no``, ``true``, ``false``, or anything else a user may likely throw at them. The AnsibleModule common code supports this with ``type='bool'``.
* Avoid ``action``/``command``, they are imperative and not declarative, there are other ways to express the same thing.
* Modules must output valid JSON only. The top level return type must be a hash (dictionary) although they can be nested. Lists or simple scalar values are not supported, though they can be trivially contained inside a dictionary.
General guidelines & tips
=========================
* In the event of failure, a key of 'failed' should be included, along with a string explanation in 'msg'. Modules that raise tracebacks (stacktraces) are generally considered 'poor' modules, though Ansible can deal with these returns and will automatically convert anything unparseable into a failed result. If you are using the AnsibleModule common Python code, the 'failed' element will be included for you automatically when you call 'fail_json'.
* Each module should be self-contained in one file, so it can be be auto-transferred by Ansible.
* Always use the ``hacking/test-module`` script when developing modules - it will warn you about common pitfalls.
* If you have a local module that returns facts specific to your installations, a good name for this module is ``site_facts``.
* Eliminate or minimize dependencies. If your module has dependencies, document them at the top of the module file and raise JSON error messages when dependency import fails.
* Don't write to files directly; use a temporary file and then use the ``atomic_move`` function from ``ansible.module_utils.basic`` to move the updated temporary file into place. This prevents data corruption and ensures that the correct context for the file is kept.
* Avoid creating caches. Ansible is designed without a central server or authority, so you cannot guarantee it will not run with different permissions, options or locations. If you need a central authority, have it on top of Ansible (for example, using bastion/cm/ci server or tower); do not try to build it into modules.
* If you package your module(s) in an RPM, install the modules on the control machine in ``/usr/share/ansible``. Packaging modules in RPMs is optional.
* Return codes from modules are used if 'failed' is missing, 0=success and non-zero=failure.
Python tips
===========
* As results from many hosts will be aggregated at once, modules should return only relevant output. Returning the entire contents of a log file is generally bad form.
* When fetching URLs, use ``fetch_url`` or ``open_url`` from ``ansible.module_utils.urls``. Do not use ``urllib2``, which does not natively verify TLS certificates and so is insecure for https.
* Include a ``main`` function that wraps the normal execution.
* Call your :func:`main` from a conditional so you can import it into unit tests - for example:
* Modules should have a concise and well defined functionality. Basically, follow the UNIX philosophy of doing one thing well.
.. code-block:: python
* Modules should not require that a user know all the underlying options of an api/tool to be used. For instance, if the legal values for a required module parameter cannot be documented, that's a sign that the module would be rejected.
if __name__ == '__main__':
main()
* Modules should typically encompass much of the logic for interacting with a resource. A lightweight wrapper around an API that does not contain much logic would likely cause users to offload too much logic into a playbook, and for this reason the module would be rejected. Instead try creating multiple modules for interacting with smaller individual pieces of the API.
.. _shared_code:
.. _debugging_ansiblemodule_based_modules:
Importing and using shared code
===============================
Debugging AnsibleModule-based modules
`````````````````````````````````````
* Use shared code whenever possible - don't reinvent the wheel. Ansible offers the ``AnsibleModule`` common Python code, plus :ref:`utilities <appendix_module_utilities>` for many common use cases and patterns.
* Import ``ansible.module_utils`` code in the same place as you import other libraries.
* Do NOT use wildcards (*) for importing other python modules; instead, list the function(s) you are importing (for example, ``from some.other_python_module.basic import otherFunction``).
* Import custom packages in ``try``/``except`` and handle them with ``fail_json()`` in ``main()``. For example:
.. tip::
.. code-block:: python
If you're using the :file:`hacking/test-module` script then most of this
is taken care of for you. If you need to do some debugging of the module
on the remote machine that the module will actually run on or when the
module is used in a playbook then you may need to use this information
instead of relying on test-module.
try:
import foo
HAS_LIB=True
except:
HAS_LIB=False
Starting with Ansible-2.1.0, AnsibleModule-based modules are put together as
a zip file consisting of the module file and the various python module
boilerplate inside of a wrapper script instead of as a single file with all of
the code concatenated together. Without some help, this can be harder to
debug as the file needs to be extracted from the wrapper in order to see
what's actually going on in the module. Luckily the wrapper script provides
some helper methods to do just that.
Then in main(), just after the argspec, do
If you are using Ansible with the :envvar:`ANSIBLE_KEEP_REMOTE_FILES`
environment variables to keep the remote module file, here's a sample of how
your debugging session will start:
.. code-block:: python
.. code-block:: shell-session
if not HAS_LIB:
module.fail_json(msg='The foo Python module is required')
$ ANSIBLE_KEEP_REMOTE_FILES=1 ansible localhost -m ping -a 'data=debugging_session' -vvv
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: badger
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" && echo "` echo $HOME/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595 `" )'
<127.0.0.1> PUT /var/tmp/tmpjdbJ1w TO /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping
<127.0.0.1> EXEC /bin/sh -c 'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping'
localhost | SUCCESS => {
"changed": false,
"invocation": {
"module_args": {
"data": "debugging_session"
},
"module_name": "ping"
},
"ping": "debugging_session"
}
And document the dependency in the ``requirements`` section of your module's :ref:`documentation_block`.
Setting :envvar:`ANSIBLE_KEEP_REMOTE_FILES` to ``1`` tells Ansible to keep the
remote module files instead of deleting them after the module finishes
executing. Giving Ansible the ``-vvv`` option makes Ansible more verbose.
That way it prints the file name of the temporary module file for you to see.
.. _module_failures:
If you want to examine the wrapper file you can. It will show a small python
script with a large, base64 encoded string. The string contains the module
that is going to be executed. Run the wrapper's explode command to turn the
string into some python files that you can work with:
Handling module failures
========================
.. code-block:: shell-session
When your module fails, help users understand what went wrong. If you are using the ``AnsibleModule`` common Python code, the ``failed`` element will be included for you automatically when you call ``fail_json``. For polite module failure behavior:
$ python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping explode
Module expanded into:
/home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/debug_dir
* Include a key of ``failed`` along with a string explanation in ``msg``. If you don't do this, Ansible will use standard return codes: 0=success and non-zero=failure.
* Don't raise a traceback (stacktrace). Ansible can deal with stacktraces and automatically converts anything unparseable into a failed result, but raising a stacktrace on module failure is not user-friendly.
* Do not use ``sys.exit()``. Use ``fail_json()`` from the module object.
When you look into the debug_dir you'll see a directory structure like this::
Handling exceptions (bugs) gracefully
=====================================
├── ansible_module_ping.py
├── args
└── ansible
├── __init__.py
└── module_utils
├── basic.py
└── __init__.py
* Validate upfront--fail fast and return useful and clear error messages.
* Use defensive programming--use a simple design for your module, handle errors gracefully, and avoid direct stacktraces.
* Fail predictably--if we must fail, do it in a way that is the most expected. Either mimic the underlying tool or the general way the system works.
* Give out a useful message on what you were doing and add exception messages to that.
* Avoid catchall exceptions, they are not very useful unless the underlying API gives very good error messages pertaining the attempted action.
* :file:`ansible_module_ping.py` is the code for the module itself. The name
is based on the name of the module with a prefix so that we don't clash with
any other python module names. You can modify this code to see what effect
it would have on your module.
.. _module_output:
* The :file:`args` file contains a JSON string. The string is a dictionary
containing the module arguments and other variables that Ansible passes into
the module to change its behaviour. If you want to modify the parameters
that are passed to the module, this is the file to do it in.
Creating correct and informative module output
==============================================
* The :file:`ansible` directory contains code from
:mod:`ansible.module_utils` that is used by the module. Ansible includes
files for any :`module:`ansible.module_utils` imports in the module but not
any files from any other module. So if your module uses
:mod:`ansible.module_utils.url` Ansible will include it for you, but if
your module includes :mod:`requests` then you'll have to make sure that
the python requests library is installed on the system before running the
module. You can modify files in this directory if you suspect that the
module is having a problem in some of this boilerplate code rather than in
the module code you have written.
Modules must output valid JSON only. Follow these guidelines for creating correct, useful module output:
Once you edit the code or arguments in the exploded tree you need some way to
run it. There's a separate wrapper subcommand for this:
* Make your top-level return type a hash (dictionary).
* Nest complex return values within the top-level hash.
* Incorporate any lists or simple scalar values within the top-level return hash.
* Do not send module output to standard error, because the system will merge standard out with standard error and prevent the JSON from parsing.
* Capture standard error and return it as a variable in the JSON on standard out. This is how the command module is implemented.
* Never do ``print("some status message")`` in a module, because it will not produce valid JSON output.
* Always return useful data, even when there is no change.
* Be consistent about returns (some modules are too random), unless it is detrimental to the state/action.
* Make returns reusable--most of the time you don't want to read it, but you do want to process it and re-purpose it.
* Return diff if in diff mode. This is not required for all modules, as it won't make sense for certain ones, but please include it when applicable.
* Enable your return values to be serialized as JSON with Python's standard `JSON encoder and decoder <https://docs.python.org/3/library/json.html>`_ library. Basic python types (strings, int, dicts, lists, etc) are serializable.
* Do not return an object via exit_json(). Instead, convert the fields you need from the object into the fields of a dictionary and return the dictionary.
* Results from many hosts will be aggregated at once, so your module should return only relevant output. Returning the entire contents of a log file is generally bad form.
.. code-block:: shell-session
If a module returns stderr or otherwise fails to produce valid JSON, the actual output will still be shown in Ansible, but the command will not succeed.
$ python /home/badger/.ansible/tmp/ansible-tmp-1461434734.35-235318071810595/ping execute
{"invocation": {"module_args": {"data": "debugging_session"}}, "changed": false, "ping": "debugging_session"}
.. _module_conventions:
This subcommand takes care of setting the PYTHONPATH to use the exploded
:file:`debug_dir/ansible/module_utils` directory and invoking the script using
the arguments in the :file:`args` file. You can continue to run it like this
until you understand the problem. Then you can copy it back into your real
module file and test that the real module works via :command:`ansible` or
:command:`ansible-playbook`.
Following Ansible conventions
=============================
.. note::
Ansible conventions offer a predictable user interface across all modules, playbooks, and roles. To follow Ansible conventions in your module development:
The wrapper provides one more subcommand, ``excommunicate``. This
subcommand is very similar to ``execute`` in that it invokes the exploded
module on the arguments in the :file:`args`. The way it does this is
different, however. ``excommunicate`` imports the :func:`main`
function from the module and then calls that. This makes excommunicate
execute the module in the wrapper's process. This may be useful for
running the module under some graphical debuggers but it is very different
from the way the module is executed by Ansible itself. Some modules may
not work with ``excommunicate`` or may behave differently than when used
with Ansible normally. Those are not bugs in the module; they're
limitations of ``excommunicate``. Use at your own risk.
Module Paths
````````````
If you are having trouble getting your module "found" by ansible, be
sure it is in the :envvar:`ANSIBLE_LIBRARY` environment variable.
If you have a fork of one of the ansible module projects, do something like this::
ANSIBLE_LIBRARY=~/ansible-modules-core
And this will make the items in your fork be loaded ahead of what ships with Ansible. Just be sure
to make sure you're not reporting bugs on versions from your fork!
To be safe, if you're working on a variant on something in Ansible's normal distribution, it's not
a bad idea to give it a new name while you are working on it, to be sure you know you're pulling
your version.
Common Pitfalls
```````````````
You should never do this in a module:
.. code-block:: python
print("some status message")
Because the output is supposed to be valid JSON.
Modules must not output anything on standard error, because the system will merge
standard out with standard error and prevent the JSON from parsing. Capturing standard
error and returning it as a variable in the JSON on standard out is fine, and is, in fact,
how the command module is implemented.
If a module returns stderr or otherwise fails to produce valid JSON, the actual output
will still be shown in Ansible, but the command will not succeed.
Don't write to files directly; use a temporary file and then use the `atomic_move` function from `ansible.module_utils.basic` to move the updated temporary file into place. This prevents data corruption and ensures that the correct context for the file is kept.
Avoid creating a module that does the work of other modules; this leads to code duplication and divergence, and makes things less uniform, unpredictable and harder to maintain. Modules should be the building blocks. Instead of creating a module that does the work of other modules, use Plays and Roles instead.
Avoid creating 'caches'. Ansible is designed without a central server or authority, so you cannot guarantee it will not run with different permissions, options or locations. If you need a central authority, have it on top of Ansible (for example, using bastion/cm/ci server or tower); do not try to build it into modules.
Always use the hacking/test-module script when developing modules and it will warn you about these kind of things.
* Use consistent names across modules (yes, we have many legacy deviations - don't make the problem worse!).
* Use consistent parameters (arguments) within your module(s).
* Normalize parameters with other modules - if Ansible and the API your module connects to use different names for the same parameter, add aliases to your parameters so the user can choose which names to use in tasks and playbooks.
* Return facts from ``*_facts`` modules in the ``ansible_facts`` field of the :ref:`result dictionary<common_return_values>` so other modules can access them.
* Implement ``check_mode`` in all ``*_facts`` modules. Playbooks which conditionalize based on fact information will only conditionalize correctly in ``check_mode`` if the facts are returned in ``check_mode``. Usually you can add ``check_mode=True`` when instantiating ``AnsibleModule``.
* Use module-specific environment variables. For example, if you use the helpers in ``module_utils.api`` for basic authentication with ``module_utils.urls.fetch_url()`` and you fall back on environment variables for default values, use a module-specific environment variable like :code:`API_<MODULENAME>_USERNAME` to avoid conflict between modules.
* Keep module options simple and focused - if you're loading a lot of choices/states on an existing option, consider adding a new, simple option instead.
* Keep options small when possible. Passing a large data structure to an option might save us a few tasks, but it adds a complex requirement that we cannot easily validate before passing on to the module.
* If you want to pass complex data to an option, write an expert module that allows this, along with several smaller modules that provide a more 'atomic' operation against the underlying APIs and services. Complex operations require complex data. Let the user choose whether to reflect that complexity in tasks and plays or in vars files.
* Implement declarative operations (not CRUD) so the user can ignore existing state and focus on final state. For example, use ``started/stopped``, ``present/absent``.
* Strive for a consistent final state (aka idempotency). If running your module twice in a row against the same system would result in two different states, see if you can redesign or rewrite to achieve consistent final state. If you can't, document the behavior and the reasons for it.
* Provide consistent return values within the standard Ansible return structure, even if NA/None are used for keys normally returned under other options.
* Follow additional guidelines that apply to families of modules if applicable. For example, AWS modules should follow `the Amazon guidelines <https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/GUIDELINES.md>`_

View File

@ -1,168 +1,37 @@
.. _developing_modules_checklist:
.. _module_contribution:
===================================
Contributing Your Module to Ansible
===================================
***********************************
Contributing your module to Ansible
***********************************
High-quality modules with minimal dependencies
can be included in Ansible, but modules (just due to the programming
preferences of the developers) will need to be implemented in Python and use
the AnsibleModule common code, and should generally use consistent arguments with the rest of
the program. Stop by the mailing list to inquire about requirements if you like, and submit
a github pull request to the `ansible <https://github.com/ansible/ansible>`_ project.
Included modules will ship with ansible, and also have a chance to be promoted to 'core' status, which
gives them slightly higher development priority (though they'll work in exactly the same way).
If you want to contribute a module to Ansible, you must meet our objective and subjective requirements. Modules accepted into the `main project repo <https://github.com/ansible/ansible>`_ ship with every Ansible installation. However, contributing to the main project isn't the only way to distribute a module - you can embed modules in roles on Galaxy or simply share copies of your module code for :ref:`local use <developing_locally>`.
.. formerly marked with _module_dev_testing:
Contributing to Ansible: objective requirements
===============================================
------------------------------
Contributing Modules Checklist
------------------------------
To contribute a module to Ansible, you must:
The following checklist items are important guidelines for people who want to contribute to the development of modules to Ansible on GitHub. Please read the guidelines before you submit your PR/proposal.
* write your module in either Python or Powershell for Windows
* use the ``AnsibleModule`` common code
* support Python 2.7 and Python 3.5 - if your module cannot support Python 2.7, explain the required minimum Python version and rationale in the requirements section in ``DOCUMENTATION``
* use proper :ref:`Python 3 syntax <developing_python_3>`
* follow `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_ Python style conventions - see :ref:`testing_pep8` for more information
* license your module under the GPL license (GPLv3 or later)
* understand the :ref:`license agreement <contributor_license_agreement>`, which applies to all contributions
* conform to Ansible's :ref:`formatting and documentation <developing_modules_documenting>` standards
* include comprehensive :ref:`tests <developing_testing>` for your module
* minimize module dependencies
* support :ref:`check_mode <check_mode_dry>` if possible
* The shebang must always be ``#!/usr/bin/python``. This allows ``ansible_python_interpreter`` to work
* Modules must be written to support Python 2.6. If this is not possible, required minimum Python version and rationale should be explained in the requirements section in ``DOCUMENTATION``. In Ansible-2.3 the minimum requirement for modules was Python-2.4.
* Modules must be written to use proper Python-3 syntax. At some point in the future we'll come up with rules for running on Python-3 but we're not there yet. See :doc:`developing_python_3` for help on how to do this.
* Modules must have a metadata section. For the vast majority of new modules,
the metadata should look exactly like this:
Please make sure your module meets these requirements before you submit your PR/proposal. If you have questions, reach out via `Ansible's IRC chat channel <http://irc.freenode.net>`_ or the `Ansible development mailing list <https://groups.google.com/group/ansible-devel>`_.
.. code-block:: python
Contributing to Ansible: subjective requirements
================================================
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'metadata_version': '1.1'}
Read the complete :ref:`module metadata specification <ansible_metadata_block>` for more information.
* Documentation: Make sure it exists
* Module documentation should briefly and accurately define what each module and option does, and how it works with others in the underlying system. Documentation should be written for broad audience--readable both by experts and non-experts. This documentation is not meant to teach a total novice, but it also should not be reserved for the Illuminati (hard balance).
* Descriptions should always start with a capital letter and end with a full stop. Consistency always helps.
* The `required` setting is only required when true, otherwise it is assumed to be false.
* If `required` is false/missing, `default` may be specified (assumed 'null' if missing). Ensure that the default parameter in docs matches default parameter in code.
* Documenting `default` is not needed for `required: true`.
* Remove unnecessary doc like `aliases: []` or `choices: []`.
* Do not use Boolean values in a choice list . For example, in the list `choices: ['no', 'verify', 'always]`, 'no' will be interpreted as a Boolean value (you can check basic.py for BOOLEANS_* constants to see the full list of Boolean keywords). If your option actually is a boolean, just use `type=bool`; there is no need to populate 'choices'.
* For new modules or options in a module add version_added. The version should match the value of the current development version and is a string (not a float), so be sure to enclose it in quotes.
* Verify that arguments in doc and module spec dict are identical.
* For password / secret arguments no_log=True should be set.
* Requirements should be documented, using the `requirements=[]` field.
* Author should be set, with their name and their github id, at the least.
* Ensure that you make use of `U()` for URLs, `I()` for option names, `C()` for files and option values, `M()` for module names.
* If an optional parameter is sometimes required this need to be reflected in the documentation, e.g. "Required when C(state=present)."
* Verify that a GPL 3 License header is included.
* Does module use check_mode? Could it be modified to use it? Document it. Documentation is everyone's friend.
* Examples--include them whenever possible and make sure they are reproducible.
* Document the return structure of the module. Refer to :ref:`common_return_values` and :ref:`module_documenting` for additional information.
* Predictable user interface: This is a particularly important section as it is also an area where we need significant improvements.
* Name consistency across modules (we've gotten better at this, but we still have many deviations).
* Declarative operation (not CRUD)--this makes it easy for a user not to care what the existing state is, just about the final state. ``started/stopped``, ``present/absent``--don't overload options too much. It is preferable to add a new, simple option than to add choices/states that don't fit with existing ones.
* Keep options small, having them take large data structures might save us a few tasks, but adds a complex requirement that we cannot easily validate before passing on to the module.
* Allow an "expert mode". This may sound like the absolute opposite of the previous one, but it is always best to let expert users deal with complex data. This requires different modules in some cases, so that you end up having one (1) expert module and several 'piecemeal' ones (ec2_vpc_net?). The reason for this is not, as many users express, because it allows a single task and keeps plays small (which just moves the data complexity into vars files, leaving you with a slightly different structure in another YAML file). It does, however, allow for a more 'atomic' operation against the underlying APIs and services.
* Informative responses: Please note, that for >= 2.0, it is required that return data to be documented.
* Always return useful data, even when there is no change.
* Be consistent about returns (some modules are too random), unless it is detrimental to the state/action.
* Make returns reusable--most of the time you don't want to read it, but you do want to process it and re-purpose it.
* Return diff if in diff mode. This is not required for all modules, as it won't make sense for certain ones, but please attempt to include this when applicable).
* Code: This applies to all code in general, but often seems to be missing from modules, so please keep the following in mind as you work.
* Validate upfront--fail fast and return useful and clear error messages.
* Defensive programming--modules should be designed simply enough that this should be easy. Modules should always handle errors gracefully and avoid direct stacktraces. Ansible deals with this better in 2.0 and returns them in the results.
* Fail predictably--if we must fail, do it in a way that is the most expected. Either mimic the underlying tool or the general way the system works.
* Modules should not do the job of other modules, that is what roles are for. Less magic is more.
* Don't reinvent the wheel. Part of the problem is that code sharing is not that easy nor documented, we also need to expand our base functions to provide common patterns (retry, throttling, etc).
* Support check mode. This is not required for all modules, as it won't make sense for certain ones, but please attempt to include this when applicable). For more information, refer to :ref:`check_mode_drift` and :ref:`check_mode_dry`.
* Exceptions: The module must handle them. (exceptions are bugs)
* Give out useful messages on what you were doing and you can add the exception message to that.
* Avoid catchall exceptions, they are not very useful unless the underlying API gives very good error messages pertaining the attempted action.
* Module-dependent guidelines: Additional module guidelines may exist for certain families of modules.
* Be sure to check out the modules themselves for additional information.
* `Amazon <https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/amazon/GUIDELINES.md>`_
* Modules should make use of the "extends_documentation_fragment" to ensure documentation available. For example, the AWS module should include::
extends_documentation_fragment:
- aws
- ec2
* The module must not use sys.exit() --> use fail_json() from the module object.
* Import custom packages in try/except and handled with fail_json() in main() e.g.
.. code-block:: python
try:
import foo
HAS_LIB=True
except:
HAS_LIB=False
* The return structure should be consistent, even if NA/None are used for keys normally returned under other options.
* Are module actions idempotent? If not document in the descriptions or the notes.
* Import ``ansible.module_utils`` code in the same place as you import other libraries. In older code, this was done at the bottom of the file but that's no longer needed.
* Do not use wildcards for importing other python modules (ex: ``from ansible.module_utils.basic import *``). This used to be required for code imported from ``ansible.module_utils`` but, from Ansible-2.1 onwards, it's just an outdated and bad practice.
* The module must have a `main` function that wraps the normal execution.
* Call your :func:`main` from a conditional so that it would be possible to
import them into unit tests in the future example
.. code-block:: python
if __name__ == '__main__':
main()
* Try to normalize parameters with other modules, you can have aliases for when user is more familiar with underlying API name for the option
* Being `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_ compliant is a requirement. See :doc:`testing_pep8` for more information.
* Avoid '`action`/`command`', they are imperative and not declarative, there are other ways to express the same thing
* Do not add `list` or `info` state options to an existing module - create a new `_facts` module.
* If you are asking 'how can I have a module execute other modules' ... you want to write a role
* Return values must be able to be serialized as json via the python stdlib
json library. basic python types (strings, int, dicts, lists, etc) are
serializable. A common pitfall is to try returning an object via
exit_json(). Instead, convert the fields you need from the object into the
fields of a dictionary and return the dictionary.
* When fetching URLs, please use either fetch_url or open_url from ansible.module_utils.urls
rather than urllib2; urllib2 does not natively verify TLS certificates and so is insecure for https.
* facts modules must return facts in the ansible_facts field of the :ref:`result
dictionary<common_return_values>`.
* modules that are purely about fact gathering need to implement check_mode.
they should not cause any changes anyway so it should be as simple as adding
check_mode=True when instantiating AnsibleModule. (The reason is that
playbooks which conditionalize based on fact information will only
conditionalize correctly in check_mode if the facts are returned in
check_mode).
* Basic auth: module_utils.api has some helpers for doing basic auth with
module_utils.urls.fetch_url(). If you use those you may find you also want
to fallback on environment variables for default values. If you do that,
be sure to use non-generic environment variables (like
:code:`API_<MODULENAME>_USERNAME`). Using generic environment variables
like :code:`API_USERNAME` would conflict between modules.
If your module meets our objective requirements, we'll review your code to see if we think it's clear, concise, secure, and maintainable. We'll consider whether your module provides a good user experience, helpful error messages, reasonable defaults, and more. This process is subjective, and we can't list exact standards for acceptance. For the best chance of getting your module accepted into the Ansible repo, follow our :ref:`tips for module development <developing_modules_best_practices>`.
Windows modules checklist
=========================
For a checklist and details on how to write Windows modules please see :doc:`developing_modules_general_windows`
Deprecating and making module aliases
======================================
Starting in 1.8, you can deprecate modules by renaming them with a preceding ``_``, i.e. ``old_cloud.py`` to
``_old_cloud.py``. This keeps the module available, but hides it from the primary docs and listing.
When deprecating a module:
1) Set the ``ANSIBLE_METADATA`` `status` to `deprecated`.
2) In the ``DOCUMENTATION`` section, add a `deprecated` field along the lines of::
deprecated: Deprecated in 2.3. Use M(whatmoduletouseinstead) instead.
3) Add the deprecation to CHANGELOG.md under the ``###Deprecations:`` section.
Alias module names
------------------
You can also rename modules and keep an alias to the old name by using a symlink that starts with _.
This example allows the stat module to be called with fileinfo, making the following examples equivalent::
EXAMPLES = '''
ln -s stat.py _fileinfo.py
ansible -m stat -a "path=/tmp" localhost
ansible -m fileinfo -a "path=/tmp" localhost
'''
For a checklist and details on how to write Windows modules please see :ref:`developing_modules_general_windows`

View File

@ -1,80 +1,63 @@
.. _developing_modules_documenting:
.. _module_documenting:
Documenting Your Module
=======================
*******************************
Module format and documentation
*******************************
.. contents:: Topics
If you want to contribute your module to Ansible, you must write your module in Python and follow the standard format described below. (Unless you're writing a Windows module, in which case the :ref:`Windows guidelines <developing_modules_general_windows>` apply.) In addition to following this format, you should review our :ref:`submission checklist <developing_modules_checklist>`, :ref:`programming tips <developing_modules_best_practices>`, and :ref:`strategy for maintaining Python 2 and Python 3 compatibility <developing_python_3>`, as well as information about :ref:`testing <developing_testing>` before you open a pull request.
The online module documentation is generated from the modules themselves.
As the module documentation is generated from documentation strings contained in the modules, all modules included with Ansible must have a ``DOCUMENTATION`` string.
This string must be a valid YAML document
which conforms to the schema defined below. You may find it easier to
start writing your ``DOCUMENTATION`` string in an editor with YAML
syntax highlighting before you include it in your Python file.
Every Ansible module written in Python must begin with seven standard sections in a particular order, followed by the code. The sections in order are:
All modules must have the following sections defined in this order:
1. Copyright
2. ANSIBLE_METADATA
3. DOCUMENTATION
4. EXAMPLES
5. RETURN
6. Python imports
.. contents::
:depth: 1
:local:
.. note:: Why don't the imports go first?
Keen Python programmers may notice that contrary to PEP 8's advice we don't put ``imports`` at the top of the file. This is because the ``ANSIBLE_METADATA`` through ``RETURN`` sections are not used by the module code itself; they are essentially extra docstrings for the file. The imports are placed after these special variables for the same reason as PEP 8 puts the imports after the introductory comments and docstrings. This keeps the active parts of the code together and the pieces which are purely informational apart. The decision to exclude E402 is based on readability (which is what PEP 8 is about). Documentation strings in a module are much more similar to module level docstrings, than code, and are never utilized by the module itself. Placing the imports below this documentation and closer to the code, consolidates and groups all related code in a congruent manner to improve readability, debugging and understanding.
.. warning:: Why do some modules have imports at the bottom of the file?
.. warning:: **Copy old modules with care!**
If you look at some existing older modules, you may find imports at the bottom of the file. Do not copy that idiom into new modules as it is a historical oddity due to how modules used to be combined with libraries. Over time we're moving the imports to be in their proper place.
Some older modules in Ansible Core have ``imports`` at the bottom of the file, ``Copyright`` notices with the full GPL prefix, and/or ``ANSIBLE_METADATA`` fields in the wrong order. These are legacy files that need updating - do not copy them into new modules. Over time we're updating and correcting older modules. Please follow the guidelines on this page!
.. _shebang:
Python shebang
==============
Every Ansible module must begin with ``#!/usr/bin/python`` - this "shebang" allows ``ansible_python_interpreter`` to work.
.. _copyright:
Copyright
----------------------
Copyright and license
=====================
The beginning of every module should look about the same. After the shebang,
there should be at least two lines covering copyright and licensing of the
code.
After the shebang, there should be a `copyright line <https://www.gnu.org/licenses/gpl-howto.en.html>`_ with the original copyright holder and a license declaration. The license declaration should be ONLY one line, not the full GPL prefix.:
.. code-block:: python
#!/usr/bin/python
# Copyright: (c) 2018, Terry Jones <terry.jones@example.org>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
Every file should have a copyright line (see `The copyright notice <https://www.gnu.org/licenses/gpl-howto.en.html>`_)
with the original copyright holder. Major additions to the module (for
instance, rewrites) may add additional copyright lines. Any legal questions
need to review the source control history, so an exhaustive copyright header is
not necessary.
The license declaration should be ONLY one line, not the full GPL prefix. If
you notice a module with the full prefix, feel free to switch it to the
one-line declaration instead.
When adding a copyright line after completing a significant feature or rewrite,
add the newer line above the older one, like so:
Major additions to the module (for instance, rewrites) may add additional copyright lines. Any legal review will include the source control history, so an exhaustive copyright header is not necessary. When adding a second copyright line for a significant feature or rewrite, add the newer line above the older one:
.. code-block:: python
#!/usr/bin/python
# Copyright: (c) 2017, [New Contributor(s)]
# Copyright: (c) 2015, [Original Contributor(s)]
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
.. _ansible_metadata_block:
ANSIBLE_METADATA Block
----------------------
ANSIBLE_METADATA block
======================
``ANSIBLE_METADATA`` contains information about the module for use by other tools. At the moment, it informs other tools which type of maintainer the module has and to what degree users can rely on a module's behaviour remaining the same over time.
For new modules, the following block can be simply added into your module
After the shebang, the copyright, and the license, your module file should contain an ``ANSIBLE_METADATA`` section. This section provides information about the module for use by other tools. For new modules, the following block can be simply added into your module:
.. code-block:: python
@ -87,30 +70,8 @@ For new modules, the following block can be simply added into your module
* ``metadata_version`` is the version of the ``ANSIBLE_METADATA`` schema, *not* the version of the module.
* Promoting a module's ``status`` or ``supported_by`` status should only be done by members of the Ansible Core Team.
.. note:: Pre-released metadata version
During development of Ansible-2.3, modules had an initial version of the
metadata. This version was modified slightly after release to fix some
points of confusion. You may occasionally see PRs for modules where the
ANSIBLE_METADATA doesn't look quite right because of this. Module
metadata should be fixed before checking it into the repository.
Version 1.1 of the metadata
+++++++++++++++++++++++++++
Structure
^^^^^^^^^
.. code-block:: python
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'supported_by': 'community',
'status': ['preview', 'deprecated']
}
Fields
^^^^^^
Ansible metadata fields
-----------------------
:metadata_version: An "X.Y" formatted string. X and Y are integers which
define the metadata format version. Modules shipped with Ansible are
@ -119,160 +80,188 @@ Fields
to an existing field. We'll increment X if we remove fields or values
or change the type or meaning of a field.
Current metadata_version is "1.1"
:supported_by: This field records who supports the module.
Default value is ``community``. Values are:
:supported_by: Who supports the module.
Default value is ``community``. For information on what the support level values entail, please see
:ref:`Modules Support <modules_support>`. Values are:
* core
* network
* certified
* community
* curated (Deprecated. Modules in this category should probably be core or
certified instead)
* curated (*deprecated value - modules in this category should be core or
certified instead*)
For information on what the support level values entail, please see
:ref:`Modules Support <modules_support>`.
:status: This field records information about the module that is
important to the end user. It's a list of strings. The default value
is a single element list ["preview"]. The following strings are valid
:status: List of strings describing how stable the module is likely to be. See also :ref:`module_lifecycle`.
The default value is a single element list ["preview"]. The following strings are valid
statuses and have the following meanings:
:stableinterface: This means that the module's parameters are
stable. Every effort will be made not to remove parameters or change
their meaning. It is not a rating of the module's code quality.
:preview: This module is a tech preview. This means it may be
:stableinterface: The module's parameters are stable. Every effort will be made not to remove parameters or change
their meaning. **Not** a rating of the module's code quality.
:preview: The module is in tech preview. It may be
unstable, the parameters may change, or it may require libraries or
web services that are themselves subject to incompatible changes.
:deprecated: This module is deprecated and will no longer be
available in a future release.
:removed: This module is not present in the release. A stub is
:deprecated: The module is deprecated and will be removed in a future release.
:removed: The module is not present in the release. A stub is
kept so that documentation can be built. The documentation helps
users port from the removed module to new modules.
Changes from Version 1.0
++++++++++++++++++++++++
.. _documentation_block:
:metadata_version: Version updated from 1.0 to 1.1
:supported_by: All substantive changes were to potential values of the supported_by field
DOCUMENTATION block
===================
* Added the certified value
* Deprecated the curated value, modules shipped with Ansible will use
certified instead. Third party modules are encouraged not to use this as
it is meaningless within Ansible proper.
* Added the network value
After the shebang, the copyright line, the license, and the ``ANSIBLE_METADATA`` section comes the ``DOCUMENTATION`` block. Ansible's online module documentation is generated from the ``DOCUMENTATION`` blocks in each module's source code. The ``DOCUMENTATION`` block must be valid YAML. You may find it easier to start writing your ``DOCUMENTATION`` string in an :ref:`editor with YAML syntax highlighting <other_tools_and_programs>` before you include it in your Python file. You can start by copying our `example documentation string <https://github.com/ansible/ansible/blob/devel/examples/DOCUMENTATION.yml>`_ into your module file and modifying it. If you run into syntax issues in your YAML, you can validate it on the `YAML Lint <http://www.yamllint.com/>`_ website.
DOCUMENTATION Block
-------------------
Module documentation should briefly and accurately define what each module and option does, and how it works with others in the underlying system. Documentation should be written for broad audience--readable both by experts and non-experts.
* Descriptions should always start with a capital letter and end with a full stop. Consistency always helps.
* Verify that arguments in doc and module spec dict are identical.
* For password / secret arguments no_log=True should be set.
* If an optional parameter is sometimes required, reflect this fact in the documentation, e.g. "Required when C(state=present)."
* If your module allows ``check_mode``, reflect this fact in the documentation.
See an example documentation string in the checkout under `examples/DOCUMENTATION.yml <https://github.com/ansible/ansible/blob/devel/examples/DOCUMENTATION.yml>`_.
Each documentation field is described below. Before committing your module documentation, please test it at the command line and as HTML:
Include it in your module file like this:
* As long as your module file is :ref:`available locally <local_modules>`, you can use ``ansible-doc -t module my_module_name`` to view your module documentation at the command line. Any parsing errors will be obvious - you can view details by adding ``-vvv`` to the command.
* You should also :ref:`test the HTML output <testing_documentation>` of your documentation.
.. code-block:: python
Documentation fields
--------------------
#!/usr/bin/python
# Copyright (c) 2017 [REPLACE THIS]
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = '''
---
module: modulename
short_description: This is a sentence describing the module
# ... snip ...
'''
The following fields can be used and are all required unless specified otherwise:
All fields in the ``DOCUMENTATION`` block are lower-case. All fields are required unless specified otherwise:
:module:
The name of the module. This must be the same as the filename, without the ``.py`` extension.
* The name of the module.
* Must be the same as the filename, without the ``.py`` extension.
:short_description:
* A short description which is displayed on the :ref:`all_modules` page and ``ansible-doc -l``.
* As the short description is displayed by ``ansible-doc -l`` without the category grouping it needs enough detail to explain its purpose without the context of the directory structure in which it lives.
* Unlike ``description:`` this field should not have a trailing full stop.
* The ``short_description`` is displayed by ``ansible-doc -l`` without any category grouping,
so it needs enough detail to explain the module's purpose without the context of the directory structure in which it lives.
* Unlike ``description:``, ``short_description`` should not have a trailing period/full stop.
:description:
* A detailed description (generally two or more sentences).
* Must be written in full sentences, i.e. with capital letters and fullstops.
* Shouldn't mention the name module.
* Must be written in full sentences, i.e. with capital letters and periods/full stops.
* Shouldn't mention the module name.
:version_added:
The version of Ansible when the module was added.
This is a `string`, and not a float, i.e. ``version_added: "2.1"``
* The version of Ansible when the module was added.
* This is a string, and not a float, i.e. ``version_added: "2.1"``
:author:
Name of the module author in the form ``First Last (@GitHubID)``. Use a multi-line list if there is more than one author.
* Name of the module author in the form ``First Last (@GitHubID)``.
* Use a multi-line list if there is more than one author.
:deprecated:
If a module is deprecated it must be:
* Mentioned in ``CHANGELOG``
* Referenced in the ``porting_guide_x.y.rst``
* File should be renamed to start with an ``_``
* ``ANSIBLE_METADATA`` must contain ``status: ['deprecated']``
* Following values must be set:
* Marks modules that will be removed in future releases. See also :ref:`module_lifecycle`.
:removed_in: A `string`, such as ``"2.9"``, which represents the version of Ansible this module will replaced with docs only module stub.
:why: Optional string that used to detail why this has been removed.
:alternative: Inform users they should do instead, i.e. ``Use M(whatmoduletouseinstead) instead.``.
:options:
One per module argument:
* If the module has no options (for example, it's a ``_facts`` module), all you need is one line: ``options: {}``.
* If your module has options (in other words, accepts arguments), each option should be documented thoroughly. For each module argument/option, include:
:option-name:
* Declarative operation (not CRUD)–this makes it easy for a user not to care what the existing state is, just about the final state, for example `online:`, rather than `is_online:`.
* Declarative operation (not CRUD), to focus on the final state, for example `online:`, rather than `is_online:`.
* The name of the option should be consistent with the rest of the module, as well as other modules in the same category.
:description:
* Detailed explanation of what this option does. It should be written in full sentences.
* Should not list the options values (that's what ``choices:`` is for, though it should explain `what` the values do if they aren't obvious.
* Should not list the possible values (that's what ``choices:`` is for, though it should explain `what` the values do if they aren't obvious).
* If an optional parameter is sometimes required this need to be reflected in the documentation, e.g. "Required when I(state=present)."
* Mutually exclusive options must be documented as the final sentence on each of the options.
:required:
Only needed if true, otherwise it is assumed to be false.
* Only needed if ``true``.
* If missing, we assume the option is not required.
:default:
* If `required` is false/missing, `default` may be specified (assumed 'null' if missing).
* If ``required`` is false/missing, ``default`` may be specified (assumed 'null' if missing).
* Ensure that the default parameter in the docs matches the default parameter in the code.
* The default option must not be listed as part of the description.
* If the option is a boolean value, you can use any of the boolean values recognized by Ansible:
(such as true/false or yes/no). Choose the one that reads better in the context of the option.
:choices:
List of option values. Should be absent if empty.
* List of option values.
* Should be absent if empty.
:type:
* Specifies the data type that option accepts, must match the ``argspec``.
* If an argument is ``type='bool'``, this field should be set to ``type: bool`` and no ``choices`` should be specified.
:aliases:
List of option name aliases; generally not needed.
:version_added:
Only needed if this option was extended after initial Ansible release, i.e. this is greater than the top level `version_added` field.
This is a string, and not a float, i.e. ``version_added: "2.3"``.
:suboptions:
If this option takes a dict, you can define it here. See `azure_rm_securitygroup`, `os_ironic_node` for examples.
:requirements:
List of requirements, and minimum versions (if applicable)
:notes:
Details of any important information that doesn't fit in one of the above sections; for example if ``check_mode`` isn't supported, or a link to external documentation.
:aliases:
* List of optional name aliases.
* Generally not needed.
:version_added:
* Only needed if this option was extended after initial Ansible release, i.e. this is greater than the top level `version_added` field.
* This is a string, and not a float, i.e. ``version_added: "2.3"``.
:suboptions:
* If this option takes a dict, you can define it here.
* See :ref:`azure_rm_securitygroup_module`, :ref:`os_ironic_node_module` for examples.
:requirements:
* List of requirements (if applicable).
* Include minimum versions.
:notes:
* Details of any important information that doesn't fit in one of the above sections.
* For example, whether ``check_mode`` is or is not supported, or links to external documentation.
Linking within module documentation
-----------------------------------
You can link from your module documentation to other module docs, other resources on docs.ansible.com, and resources elsewhere on the internet. The correct formats for these links are:
* ``L()`` for Links with a heading. For example: ``See L(IOS Platform Options guide, ../network/user_guide/platform_ios.html).``
* ``U()`` for URLs. For example: ``See U(https://www.ansible.com/products/tower) for an overview.``
* ``I()`` for option names. For example: ``Required if I(state=present).``
* ``C()`` for files and option values. For example: ``If not set the environment variable C(ACME_PASSWORD) will be used.``
* ``M()`` for module names. For example: ``See also M(win_copy) or M(win_template).``
.. note::
- The above fields are are all in lowercase.
To refer a collection of modules, use ``C(..)``, e.g. ``Refer to the C(win_*) modules.``
- If the module doesn't doesn't have any options (for example, it's a ``_facts`` module), you can use ``options: {}``.
Documentation fragments
-----------------------
If you're writing multiple related modules, they may share common documentation, such as authentication details or file mode settings. Rather than duplicate that information in each module's ``DOCUMENTATION`` block, you can save it once as a fragment and use it in each module's documentation. Shared documentation fragments are contained in a ``ModuleDocFragment`` class in `lib/ansible/utils/module_docs_fragments/ <https://github.com/ansible/ansible/tree/devel/lib/ansible/utils/module_docs_fragments>`_. To include a documentation fragment, add ``extends_documentation_fragment: FRAGMENT_NAME`` in your module's documentation.
For example, all AWS modules should include::
extends_documentation_fragment:
- aws
- ec2
You can find more examples by searching for ``extends_documentation_fragment`` under the Ansible source tree.
.. _examples_block:
EXAMPLES block
--------------
==============
The EXAMPLES section is required for all new modules.
After the shebang, the copyright line, the license, the ``ANSIBLE_METADATA`` section, and the ``DOCUMENTATION`` block comes the ``EXAMPLES`` block. Here you show users how your module works with real-world examples in multi-line plain-text YAML format. The best examples are ready for the user to copy and paste into a playbook. Review and update your examples with every change to your module.
Examples should demonstrate real world usage, and be written in multi-line plain-text YAML format.
Ensure that examples are kept in sync with the options during the PR review and any following code refactor.
As per playbook best practice, a `name:` should be specified.
``EXAMPLES`` string within the module like this::
Per playbook best practices, each example should include a ``name:`` line::
EXAMPLES = '''
- name: Ensure foo is installed
@ -281,18 +270,17 @@ As per playbook best practice, a `name:` should be specified.
state: present
'''
If the module returns facts that are often needed, an example of how to use them can be helpful.
If your module returns facts that are often needed, an example of how to use them can be helpful.
RETURN Block
------------
.. _return_block:
The RETURN section documents what the module returns, and is required for all new modules.
RETURN block
============
For each value returned, provide a ``description``, in what circumstances the value is ``returned``,
the ``type`` of the value and a ``sample``. For example, from the ``copy`` module:
After the shebang, the copyright line, the license, the ``ANSIBLE_METADATA`` section, ``DOCUMENTATION`` and ``EXAMPLES`` blocks comes the ``RETURN`` block. This section documents the information the module returns for use by other modules.
The following fields can be used and are all required unless specified otherwise.
If your module doesn't return anything (apart from the standard returns), this section of your module should read: ``RETURN = ''' # '''``
Otherwise, for each value returned, provide the following fields. All fields are required unless specified otherwise.
:return name:
Name of the returned field.
@ -300,37 +288,18 @@ The following fields can be used and are all required unless specified otherwise
:description:
Detailed description of what this value represents.
:returned:
When this value is returned, such as `always`, on `success`, `always`
When this value is returned, such as ``always``, or ``on success``.
:type:
Data type
Data type.
:sample:
One or more examples.
:version_added:
Only needed if this return was extended after initial Ansible release, i.e. this is greater than the top level `version_added` field.
This is a string, and not a float, i.e. ``version_added: "2.3"``.
:contains:
Optional, if you set `type: complex` you can detail the dictionary here by repeating the above elements.
:return name:
One per return
:description:
Detailed description of what this value represents.
:returned:
When this value is returned, such as `always`, on `success`, `always`
:type:
Data type
:sample:
One or more examples.
:version_added:
Only needed if this return was extended after initial Ansible release, i.e. this is greater than the top level `version_added` field.
This is a string, and not a float, i.e. ``version_added: "2.3"``.
For complex nested returns type can be specified as ``type: complex``.
Example::
Optional. To describe nested return values, set ``type: complex`` and repeat the elements above for each sub-field.
Here are two example ``RETURN`` sections, one with three simple fields and one with a complex nested field::
RETURN = '''
dest:
@ -373,102 +342,15 @@ Example::
constraint: ">= 3.0"
'''
.. note::
.. _python_imports:
If your module doesn't return anything (apart from the standard returns), you can use ``RETURN = ''' # '''``.
Python imports
==============
Python Imports
--------------
Starting with Ansible version 2.2, all new modules are required to use imports in the form:
After the shebang, the copyright line, the license, and the sections for ``ANSIBLE_METADATA``, ``DOCUMENTATION``, ``EXAMPLES``, and ``RETURN``, you can finally add the python imports. All modules must use Python imports in the form:
.. code-block:: python
from module_utils.basic import AnsibleModule
.. warning::
The use of "wildcard" imports such as ``from module_utils.basic import *`` is no longer allowed.
Formatting functions
--------------------
The formatting functions are:
* ``L()`` for Links with a heading
* ``U()`` for URLs
* ``I()`` for option names
* ``C()`` for files and option values
* ``M()`` for module names.
Module names should be specified as ``M(module)`` to create a link to the online documentation for that module.
Example usage::
Or if not set the environment variable C(ACME_PASSWORD) will be used.
...
Required if I(state=present)
...
Mutually exclusive with I(project_src) and I(files).
...
See also M(win_copy) or M(win_template).
...
Time zone names are from the L(tz database,https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
See U(https://www.ansible.com/products/tower) for an overview.
...
See L(IOS Platform Options guide, ../network/user_guide/platform_ios.html)
.. note::
If you wish to refer a collection of modules, use ``C(..)``, e.g. ``Refer to the C(win_*) modules.``
Documentation fragments
-----------------------
Some categories of modules share common documentation, such as details on how to authenticate options, or file mode settings. Rather than duplicate that information it can be shared using ``docs_fragments``.
These shared fragments are similar to the standard documentation block used in a module, they are just contained in a ``ModuleDocFragment`` class.
All the existing ``docs_fragments`` can be found in ``lib/ansible/utils/module_docs_fragments/``.
To include, simply add in ``extends_documentation_fragment: FRAGMENT_NAME`` into your module.
Examples can be found by searching for ``extends_documentation_fragment`` under the Ansible source tree.
Testing documentation
---------------------
The simplest way to check if your documentation works is to use ``ansible-doc`` to view it. Any parsing errors will be apparent, and details can be obtained by adding ``-vvv``.
If you are going to submit the module for inclusion in the main Ansible repo you should make sure that it renders correctly as HTML.
Put your completed module file into the ``lib/ansible/modules/$CATEGORY/`` directory and then
run the command: ``make webdocs``. The new 'modules.html' file will be
built in the ``docs/docsite/_build/html/$MODULENAME_module.html`` directory.
In order to speed up the build process, you can limit the documentation build to
only include modules you specify, or no modules at all. To do this, run the command:
``MODULES=$MODULENAME make webdocs``. The ``MODULES`` environment variable
accepts a comma-separated list of module names. To skip building
documentation for all modules, specify a non-existent module name, for example:
``MODULES=none make webdocs``.
You may also build a single page of the entire docsite. From ``ansible/docs/docsite`` run ``make htmlsingle rst=[relative path to the .rst file]``, for example: ``make htmlsingle rst=dev_guide/developing_modules_documenting.rst``
To test your documentation against your ``argument_spec`` you can use ``validate-modules``. Note that this option isn't currently enabled in Shippable due to the time it takes to run.
.. code-block:: bash
# If you don't already, ensure you are using your local checkout
source hacking/env-setup
./test/sanity/validate-modules/validate-modules --arg-spec --warnings lib/ansible/modules/your/modules/
.. tip::
If you're having a problem with the syntax of your YAML you can
validate it on the `YAML Lint <http://www.yamllint.com/>`_ website.
For more information in testing, including how to add unit and integration tests, see :doc:`testing`.
The use of "wildcard" imports such as ``from module_utils.basic import *`` is no longer allowed.

View File

@ -1,30 +1,23 @@
.. _developing_modules_general:
.. _module_dev_tutorial_sample:
Ansible Module Development Walkthrough
======================================
*******************************************
Ansible module development: getting started
*******************************************
A module is a reusable, standalone script that Ansible runs on your behalf, either locally or remotely. Modules interact with your local machine, an API, or a remote system to perform specific tasks like changing a database password or spinning up a cloud instance. Each module can be used by the Ansible API, or by the :command:`ansible` or :command:`ansible-playbook` programs. A module provides a defined interface, accepting arguments and returning information to Ansible by printing a JSON string to stdout before exiting. Ansible ships with thousands of modules, and you can easily write your own. If you're writing a module for local use, you can choose any programming language and follow your own rules. This tutorial illustrates how to get started developing an Ansible module in Python.
In this section, we will walk through developing, testing, and debugging an Ansible module.
What's covered in this section:
- `Environment setup <#environment-setup>`__
- `New module development <#new-module-development>`__
- `Local/direct module testing <#localdirect-module-testing>`__
- `Playbook module testing <#playbook-module-testing>`__
- `Debugging (local) <#debugging-local>`__
- `Debugging (remote) <#debugging-remote>`__
- `Unit testing <#unit-testing>`__
- Integration testing (coming soon)
- `Communication and development
support <#communication-and-development-support>`__
- `Credit <#credit>`__
.. contents:: Topics
:local:
.. _environment_setup:
Environment setup
=================
Prerequisites Via Apt (Ubuntu)
``````````````````````````````
Prerequisites via apt (Ubuntu)
------------------------------
Due to dependencies (for example ansible -> paramiko -> pynacl -> libffi):
.. code:: bash
@ -32,8 +25,9 @@ Due to dependencies (for example ansible -> paramiko -> pynacl -> libffi):
sudo apt update
sudo apt install build-essential libssl-dev libffi-dev python-dev
Common Environment setup
````````````````````````
Common environment setup
------------------------------
1. Clone the Ansible repository:
``$ git clone https://github.com/ansible/ansible.git``
2. Change directory into the repository root dir: ``$ cd ansible``
@ -52,21 +46,23 @@ Common Environment setup
``$ . venv/bin/activate && . hacking/env-setup``
New module development
======================
Starting a new module
=====================
If you are creating a new module that doesn't exist, you would start
working on a whole new file. Here is an example:
To create a new module:
- Navigate to the directory that you want to develop your new module
in. E.g. ``$ cd lib/ansible/modules/cloud/azure/``
- Create your new module file: ``$ touch my_new_test_module.py``
- Paste this example code into the new module file: (explanation in comments)
1. Navigate to the correct directory for your new module: ``$ cd lib/ansible/modules/cloud/azure/``
2. Create your new module file: ``$ touch my_new_test_module.py``
3. Paste the content below into your new module file. It includes the :ref:`required Ansible format and documentation <developing_modules_documenting>` and some example code.
4. Modify and extend the code to do what you want your new module to do. See the :ref:`programming tips <developing_modules_best_practices>` and :ref:`Python 3 compatibility <developing_python_3>` pages for pointers on writing clean, concise module code.
.. code:: python
#!/usr/bin/python
# Copyright: (c) 2018, Terry Jones <terry.jones@example.org>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
@ -130,8 +126,7 @@ working on a whole new file. Here is an example:
from ansible.module_utils.basic import AnsibleModule
def run_module():
# define the available arguments/parameters that a user can pass to
# the module
# define available arguments/parameters a user can pass to the module
module_args = dict(
name=dict(type='str', required=True),
new=dict(type='bool', required=False, default=False)
@ -189,15 +184,19 @@ working on a whole new file. Here is an example:
if __name__ == '__main__':
main()
Local/direct module testing
Exercising your module code
===========================
You may want to test the module on the local machine without targeting a
remote host. This is a great way to quickly and easily debug a module
that can run locally.
Once you've modified the sample code above to do what you want, you can try out your module.
Our :ref:`debugging tips <debugging>` will help if you run into bugs as you exercise your module code.
- Create an arguments file in ``/tmp/args.json`` with the following
content: (explanation below)
Exercising module code locally
------------------------------
If you module does not need to target a remote host, you can quickly and easily exercise you code locally like this:
- Create an arguments file, a basic JSON config file that passes parameters to your module so you can run it. Name the arguments file ``/tmp/args.json`` and add the following content:
.. code:: json
@ -214,21 +213,17 @@ that can run locally.
- Run your test module locally and directly:
``$ python ./my_new_test_module.py /tmp/args.json``
This should be working output that resembles something like the
following:
This should return output something like this:
.. code:: json
{"changed": true, "state": {"original_message": "hello", "new_message": "goodbye"}, "invocation": {"module_args": {"name": "hello", "new": true}}}
The arguments file is just a basic json config file that you can
use to pass the module your parameters to run the module it
Playbook module testing
=======================
Exercising module code in a playbook
------------------------------------
If you want to test your new module, you can now consume it with an
Ansible playbook.
The next step in testing your new module is to consume it with an Ansible playbook.
- Create a playbook in any directory: ``$ touch testmod.yml``
- Add the following to the new playbook file::
@ -247,35 +242,26 @@ Ansible playbook.
- Run the playbook and analyze the output: ``$ ansible-playbook ./testmod.yml``
Debugging (local)
=================
Testing basics
====================
If you want to break into a module and step through with the debugger, locally running the module you can do:
These two examples will get you started with testing your module code. Please review our :ref:`testing <developing_testing>` section for more detailed
information, including instructions for :ref:`testing documentation <testing_documentation>`, adding :ref:`integration tests <testing_integration>`, and more.
- Set a breakpoint in the module: ``import pdb; pdb.set_trace()``
- Run the module on the local machine: ``$ python -m pdb ./my_new_test_module.py ./args.json``
Sanity tests
------------
Debugging (remote)
==================
You can run through Ansible's sanity checks in a container:
In the event you want to debug a module that is running on a remote target (i.e. not localhost), one way to do this is the following:
``$ ansible-test sanity -v --docker --python 2.7 MODULE_NAME``
- On your controller machine (running Ansible) set `ANSIBLE_KEEP_REMOTE_FILES=1` (this tells Ansible to retain the modules it sends to the remote machine instead of removing them)
- Run your playbook targetting the remote machine and specify ``-vvvv`` (the verbose output will show you many things, including the remote location that Ansible uses for the modules)
- Take note of the remote path Ansible used on the remote host
- SSH into the remote target after the completion of the playbook
- Navigate to the directory (most likely it is going to be your ansible remote user defined or implied from the playbook: ``~/.ansible/tmp/ansible-tmp-...``)
- Here you should see the module that you executed from your Ansible controller, but this is the zipped file that Ansible sent to the remote host. You can run this by specifying ``python my_test_module.py`` (not necessary)
- To debug, though, we will want to extract this zip out to the original module format: ``python my_test_module.py explode`` (Ansible will expand the module into ``./debug-dir``)
- Navigate to ``./debug-dir`` (notice that unzipping has caused the generation of ``ansible_module_my_test_module.py``)
- Modify or set a breakpoint in the unzipped module
- Ensure that the unzipped module is executable: ``$ chmod 755 ansible_module_my_test_module.py``
- Run the unzipped module directly passing the args file: ``$ ./ansible_module_my_test_module.py args`` (args is the file that contains the params that were originally passed. Good for repro and debugging)
Note that this example requires Docker to be installed and running. If you'd rather not use a
container for this, you can choose to use ``--tox`` instead of ``--docker``.
Unit testing
============
Unit tests
----------
Unit tests for modules will be appropriately located in ``./test/units/modules``. You must first setup your testing environment. In this example, we're using Python 3.5.
You can add unit tests for your module in ``./test/units/modules``. You must first setup your testing environment. In this example, we're using Python 3.5.
- Install the requirements (outside of your virtual environment): ``$ pip3 install -r ./test/runner/requirements/units.txt``
- To run all tests do the following: ``$ ansible-test units --python 3.5`` (you must run ``. hacking/env-setup`` prior to this)
@ -287,26 +273,23 @@ To run pytest against a single test module, you can do the following (provide th
``$ pytest -r a --cov=. --cov-report=html --fulltrace --color yes
test/units/modules/.../test/my_new_test_module.py``
Going Further
=============
Contributing back to Ansible
============================
If you would like to contribute to the main Ansible repository
by adding a new feature or fixing a bug, `create a fork <https://help.github.com/articles/fork-a-repo/>`_
of the Ansible repository and develop against a new feature
branch using the ``devel`` branch as a starting point.
When you you have a good working code change,
When you you have a good working code change, you can
submit a pull request to the Ansible repository by selecting
your feature branch as a source and the Ansible devel branch as
a target.
If you want to submit a new module to the upstream Ansible repo, be sure
to run through sanity checks first. For example:
``$ ansible-test sanity -v --docker --python 2.7 MODULE_NAME``
Note that this example requires docker to be installed and running. If you'd rather not use a
container for this, you can choose to use ``--tox`` instead of ``--docker``.
If you want to contribute your module back to the upstream Ansible repo,
review our :ref:`submission checklist <developing_modules_checklist>`, :ref:`programming tips <developing_modules_best_practices>`,
and :ref:`strategy for maintaining Python 2 and Python 3 compatibility <developing_python_3>`, as well as
information about :ref:`testing <developing_testing>` before you open a pull request.
The :ref:`Community Guide <ansible_community_guide>` covers how to open a pull request and what happens next.
Communication and development support

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,443 @@
.. _aci_dev_guide:
****************************
Developing Cisco ACI modules
****************************
This is a brief walk-through of how to create new Cisco ACI modules for Ansible.
For more information about Cisco ACI, look at the :ref:`Cisco ACI user guide <aci_guide>`.
What's covered in this section:
.. contents::
:depth: 3
:local:
.. _aci_dev_guide_intro:
Introduction
============
Ansible already ships with a large collection of Cisco ACI modules, however the ACI object model is huge and covering all possible functionality would easily cover more than 1500 individual modules.
If you are in need of specific functionality, you have 2 options:
- Learn the ACI object model and use the low-level APIC REST API using the :ref:`aci_rest <aci_rest_module>` module
- Write your own dedicated modules, which is actually quite easy
.. seealso::
`ACI Fundamentals: ACI Policy Model <https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/1-x/aci-fundamentals/b_ACI-Fundamentals/b_ACI-Fundamentals_chapter_010001.html>`_
A good introduction to the ACI object model.
`APIC Management Information Model reference <https://developer.cisco.com/docs/apic-mim-ref/>`_
Complete reference of the APIC object model.
`APIC REST API Configuration Guide <https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/2-x/rest_cfg/2_1_x/b_Cisco_APIC_REST_API_Configuration_Guide.html>`_
Detailed guide on how the APIC REST API is designed and used, incl. many examples.
So let's look at how a typical ACI module is built up.
.. _aci_dev_guide_module_structure:
ACI module structure
====================
Importing objects from Python libraries
---------------------------------------
The following imports are standard across ACI modules:
.. code-block:: python
from ansible.module_utils.aci import ACIModule, aci_argument_spec
from ansible.module_utils.basic import AnsibleModule
Defining the argument spec
--------------------------
The first line adds the standard connection parameters to the module. After that, the next section will update the ``argument_spec`` dictionary with module-specific parameters. The module-specific parameters should include:
* the object_id (usually the name)
* the configurable properties of the object
* the parent object IDs (all parents up to the root)
* only child classes that are a 1-to-1 relationship (1-to-many/many-to-many require their own module to properly manage)
* the state
+ ``state: absent`` to ensure object does not exist
+ ``state: present`` to ensure the object and configs exist; this is also the default
+ ``state: query`` to retrieve information about objects in the class
.. code-block:: python
def main():
argument_spec = aci_argument_spec()
argument_spec.update(
object_id=dict(type='str', aliases=['name']),
object_prop1=dict(type='str'),
object_prop2=dict(type='str', choices=['choice1', 'choice2', 'choice3']),
object_prop3=dict(type='int'),
parent_id=dict(type='str'),
child_object_id=dict(type='str'),
child_object_prop=dict(type='str'),
state=dict(type='str', default='present', choices=['absent', 'present', 'query']),
)
.. hint:: Do not provide default values for configuration arguments. Default values could cause unintended changes to the object.
Using the AnsibleModule object
------------------------------
The following section creates an AnsibleModule instance. The module should support check-mode, so we pass the ``argument_spec`` and ``supports_check_mode`` arguments. Since these modules support querying the APIC for all objects of the module's class, the object/parent IDs should only be required if ``state: absent`` or ``state: present``.
.. code-block:: python
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
['state', 'absent', ['object_id', 'parent_id']],
['state', 'present', ['object_id', 'parent_id']],
],
)
Mapping variable definition
---------------------------
Once the AnsibleModule object has been initiated, the necessary parameter values should be extracted from ``params`` and any data validation should be done. Usually the only params that need to be extracted are those related to the ACI object configuration and its child configuration. If you have integer objects that you would like to validate, then the validation should be done here, and the ``ACIModule.payload()`` method will handle the string conversion.
.. code-block:: python
object_id = object_id
object_prop1 = module.params['object_prop1']
object_prop2 = module.params['object_prop2']
object_prop3 = module.params['object_prop3']
if object_prop3 is not None and object_prop3 not in range(x, y):
module.fail_json(msg='Valid object_prop3 values are between x and (y-1)')
child_object_id = module.params[' child_objec_id']
child_object_prop = module.params['child_object_prop']
state = module.params['state']
Using the ACIModule object
--------------------------
The ACIModule class handles most of the logic for the ACI modules. The ACIModule extends functionality to the AnsibleModule object, so the module instance must be passed into the class instantiation.
.. code-block:: python
aci = ACIModule(module)
The ACIModule has six main methods that are used by the modules:
* construct_url
* get_existing
* payload
* get_diff
* post_config
* delete_config
The first two methods are used regardless of what value is passed to the ``state`` parameter.
Constructing URLs
^^^^^^^^^^^^^^^^^
The ``construct_url()`` method is used to dynamically build the appropriate URL to interact with the object, and the appropriate filter string that should be appended to the URL to filter the results.
* When the ``state`` is not ``query``, the URL is the base URL to access the APIC plus the distinguished name to access the object. The filter string will restrict the returned data to just the configuration data.
* When ``state`` is ``query``, the URL and filter string used depends on what parameters are passed to the object. This method handles the complexity so that it is easier to add new modules and so that all modules are consistent in what type of data is returned.
.. note:: Our design goal is to take all ID parameters that have values, and return the most specific data possible. If you do not supply any ID parameters to the task, then all objects of the class will be returned. If your task does consist of ID parameters sed, then the data for the specific object is returned. If a partial set of ID parameters are passed, then the module will use the IDs that are passed to build the URL and filter strings appropriately.
The ``construct_url()`` method takes 2 required arguments:
* **self** - passed automatically with the class instance
* **root_class** - A dictionary consisting of ``aci_class``, ``aci_rn``, ``target_filter``, and ``module_object`` keys
+ **aci_class**: The name of the class used by the APIC, e.g. ``fvTenant``
+ **aci_rn**: The relative name of the object, e.g. ``tn-ACME``
+ **target_filter**: A dictionary with key-value pairs that make up the query string for selecting a subset of entries, e.g. ``{'name': 'ACME'}``
+ **module_object**: The particular object for this class, e.g. ``ACME``
Example:
.. code-block:: python
aci.construct_url(
root_class=dict(
aci_class='fvTenant',
aci_rn='tn-{0}'.format(tenant),
target_filter={'name': tenant},
module_object=tenant,
),
)
Some modules, like ``aci_tenant``, are the root class and so they would not need to pass any additional arguments to the method.
The ``construct_url()`` method takes 4 optional arguments, the first three imitate the root class as described above, but are for child objects:
* subclass_1 - A dictionary consisting of ``aci_class``, ``aci_rn``, ``target_filter``, and ``module_object`` keys
+ Example: Application Profile Class (AP)
* subclass_2 - A dictionary consisting of ``aci_class``, ``aci_rn``, ``target_filter``, and ``module_object`` keys
+ Example: End Point Group (EPG)
* subclass_3 - A dictionary consisting of ``aci_class``, ``aci_rn``, ``target_filter``, and ``module_object`` keys
+ Example: Binding a Contract to an EPG
* child_classes - The list of APIC names for the child classes supported by the modules.
+ This is a list, even if it is a list of one
+ These are the unfriendly names used by the APIC
+ These are used to limit the returned child_classes when possible
+ Example: ``child_classes=['fvRsBDSubnetToProfile', 'fvRsNdPfxPol']``
.. note:: Sometimes the APIC will require special characters ([, ], and -) or will use object metadata in the name ("vlanns" for VLAN pools); the module should handle adding special characters or joining of multiple parameters in order to keep expected inputs simple.
Getting the existing configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Once the URL and filter string have been built, the module is ready to retrieve the existing configuration for the object:
* ``state: present`` retrieves the configuration to use as a comparison against what was entered in the task. All values that are different than the existing values will be updated.
* ``state: absent`` uses the existing configuration to see if the item exists and needs to be deleted.
* ``state: query`` uses this to perform the query for the task and report back the existing data.
.. code-block:: python
aci.get_existing()
When state is present
^^^^^^^^^^^^^^^^^^^^^
When ``state: present``, the module needs to perform a diff against the existing configuration and the task entries. If any value needs to be updated, then the module will make a POST request with only the items that need to be updated. Some modules have children that are in a 1-to-1 relationship with another object; for these cases, the module can be used to manage the child objects.
Building the ACI payload
""""""""""""""""""""""""
The ``aci.payload()`` method is used to build a dictionary of the proposed object configuration. All parameters that were not provided a value in the task will be removed from the dictionary (both for the object and its children). Any parameter that does have a value will be converted to a string and added to the final dictionary object that will be used for comparison against the existing configuration.
The ``aci.payload()`` method takes two required arguments and 1 optional argument, depending on if the module manages child objects.
* ``aci_class`` is the APIC name for the object's class, e.g. ``aci_class='fvBD'``
* ``class_config`` is the appropriate dictionary to be used as the payload for the POST request
+ The keys should match the names used by the APIC.
+ The values should be the corresponding value in ``module.params``; these are the variables defined above
* ``child_configs`` is optional, and is a list of child config dictionaries.
+ The child configs include the full child object dictionary, not just the attributes configuration portion.
+ The configuration portion is built the same way as the object.
.. code-block:: python
aci.payload(
aci_class=aci_class,
class_config=dict(
name=bd,
descr=description,
type=bd_type,
),
child_configs=[
dict(
fvRsCtx=dict(
attributes=dict(
tnFvCtxName=vrf
),
),
),
],
)
Performing the request
""""""""""""""""""""""
The ``get_diff()`` method is used to perform the diff, and takes only one required argument, ``aci_class``.
Example: ``aci.get_diff(aci_class='fvBD')``
The ``post_config()`` method is used to make the POST request to the APIC if needed. This method doesn't take any arguments and handles check mode.
Example: ``aci.post_config()``
Example code
""""""""""""
.. code-block:: guess
if state == 'present':
aci.payload(
aci_class='<object APIC class>',
class_config=dict(
name=object_id,
prop1=object_prop1,
prop2=object_prop2,
prop3=object_prop3,
),
child_configs=[
dict(
'<child APIC class>'=dict(
attributes=dict(
child_key=child_object_id,
child_prop=child_object_prop
),
),
),
],
)
aci.get_diff(aci_class='<object APIC class>')
aci.post_config()
When state is absent
^^^^^^^^^^^^^^^^^^^^
If the task sets the state to absent, then the ``delete_config()`` method is all that is needed. This method does not take any arguments, and handles check mode.
.. code-block:: guess
elif state == 'absent':
aci.delete_config()
Exiting the module
^^^^^^^^^^^^^^^^^^
To have the module exit, call the ACIModule method ``exit_json()``. This method automatically takes care of returning the common return values for you.
.. code-block:: guess
aci.exit_json()
if __name__ == '__main__':
main()
.. _aci_dev_guide_testing:
Testing ACI library functions
=============================
You can test your ``construct_url()`` and ``payload()`` arguments without accessing APIC hardware by using the following python script:
.. code-block:: guess
#!/usr/bin/python
import json
from ansible.module_utils.network.aci.aci import ACIModule
# Just another class mimicking a bare AnsibleModule class for construct_url() and payload() methods
class AltModule():
params = dict(
host='dummy',
port=123,
protocol='https',
state='present',
output_level='debug',
)
# A sub-class of ACIModule to overload __init__ (we don't need to log into APIC)
class AltACIModule(ACIModule):
def __init__(self):
self.result = dict(changed=False)
self.module = AltModule()
self.params = self.module.params
# Instantiate our version of the ACI module
aci = AltACIModule()
# Define the variables you need below
aep = 'AEP'
aep_domain = 'uni/phys-DOMAIN'
# Below test the construct_url() arguments to see if it produced correct results
aci.construct_url(
root_class=dict(
aci_class='infraAttEntityP',
aci_rn='infra/attentp-{}'.format(aep),
target_filter={'name': aep},
module_object=aep,
),
subclass_1=dict(
aci_class='infraRsDomP',
aci_rn='rsdomP-[{}]'.format(aep_domain),
target_filter={'tDn': aep_domain},
module_object=aep_domain,
),
)
# Below test the payload arguments to see if it produced correct results
aci.payload(
aci_class='infraRsDomP',
class_config=dict(tDn=aep_domain),
)
# Print the URL and proposed payload
print 'URL:', json.dumps(aci.url, indent=4)
print 'PAYLOAD:', json.dumps(aci.proposed, indent=4)
This will result in:
.. code-block:: yaml
URL: "https://dummy/api/mo/uni/infra/attentp-AEP/rsdomP-[phys-DOMAIN].json"
PAYLOAD: {
"infraRsDomP": {
"attributes": {
"tDn": "phys-DOMAIN"
}
}
}
Testing for sanity checks
-------------------------
You can run from your fork something like:
.. code-block:: bash
$ ./test/runner/ansible-test sanity --python 2.7 lib/ansible/modules/network/aci/aci_tenant.py
.. seealso::
:doc:`testing_sanity`
Information on how to build sanity tests.
Testing ACI integration tests
-----------------------------
You can run this:
.. code-block:: bash
$ ./test/runner/ansible-test network-integration --continue-on-error --allow-unsupported --diff -v aci_tenant
.. note:: You may need to add ``--python 2.7`` or ``--python 3.6`` in order to use the correct python version for performing tests.
You may want to edit the used inventory at *./test/integration/inventory.networking* and add something like:
.. code-block:: ini
[aci:vars]
aci_hostname=my-apic-1
aci_username=admin
aci_password=my-password
aci_use_ssl=yes
aci_use_proxy=no
[aci]
localhost ansible_ssh_host=127.0.0.1 ansible_connection=local
.. seealso::
:doc:`testing_integration`
Information on how to build integration tests.
Testing for test coverage
-------------------------
You can run this:
.. code-block:: bash
$ ./test/runner/ansible-test integration --python 2.7 --coverage aci_tenant
$ ./test/runner/ansible-test coverage report

View File

@ -1,7 +1,8 @@
.. _developing_modules_general_windows:
Windows Ansible Module Development Walkthrough
==============================================
**************************************
Windows module development walkthrough
**************************************
In this section, we will walk through developing, testing, and debugging an
Ansible Windows module.
@ -11,7 +12,8 @@ Windows host, this guide differs from the usual development walkthrough guide.
What's covered in this section:
.. contents:: Topics
.. contents::
:local:
Windows environment setup
@ -39,7 +41,7 @@ VirtualBox documentation for installation instructions):
- Vagrant
- VirtualBox
Create a Windows Server in a VM
Create a Windows server in a VM
===============================
To create a single Windows Server 2016 instance, run the following:
@ -55,7 +57,7 @@ for the first time, the Windows VM will run through the sysprep process and
then create a HTTP and HTTPS WinRM listener automatically. Vagrant will finish
its process once the listeners are onlinem, after which the VM can be used by Ansible.
Create an Ansible Inventory
Create an Ansible inventory
===========================
The following Ansible inventory file can be used to connect to the newly
@ -121,7 +123,7 @@ hosts that are defined under the ``domain_children`` key. The host variable
only network adapter while ``vagrant_box`` is the box that will be used to
create the VM.
Provisioning the Environment
Provisioning the environment
============================
To provision the environment as is, run the following:
@ -206,7 +208,7 @@ into PowerShell as well as some Ansible-specific requirements specified by
but are most commonly near the top. They are used to make it easier to state the
requirements of the module without writing any of the checks. Each ``requires``
statement must be on its own line, but there can be multiple requires statements
in one script.
in one script.
These are the checks that can be used within Ansible modules:
@ -228,7 +230,7 @@ can be imported by adding the following line to a PowerShell module:
#Requires -Module Ansible.ModuleUtils.Legacy
This will import the module_util at ``./lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1``
and enable calling all of its functions.
and enable calling all of its functions.
The following is a list of module_utils that are packaged with Ansible and a general description of what
they do:
@ -241,7 +243,7 @@ they do:
- LinkUtil: Utility to create, remove, and get information about symbolic links, junction points and hard inks.
- SID: Utilities used to convert a user or group to a Windows SID and vice versa.
For more details on any specific module utility and their requirements, please see the `Ansible
For more details on any specific module utility and their requirements, please see the `Ansible
module utilities source code <https://github.com/ansible/ansible/tree/devel/lib/ansible/module_utils/powershell>`_.
PowerShell module utilities can be stored outside of the standard Ansible
@ -360,7 +362,7 @@ Windows integration testing
Integration tests for Ansible modules are typically written as Ansible roles. These test
roles are located in ``./test/integration/targets``. You must first set up your testing
environment, and configure a test inventory for Ansible to connect to.
environment, and configure a test inventory for Ansible to connect to.
In this example we will set up a test inventory to connect to two hosts and run the integration
tests for win_stat:
@ -386,11 +388,11 @@ idempotent and does not report changes. For example:
state: absent
register: remove_file_check
check_mode: yes
- name: get result of remove a file (check mode)
win_command: powershell.exe "if (Test-Path -Path 'C:\temp') { 'true' } else { 'false' }"
register: remove_file_actual_check
- name: assert remove a file (check mode)
assert:
that:
@ -402,11 +404,11 @@ idempotent and does not report changes. For example:
path: C:\temp
state: absent
register: remove_file
- name: get result of remove a file
win_command: powershell.exe "if (Test-Path -Path 'C:\temp') { 'true' } else { 'false' }"
register: remove_file_actual
- name: assert remove a file
assert:
that:
@ -418,7 +420,7 @@ idempotent and does not report changes. For example:
path: C:\temp
state: absent
register: remove_file_again
- name: assert remove a file (idempotent)
assert:
that:

View File

@ -1,27 +1,31 @@
.. _developing_modules_in_groups:
*********************************************
Information for submitting a group of modules
=============================================
*********************************************
.. contents:: Topics
:local:
Submitting a group of modules
`````````````````````````````
=============================
This section discusses how to get multiple related modules into Ansible.
This document is intended for both companies wishing to add modules for their own products as well as users of 3rd party products wishing to add Ansible functionality.
It's based on module development best practices that the Ansible core team and community have accumulated.
It's based on module development tips and tricks that the Ansible core team and community have accumulated.
.. include:: shared_snippets/licensing.txt
Before you start coding
```````````````````````
=======================
Although it's tempting to get straight into coding, there are a few things to be aware of first. This list of prerequisites is designed to help ensure that you develop high-quality modules that flow easily through the review process and get into Ansible more quickly.
* Read though all the pages linked off :doc:`developing_modules`; paying particular focus to the :doc:`developing_modules_checklist`.
* For new modules going into Ansible 2.4 we are raising the bar so they must be PEP 8 compliant. See :doc:`testing_pep8` for more information.
* Starting with Ansible version 2.4, all new modules must support Python 2.6 and Python 3.5+. If this is an issue, please contact us (see the "Speak to us" section later in this document to learn how).
* All modules shipped with Ansible must be done so under the GPLv3 license. Files under the ``lib/ansible/module_utils/`` directory should be done so under the BSD license.
* New modules must be PEP 8 compliant. See :doc:`testing_pep8` for more information.
* Starting with Ansible version 2.7, all new modules must :ref:`support Python 2.7+ and Python 3.5+ <developing_python_3>`. If this is an issue, please contact us (see the "Speak to us" section later in this document to learn how).
* Have a look at the existing modules and how they've been named in the :ref:`all_modules`, especially in the same functional area (such as cloud, networking, databases).
* Shared code can be placed into ``lib/ansible/module_utils/``
* Shared documentation (for example describing common arguments) can be placed in ``lib/ansible/utils/module_docs_fragments/``.
@ -30,8 +34,8 @@ Although it's tempting to get straight into coding, there are a few things to be
* Starting with Ansible 2.4 all :ref:`network_modules` MUST have unit tests.
Naming Convention
`````````````````
Naming convention
=================
As you may have noticed when looking under ``lib/ansible/modules/`` we support up to two directories deep (but no deeper), e.g. `databases/mysql`. This is used to group files on disk as well as group related modules into categories and topics the Module Index, for example: :ref:`database_modules`.
@ -47,7 +51,7 @@ Each module should have the above (or similar) prefix; see existing :ref:`all_mo
Speak to us
```````````
===========
Circulating your ideas before coding is a good way to help you set off in the right direction.
@ -57,7 +61,7 @@ We've found that writing a list of your proposed module names and a one or two l
Where to get support
````````````````````
====================
Ansible has a thriving and knowledgeable community of module developers that is a great resource for getting your questions answered.
@ -68,8 +72,8 @@ In the :ref:`ansible_community_guide` you can find how to:
* IRC meetings - Join the various weekly IRC meetings `meeting schedule and agenda page <https://github.com/ansible/community/blob/master/meetings/README.md>`_
Your First Pull Request
````````````````````````
Your first pull request
=======================
Now that you've reviewed this document, you should be ready to open your first pull request.
@ -102,7 +106,7 @@ We have a ``ansibullbot`` helper that comments on GitHub Issues and PRs which sh
Subsequent PRs
``````````````
==============
By this point you first PR that defined the module namespace should have been merged. You can take the lessons learned from the first PR and apply it to the rest of the modules.
@ -116,10 +120,10 @@ Over the years we've experimented with different sized module PRs, ranging from
You can raise up to five PRs at once (5 PRs = 5 new modules) **after** your first PR has been merged. We've found this is a good batch size to keep the review process flowing.
Finally
```````
Maintaining your modules
========================
Now that your modules are integrated there are a few bits of housekeeping to be done
Now that your modules are integrated there are a few bits of housekeeping to be done.
**Bot Meta**
Update `Ansibullbot` so it knows who to notify if/when bugs or PRs are raised against your modules
@ -134,10 +138,10 @@ Review the autogenerated module documentation for each of your modules, found in
If the module documentation hasn't been published live yet, please let a member of the Ansible Core Team know in the ``#ansible-devel`` IRC channel.
New to Git or GitHub
````````````````````
New to git or GitHub
====================
We realise this may be your first use of Git or GitHub. The following guides may be of use:
We realize this may be your first use of Git or GitHub. The following guides may be of use:
* `How to create a fork of ansible/ansible <https://help.github.com/articles/fork-a-repo/>`_
* `How to sync (update) your fork <https://help.github.com/articles/syncing-a-fork/>`_
@ -147,4 +151,4 @@ Please note that in the Ansible Git Repo the main branch is called ``devel`` rat
After your first PR has been merged ensure you "sync your fork" with ``ansible/ansible`` to ensure you've pulled in the directory structure and and shared code or documentation previously created.
As stated in the GitHub documentation, always use feature branches for your PRs, never commit directly into `devel`.
As stated in the GitHub documentation, always use feature branches for your PRs, never commit directly into ``devel``.

View File

@ -1,23 +1,30 @@
.. _developing_plugins:
.. _plugin_guidelines:
Developing Plugins
==================
******************
Developing plugins
******************
.. contents:: Topics
Plugins are pieces of code that augment Ansible's core functionality. Ansible ships with a number of handy plugins, and you can easily write your own. This section describes the various types of Ansible plugins and how to implement them.
Plugins augment Ansible's core functionality with logic and features that are accessible to all modules. Ansible ships with a number of handy plugins, and you can easily write your own. All plugins must:
.. _plugin_guidelines:
* be written in Python
* raise errors
* return strings in unicode
* conform to Ansible's configuration and documentation standards
General Guidelines
------------------
Once you've reviewed these general guidelines, you can skip to the particular type of plugin you want to develop.
This section lists some things that should apply to any type of plugin you develop.
Writing plugins in Python
=========================
Raising Errors
^^^^^^^^^^^^^^
You must write your plugin in Python so it can be loaded by the ``PluginLoader`` and returned as a Python object that any module can use. Since your plugin will execute on the controller, you must write it in a :ref:`compatible version of Python <control_machine_requirements>`.
In general, errors encountered during execution should be returned by raising AnsibleError() or similar class with a message describing the error. When wrapping other exceptions into error messages, you should always use the ``to_text`` Ansible function to ensure proper string compatibility across Python versions:
Raising errors
==============
You should return errors encountered during plugin execution by raising ``AnsibleError()`` or a similar class with a message describing the error. When wrapping other exceptions into error messages, you should always use the ``to_text`` Ansible function to ensure proper string compatibility across Python versions:
.. code-block:: python
@ -28,40 +35,53 @@ In general, errors encountered during execution should be returned by raising An
except Exception as e:
raise AnsibleError('Something happened, this was original exception: %s' % to_native(e))
Check the different AnsibleError objects and see which one applies the best to your situation.
Check the different `AnsibleError objects <https://github.com/ansible/ansible/blob/devel/lib/ansible/errors/__init__.py>`_ and see which one applies best to your situation.
String Encoding
^^^^^^^^^^^^^^^
Any strings returned by your plugin that could ever contain non-ASCII characters must be converted into Python's unicode type because the strings will be run through jinja2. To do this, you can use:
String encoding
===============
You must convert any strings returned by your plugin into Python's unicode type. Converting to unicode ensures that these strings can run through Jinja2. To convert strings:
.. code-block:: python
from ansible.module_utils._text import to_text
result_string = to_text(result_string)
Plugin Configuration
^^^^^^^^^^^^^^^^^^^^
Plugin configuration & documentation standards
==============================================
Starting with Ansible version 2.4, we are unifying how each plugin type is configured and how they get those settings. Plugins will be able to declare their requirements and have Ansible provide them with a resolved'configuration. Starting with Ansible 2.4 both callback and connection type plugins can use this system.
To define configurable options for your plugin, describe them in the ``DOCUMENTATION`` section of the python file. Callback and connection plugins have declared configuration requirements this way since Ansible version 2.4; most plugin types now do the same. This approach ensures that the documentation of your plugin's options will always be correct and up-to-date. To add a configurable option to your plugin, define it in this format:
Most plugins will be able to use ``self.get_option(<optionname>)`` to access the settings.
These are pre-populated by a ``self.set_options()`` call, for most plugin types this is done by the controller,
but for some types you might need to do this explicitly.
Of course, if you don't have any configurable options, you can ignore this.
.. code-block:: yaml
Plugins that support embedded documentation (see :ref:`ansible-doc` for the list) must now include well-formed doc strings to be considered for merge into the Ansible repo. This documentation also doubles as 'configuration definition' so they will never be out of sync.
options:
option_name:
description: describe this config option
default: default value for this config option
env:
- name: NAME_OF_ENV_VAR
ini:
- section: section_of_ansible.cfg_where_this_config_option_is_defined
key: key_used_in_ansible.cfg
required: True/False
type: boolean/float/integer/list/none/path/pathlist/pathspec/string/tmppath
version_added: X.x
If you inherit from a plugin, you must document the options it takes, either via a documentation fragment or as a copy.
To access the configuration settings in your plugin, use ``self.get_option(<option_name>)``. For most plugin types, the controller pre-populates the settings. If you need to populate settings explicitly, use a ``self.set_options()`` call.
Plugins that support embedded documentation (see :ref:`ansible-doc` for the list) must include well-formed doc strings to be considered for merge into the Ansible repo. If you inherit from a plugin, you must document the options it takes, either via a documentation fragment or as a copy. See :ref:`module_documenting` for more information on correct documentation. Thorough documentation is a good idea even if you're developing a plugin for local use.
Developing particular plugin types
==================================
.. _developing_callbacks:
Callback Plugins
Callback plugins
----------------
Callback plugins enable adding new behaviors to Ansible when responding to events. By default, callback plugins control most of the output you see when running the command line programs.
Callback plugins add new behaviors to Ansible when responding to events. By default, callback plugins control most of the output you see when running the command line programs.
Callback plugins are created by creating a new class with the Base(Callbacks) class as the parent:
To create a callback plugin, create a new class with the Base(Callbacks) class as the parent:
.. code-block:: python
@ -75,7 +95,6 @@ For plugins intended for use with Ansible version 2.0 and later, you should only
For a complete list of methods that you can override, please see ``__init__.py`` in the
`lib/ansible/plugins/callback <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/callback>`_ directory.
The following is a modified example of how Ansible's timer plugin is implemented,
but with an extra option so you can see how configuration works in Ansible version 2.4 and later:
@ -144,41 +163,49 @@ but with an extra option so you can see how configuration works in Ansible versi
# Also note the use of the display object to print to screen. This is available to all callbacks, and you should use this over printing yourself
self._display.display(self._plugin_options['format_string'] % (self._days_hours_minutes_seconds(runtime)))
Note that the CALLBACK_VERSION and CALLBACK_NAME definitions are required for properly functioning plugins for Ansible version 2.0 and later. CALLBACK_TYPE is mostly needed to distinguish 'stdout' plugins from the rest, since you can only load one plugin that writes to stdout.
Note that the ``CALLBACK_VERSION`` and ``CALLBACK_NAME`` definitions are required for properly functioning plugins for Ansible version 2.0 and later. ``CALLBACK_TYPE`` is mostly needed to distinguish 'stdout' plugins from the rest, since you can only load one plugin that writes to stdout.
For example callback plugins, see the source code for the `callback plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/callback>`_
.. _developing_connection_plugins:
Connection Plugins
Connection plugins
------------------
Connection plugins allow Ansible to connect to the target hosts so it can execute tasks on them. Ansible ships with many connection plugins, but only one can be used per host at a time.
Connection plugins allow Ansible to connect to the target hosts so it can execute tasks on them. Ansible ships with many connection plugins, but only one can be used per host at a time. The most commonly used connection plugins are the ``paramiko`` SSH, native ssh (just called ``ssh``), and ``local`` connection types. All of these can be used in playbooks and with ``/usr/bin/ansible`` to connect to remote machines.
By default, Ansible ships with several plugins. The most commonly used are the 'paramiko' SSH, native ssh (just called 'ssh'), and 'local' connection types. All of these can be used in playbooks and with /usr/bin/ansible to decide how you want to talk to remote machines.
Ansible version 2.1 introduced the ``smart`` connection plugin. The ``smart`` connection type allows Ansible to automatically select either the ``paramiko`` or ``openssh`` connection plugin based on system capabilities, or the ``ssh`` connection plugin if OpenSSH supports ControlPersist.
The basics of these connection types are covered in the :ref:`intro_getting_started` section.
To create a new connection plugin (for example, to support SNMP, Message bus, or other transports), copy the format of one of the existing connection plugins and drop it into the ``connection_plugins`` directory.
Should you want to extend Ansible to support other transports (SNMP, Message bus, etc) it's as simple as copying the format of one of the existing modules and dropping it into the connection plugins directory.
For example connection plugins, see the source code for the `connection plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/connection>`_.
Ansible version 2.1 introduced the 'smart' connection plugin. The 'smart' connection type allows Ansible to automatically select either the 'paramiko' or 'openssh' connection plugin based on system capabilities, or the 'ssh' connection plugin if OpenSSH supports ControlPersist.
.. _developing_filter_plugins:
For examples on how to implement a connection plug in, see the source code here:
`lib/ansible/plugins/connection <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/connection>`_.
Filter plugins
--------------
Filter plugins manipulate data. They are a feature of Jinja2 and are also available in Jinja2 templates used by the ``template`` module. As with all plugins, they can be easily extended, but instead of having a file for each one you can have several per file. Most of the filter plugins shipped with Ansible reside in a ``core.py``.
Filter plugins do not use the standard configuration and documentation system described above.
For example filter plugins, see the source code for the `filter plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/filter>`_.
.. _developing_inventory_plugins:
Inventory Plugins
Inventory plugins
-----------------
Inventory plugins were added in Ansible version 2.4. Inventory plugins parse inventory sources and form an in memory representation of the inventory.
Inventory plugins parse inventory sources and form an in-memory representation of the inventory. Inventory plugins were added in Ansible version 2.4.
You can see the details for inventory plugins in the :ref:`developing_inventory` page.
.. _developing_lookup_plugins:
Lookup Plugins
Lookup plugins
--------------
Lookup plugins are used to pull in data from external data stores. Lookup plugins can be used within playbooks both for looping --- playbook language constructs like ``with_fileglob`` and ``with_items`` are implemented via lookup plugins --- and to return values into a variable or parameter.
Lookup plugins pull in data from external data stores. Lookup plugins can be used within playbooks both for looping --- playbook language constructs like ``with_fileglob`` and ``with_items`` are implemented via lookup plugins --- and to return values into a variable or parameter.
Lookup plugins are very flexible, allowing you to retrieve and return any type of data. When writing lookup plugins, always return data of a consistent type that can be easily consumed in a playbook. Avoid parameters that change the returned data type. If there is a need to return a single value sometimes and a complex dictionary other times, write two different lookup plugins.
@ -261,13 +288,24 @@ The following is an example of how this lookup is called::
- debug:
msg: the value of foo.txt is {{ contents }} as seen today {{ lookup('pipe', 'date +"%Y-%m-%d"') }}
For more example lookup plugins, check out the source code for the lookup plugins that are included with Ansible here: `lib/ansible/plugins/lookup <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/lookup>`_.
For example lookup plugins, see the source code for the `lookup plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/lookup>`_.
For more usage examples of lookup plugins, see :ref:`Using Lookups<playbooks_lookups>`.
.. _developing_test_plugins:
Test plugins
------------
Test plugins verify data. They are a feature of Jinja2 and are also available in Jinja2 templates used by the ``template`` module. As with all plugins, they can be easily extended, but instead of having a file for each one you can have several per file. Most of the test plugins shipped with Ansible reside in a ``core.py``. These are specially useful in conjunction with some filter plugins like ``map`` and ``select``; they are also available for conditional directives like ``when:``.
Test plugins do not use the standard configuration and documentation system described above.
For example test plugins, see the source code for the `test plugins included with Ansible Core <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/test>`_.
.. _developing_vars_plugins:
Vars Plugins
Vars plugins
------------
Vars plugins inject additional variable data into Ansible runs that did not come from an inventory source, playbook, or command line. Playbook constructs like 'host_vars' and 'group_vars' work using vars plugins.
@ -292,7 +330,7 @@ Most of the work now happens in the ``get_vars`` method which is called from th
The parameters are:
* loader: Ansible's DataLoader. The DataLoader can read files, auto load JSON/YAML and decrypt vaulted data, and cache read files.
* loader: Ansible's DataLoader. The DataLoader can read files, auto-load JSON/YAML and decrypt vaulted data, and cache read files.
* path: this is 'directory data' for every inventory source and the current play's playbook directory, so they can search for data in reference to them. ``get_vars`` will be called at least once per available path.
* entities: these are host or group names that are pertinent to the variables needed. The plugin will get called once for hosts and again for groups.
@ -300,51 +338,8 @@ This ``get vars`` method just needs to return a dictionary structure with the va
Since Ansible version 2.4, vars plugins only execute as needed when preparing to execute a task. This avoids the costly 'always execute' behavior that occurred during inventory construction in older versions of Ansible.
For implementation examples of vars plugins, check out the source code for the vars plugins that are included with Ansible:
`lib/ansible/plugins/vars <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/vars>`_ .
.. _developing_filter_plugins:
Filter Plugins
--------------
Filter plugins are used for manipulating data. They are a feature of Jinja2 and are also available in Jinja2 templates used by the ``template`` module. As with all plugins, they can be easily extended, but instead of having a file for each one you can have several per file. Most of the filter plugins shipped with Ansible reside in a ``core.py``.
See `lib/ansible/plugins/filter <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/filter>`_ for details.
.. _developing_test_plugins:
Test Plugins
------------
Test plugins are for verifying data. They are a feature of Jinja2 and are also available in Jinja2 templates used by the ``template`` module. As with all plugins, they can be easily extended, but instead of having a file for each one you can have several per file. Most of the test plugins shipped with Ansible reside in a ``core.py``. These are specially useful in conjunction with some filter plugins like ``map`` and ``select``; they are also available for conditional directives like ``when:``.
See `lib/ansible/plugins/test <https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/test>`_ for details.
.. _distributing_plugins:
Distributing Plugins
--------------------
Plugins are loaded from the library installed path and the configured plugins directory (check your `ansible.cfg`).
The location can vary depending on how you installed Ansible (pip, rpm, deb, etc) or by the OS/Distribution/Packager.
Plugins are automatically loaded when you have one of the following subfolders adjacent to your playbook or inside a role:
* action_plugins
* lookup_plugins
* callback_plugins
* connection_plugins
* inventory_plugins
* filter_plugins
* strategy_plugins
* cache_plugins
* test_plugins
* shell_plugins
* vars_plugins
When shipped as part of a role, the plugin will be available as soon as the role is called in the play.
For example vars plugins, see the source code for the `vars plugins included with Ansible Core
<https://github.com/ansible/ansible/tree/devel/lib/ansible/plugins/vars>`_.
.. seealso::

View File

@ -1,8 +1,9 @@
.. _flow_modules:
.. _developing_program_flow_modules:
===========================
Ansible Module Architecture
===========================
***************************
Ansible module architecture
***************************
This in-depth dive helps you understand Ansible's program flow to execute
modules. It is written for people working on the portions of the Core Ansible
@ -10,9 +11,12 @@ Engine that execute a module. Those writing Ansible Modules may also find this
in-depth dive to be of interest, but individuals simply using Ansible Modules
will not likely find this to be helpful.
.. contents:: Topics
:local:
.. _flow_types_of_modules:
Types of Modules
Types of modules
================
Ansible supports several different types of modules in its code base. Some of
@ -20,7 +24,7 @@ these are for backwards compatibility and others are to enable flexibility.
.. _flow_action_plugins:
Action Plugins
Action plugins
--------------
Action Plugins look like modules to end users who are writing :term:`playbooks` but
@ -42,7 +46,7 @@ into its final location, sets file permissions, and so on.
.. _flow_new_style_modules:
New-style Modules
New-style modules
-----------------
All of the modules that ship with Ansible fall into this category.
@ -55,7 +59,7 @@ connections instead of only one.
.. _flow_python_modules:
Python
^^^^^^
------
New-style Python modules use the :ref:`Ansiballz` framework for constructing
modules. All official modules (shipped with Ansible) use either this or the
@ -73,7 +77,7 @@ values as :term:`JSON`, and various file operations.
.. _flow_powershell_modules:
Powershell
^^^^^^^^^^
----------
New-style powershell modules use the :ref:`module_replacer` framework for
constructing modules. These modules get a library of powershell code embedded
@ -82,7 +86,7 @@ in them before being sent to the managed node.
.. _flow_jsonargs_modules:
JSONARGS
^^^^^^^^
--------
Scripts can arrange for an argument string to be placed within them by placing
the string ``<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>`` somewhere inside of the
@ -133,7 +137,7 @@ only modifies them to change a shebang line if present.
.. _flow_binary_modules:
Binary Modules
Binary modules
--------------
From Ansible 2.2 onwards, modules may also be small binary programs. Ansible
@ -152,7 +156,7 @@ way as :ref:`want JSON modules <flow_want_json_modules>`.
.. _flow_old_style_modules:
Old-style Modules
Old-style modules
-----------------
Old-style modules are similar to
@ -176,7 +180,7 @@ the remote machine.
.. _flow_executor_task_executor:
executor/task_executor
Executor/task_executor
----------------------
The TaskExecutor receives the module name and parameters that were parsed from
@ -189,10 +193,10 @@ to that Action Plugin for further processing.
.. _flow_normal_action_plugin:
Normal Action Plugin
Normal action plugin
--------------------
The ``normal`` Action Plugin executes the module on the remote host. It is
The ``normal`` action plugin executes the module on the remote host. It is
the primary coordinator of much of the work to actually execute the module on
the managed machine.
@ -223,7 +227,7 @@ which lives in :file:`plugins/action/__init__.py`. It makes use of
.. _flow_executor_module_common:
executor/module_common.py
Executor/module_common.py
-------------------------
Code in :file:`executor/module_common.py` takes care of assembling the module
@ -248,8 +252,8 @@ Next we'll go into some details of the two assembler frameworks.
.. _module_replacer:
Module Replacer
^^^^^^^^^^^^^^^
Module Replacer framework
^^^^^^^^^^^^^^^^^^^^^^^^^
The Module Replacer framework is the original framework implementing new-style
modules. It is essentially a preprocessor (like the C Preprocessor for those
@ -310,8 +314,8 @@ substitutions:
.. _Ansiballz:
Ansiballz
^^^^^^^^^
Ansiballz framework
^^^^^^^^^^^^^^^^^^^
Ansible 2.1 switched from the :ref:`module_replacer` framework to the
Ansiballz framework for assembling modules. The Ansiballz framework differs
@ -330,7 +334,7 @@ ansible module.
.. note::
Ansible wraps the zipfile in the Python script for two reasons:
* for compatibility with Python-2.6 which has a less
* for compatibility with Python 2.6 which has a less
functional version of Python's ``-m`` command line switch.
* so that pipelining will function properly. Pipelining needs to pipe the
Python module into the Python interpreter on the remote node. Python
@ -354,7 +358,7 @@ the zipfile as well.
.. _flow_passing_module_args:
Passing args
~~~~~~~~~~~~
------------
In :ref:`module_replacer`, module arguments are turned into a JSON-ified
string and substituted into the combined module file. In :ref:`Ansiballz`,
@ -379,7 +383,7 @@ other code.
.. _flow_internal_arguments:
Internal arguments
^^^^^^^^^^^^^^^^^^
------------------
Both :ref:`module_replacer` and :ref:`Ansiballz` send additional arguments to
the module beyond those which the user specified in the playbook. These
@ -389,7 +393,7 @@ the features are implemented in :py:mod:`ansible.module_utils.basic` but certain
features need support from the module so it's good to know about them.
_ansible_no_log
~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^
This is a boolean. If it's True then the playbook specified ``no_log`` (in
a task's parameters or as a play parameter). This automatically affects calls
@ -402,7 +406,7 @@ to instantiate an `AnsibleModule` and then check the value of
``no_log`` specified in a module's argument_spec are handled by a different mechanism.
_ansible_debug
~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^
This is a boolean that turns on more verbose logging. If a module uses
:py:meth:`AnsibleModule.debug` rather than :py:meth:`AnsibleModule.log` then
@ -414,7 +418,7 @@ should do so by instantiating an `AnsibleModule` and accessing
:attr:`AnsibleModule._debug`.
_ansible_diff
~~~~~~~~~~~~~
^^^^^^^^^^^^^^^
This boolean is turned on via the ``--diff`` command line option. If a module
supports it, it will tell the module to show a unified diff of changes to be
@ -423,13 +427,13 @@ instantiating an `AnsibleModule` and accessing
:attr:`AnsibleModule._diff`.
_ansible_verbosity
~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^
This value could be used for finer grained control over logging. However, it
is currently unused.
_ansible_selinux_special_fs
~~~~~~~~~~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is a list of names of filesystems which should have a special selinux
context. They are used by the `AnsibleModule` methods which operate on
@ -452,7 +456,7 @@ filesystem names. Under Ansiballz it's an actual list.
.. versionadded:: 2.1
_ansible_syslog_facility
~~~~~~~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^^^^^^^
This parameter controls which syslog facility ansible module logs to. It may
be set by changing the ``syslog_facility`` value in :file:`ansible.cfg`. Most
@ -477,7 +481,7 @@ than it did under :ref:`module_replacer` due to how hacky the old way was
.. versionadded:: 2.1
_ansible_version
~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^
This parameter passes the version of ansible that runs the module. To access
it, a module should instantiate an `AnsibleModule` and then retrieve it
@ -489,7 +493,7 @@ from :attr:`AnsibleModule.ansible_version`. This replaces
.. _flow_special_considerations:
Special Considerations
Special considerations
----------------------
.. _flow_pipelining:
@ -528,14 +532,14 @@ Passing arguments via stdin was chosen for the following reasons:
truncation of the parameters if we hit that limit.
.. _ansiblemodule:
.. _flow_ansiblemodule:
AnsibleModule
-------------
.. _argument_spec:
Argument Spec
Argument spec
^^^^^^^^^^^^^
The ``argument_spec`` provided to ``AnsibleModule`` defines the supported arguments for a module, as well as their type, defaults and more.
@ -556,10 +560,10 @@ Example ``argument_spec``:
)
))
This section will discss the behavioral attributes for arguments
This section will discuss the behavioral attributes for arguments:
type
~~~~
""""
``type`` allows you to define the type of the value accepted for the argument. The default value for ``type`` is ``str``. Possible values are:
@ -579,17 +583,17 @@ type
The ``raw`` type, performs no type validation or type casing, and maintains the type of the passed value.
elements
~~~~~~~~
""""""""
``elements`` works in combination with ``type`` when ``type='list'``. ``elements`` can then be defined as ``elements='int'`` or any other type, indicating that each element of the specified list should be of that type.
default
~~~~~~~
"""""""
The ``default`` option allows sets a default value for the argument for the scenario when the argument is not provided to the module. When not specified, the default value is ``None``.
fallback
~~~~~~~~
""""""""
``fallback`` accepts a ``tuple`` where the first argument is a callable (function) that will be used to perform the lookup, based on the second argument. The second argument is a list of values to be accepted by the callable.
@ -600,38 +604,38 @@ Example::
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']))
choices
~~~~~~~
"""""""
``choices`` accepts a list of choices that the argument will accept. The types of ``choices`` should match the ``type``.
required
~~~~~~~~
""""""""
``required`` accepts a boolean, either ``True`` or ``False`` that indicates that the argument is required. This should not be used in combination with ``default``.
no_log
~~~~~~
""""""
``no_log`` indicates that the value of the argument should not be logged or displayed.
aliases
~~~~~~~
"""""""
``aliases`` accepts a list of alternative argument names for the argument, such as the case where the argument is ``name`` but the module accepts ``aliases=['pkg']`` to allow ``pkg`` to be interchangably with ``name``
options
~~~~~~~
"""""""
``options`` implements the ability to create a sub-argument_spec, where the sub options of the top level argument are also validated using the attributes discussed in this section. The example at the top of this section demonstrates use of ``options``. ``type`` or ``elements`` should be ``dict`` is this case.
apply_defaults
~~~~~~~~~~~~~~
""""""""""""""
``apply_defaults`` works alongside ``options`` and allows the ``default`` of the sub-options to be applied even when the top-level argument is not supplied.
In the example of the ``argument_spec`` at the top of this section, it would allow ``module.params['top_level']['second_level']`` to be defined, even if the user does not provide ``top_level`` when calling the module.
removed_in_version
~~~~~~~~~~~~~~~~~~
""""""""""""""""""
``removed_in_version`` indicates which version of Ansible a deprecated argument will be removed in.

View File

@ -1,106 +1,101 @@
.. _developing_python_3:
====================
********************
Ansible and Python 3
====================
********************
Ansible is pursuing a strategy of having one code base that runs on both
Python-2 and Python-3 because we want Ansible to be able to manage a wide
.. contents:: Topics
:local:
Ansible maintains a single code base that runs on both
Python 2 and Python 3 because we want Ansible to be able to manage a wide
variety of machines. Contributors to Ansible should be aware of the tips in
this document so that they can write code that will run on the same versions
of Python as the rest of Ansible.
Ansible can be divided into three overlapping pieces for the purposes of
porting:
To ensure that your code runs on Python 3 as well as on Python 2, learn the tips and tricks and idioms
described here. Most of these considerations apply to all three types of Ansible code:
1. Controller-side code. This is the code which runs on the machine where you
invoke :command:`/usr/bin/ansible`
2. Modules. This is the code which Ansible transmits over the wire and
invokes on the managed machine.
3. module_utils code. This is code whose primary purpose is to be used by the
modules to perform tasks. However, some controller-side code might use
generic functions from here.
1. controller-side code - code that runs on the machine where you invoke :command:`/usr/bin/ansible`
2. modules - the code which Ansible transmits to and invokes on the managed machine.
3. shared ``module_utils`` code - the common code that's used by modules to perform tasks and sometimes used by controller-side code as well
Much of the knowledge of porting code will be usable on all three of these
pieces but there are some special considerations for some of it as well.
Information that is generally applicable to all three places is located in the
controller-side section.
However, the three types of code do not use the same string strategy. If you're developing a module or some ``module_utils`` code, be sure
to read the section on string strategy carefully.
--------------------------------------------
Minimum Version of Python-3.x and Python-2.x
--------------------------------------------
Minimum version of Python 3.x and Python 2.x
============================================
On the controller we support Python-3.5 or greater and Python-2.7 or greater. Module-side, we
support Python-3.5 or greater and Python-2.6 or greater.
On the controller we support Python 3.5 or greater and Python 2.7 or greater. Module-side, we
support Python 3.5 or greater and Python 2.6 or greater.
Python-3.5 was chosen as a minimum because it is the earliest Python-3 version adopted as the
Python 3.5 was chosen as a minimum because it is the earliest Python 3 version adopted as the
default Python by a Long Term Support (LTS) Linux distribution (in this case, Ubuntu-16.04).
Previous LTS Linux distributions shipped with a Python-2 version which users can rely upon instead
of the Python-3 version.
Previous LTS Linux distributions shipped with a Python 2 version which users can rely upon instead
of the Python 3 version.
For Python 2, the default is for modules to run on at least Python-2.6. This allows
users with older distributions that are stuck on Python-2.6 to manage their
machines. Modules are allowed to drop support for Python-2.6 when one of
their dependent libraries requires a higher version of Python. This is not an
For Python 2, the default is for modules to run on at least Python 2.6. This allows
users with older distributions that are stuck on Python 2.6 to manage their
machines. Modules are allowed to drop support for Python 2.6 when one of
their dependent libraries requires a higher version of Python. This is not an
invitation to add unnecessary dependent libraries in order to force your
module to be usable only with a newer version of Python; instead it is an
acknowledgment that some libraries (for instance, boto3 and docker-py) will
only function with a newer version of Python.
.. note:: Python-2.4 Module-side Support:
.. note:: Python 2.4 Module-side Support:
Support for Python-2.4 and Python-2.5 was dropped in Ansible-2.4. RHEL-5
Support for Python 2.4 and Python 2.5 was dropped in Ansible-2.4. RHEL-5
(and its rebuilds like CentOS-5) were supported until April of 2017.
Ansible-2.3 was released in April of 2017 and was the last Ansible release
to support Python-2.4 on the module-side.
to support Python 2.4 on the module-side.
-----------------------------------
Porting Controller Code to Python 3
-----------------------------------
Developing Ansible code that supports Python 2 and Python 3
===========================================================
Most of the general tips for porting code to be used on both Python-2 and
Python-3 applies to porting controller code. The best place to start learning
to port code is `Lennart Regebro's book: Porting to Python 3 <http://python3porting.com/>`_.
The best place to start learning about writing code that supports both Python 2 and Python 3
is `Lennart Regebro's book: Porting to Python 3 <http://python3porting.com/>`_.
The book describes several strategies for porting to Python 3. The one we're
using is `to support Python 2 and Python 3 from a single code base
<http://python3porting.com/strategies.html#python 2-and-python 3-without-conversion>`_
The book describes several strategies for porting to Python 3. The one we're
using is `to support Python-2 and Python-3 from a single code base
<http://python3porting.com/strategies.html#python-2-and-python-3-without-conversion>`_
Understanding strings in Python 2 and Python 3
----------------------------------------------
Controller String Strategy
==========================
Background
----------
One of the most essential things to decide upon for porting code to Python-3
is what string model to use. Strings can be an array of bytes (like in C) or
Python 2 and Python 3 handle strings differently, so when you write code that supports Python 3
you must decide what string model to use. Strings can be an array of bytes (like in C) or
they can be an array of text. Text is what we think of as letters, digits,
numbers, other printable symbols, and a small number of unprintable "symbols"
(control codes).
In Python-2, the two types for these (:class:`str` for bytes and
In Python 2, the two types for these (:class:`str` for bytes and
:class:`unicode` for text) are often used interchangeably. When dealing only
with ASCII characters, the strings can be combined, compared, and converted
from one type to another automatically. When non-ASCII characters are
introduced, Python starts throwing exceptions due to not knowing what encoding
introduced, Python 2 starts throwing exceptions due to not knowing what encoding
the non-ASCII characters should be in.
Python-3 changes this behavior by making the separation between bytes (:class:`bytes`)
and text (:class:`str`) more strict. Python will throw an exception when
Python 3 changes this behavior by making the separation between bytes (:class:`bytes`)
and text (:class:`str`) more strict. Python 3 will throw an exception when
trying to combine and compare the two types. The programmer has to explicitly
convert from one type to the other to mix values from each.
This change makes it immediately apparent to the programmer when code is
mixing the types inappropriately, rather than working until one of their users
causes an exception by entering non-ASCII input. However, it forces the
programmer to proactively define a strategy for working with strings in their
program so that they don't mix text and byte strings unintentionally.
In Python 3 it's immediately apparent to the programmer when code is
mixing the byte and text types inappropriately, whereas in Python 2, code that mixes those types
may work until a user causes an exception by entering non-ASCII input.
Python 3 forces programmers to proactively define a strategy for
working with strings in their program so that they don't mix text and byte strings unintentionally.
Unicode Sandwich
----------------
Ansible uses different strategies for working with strings in controller-side code, in
:ref: `modules <module_string_strategy>`, and in :ref:`module_utils <module_utils_string_strategy>` code.
.. _controller_string_strategy:
Controller string strategy: the Unicode Sandwich
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In controller-side code we use a strategy known as the Unicode Sandwich (named
after Python-2's :class:`unicode` text type). For Unicode Sandwich we know that
after Python 2's :class:`unicode` text type). For Unicode Sandwich we know that
at the border of our code and the outside world (for example, file and network IO,
environment variables, and some library calls) we are going to receive bytes.
We need to transform these bytes into text and use that throughout the
@ -109,17 +104,18 @@ the outside world we first convert the text back into bytes.
To visualize this, imagine a 'sandwich' consisting of a top and bottom layer
of bytes, a layer of conversion between, and all text type in the center.
Common Borders
--------------
Unicode Sandwich common borders: places to convert bytes to text in controller code
-----------------------------------------------------------------------------------
This is a partial list of places where we have to convert to and from bytes.
It's not exhaustive but gives you an idea of where to watch for problems.
This is a partial list of places where we have to convert to and from bytes
when using the Unicode Sandwich string strategy. It's not exhaustive but
it gives you an idea of where to watch for problems.
Reading and writing to files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In Python-2, reading from files yields bytes. In Python-3, it can yield text.
To make code that's portable to both we don't make use of Python-3's ability
In Python 2, reading from files yields bytes. In Python 3, it can yield text.
To make code that's portable to both we don't make use of Python 3's ability
to yield text but instead do the conversion explicitly ourselves. For example:
.. code-block:: python
@ -153,14 +149,14 @@ Note that we don't have to catch :exc:`UnicodeError` here because we're
transforming to UTF-8 and all text strings in Python can be transformed back
to UTF-8.
Filesystem Interaction
~~~~~~~~~~~~~~~~~~~~~~
Filesystem interaction
^^^^^^^^^^^^^^^^^^^^^^
Dealing with filenames often involves dropping back to bytes because on UNIX-like
systems filenames are bytes. On Python-2, if we pass a text string to these
systems filenames are bytes. On Python 2, if we pass a text string to these
functions, the text string will be converted to a byte string inside of the
function and a traceback will occur if non-ASCII characters are present. In
Python-3, a traceback will only occur if the text string can't be decoded in
Python 3, a traceback will only occur if the text string can't be decoded in
the current locale, but it's still good to be explicit and have code which
works on both versions:
@ -198,30 +194,75 @@ and manipulate in bytes.
all the types are the same (either all bytes or all text). Mixing
bytes and text will cause tracebacks.
Interacting with Other Programs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interacting with other programs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interacting with other programs goes through the operating system and
C libraries and operates on things that the UNIX kernel defines. These
interfaces are all byte-oriented so the Python interface is byte oriented as
well. On both Python-2 and Python-3, byte strings should be given to Python's
well. On both Python 2 and Python 3, byte strings should be given to Python's
subprocess library and byte strings should be expected back from it.
One of the main places in Ansible's controller code that we interact with
other programs is the connection plugins' ``exec_command`` methods. These
methods transform any text strings they receive in the command (and arguments
to the command) to execute into bytes and return stdout and stderr as byte strings
to the command) to execute into bytes and return stdout and stderr as byte strings
Higher level functions (like action plugins' ``_low_level_execute_command``)
transform the output into text strings.
Tips, tricks, and idioms to adopt
=================================
.. _module_string_strategy:
Forwards Compatibility Boilerplate
----------------------------------
Module string strategy: Native String
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use the following boilerplate code at the top of all controller-side modules
to make certain constructs act the same way on Python-2 and Python-3:
In modules we use a strategy known as Native Strings. This makes things
easier on the community members who maintain so many of Ansible's
modules, by not breaking backwards compatibility by
mandating that all strings inside of modules are text and converting between
text and bytes at the borders.
Native strings refer to the type that Python uses when you specify a bare
string literal:
.. code-block:: python
"This is a native string"
In Python 2, these are byte strings. In Python 3 these are text strings. Modules should be
coded to expect bytes on Python 2 and text on Python 3.
.. _module_utils_string_strategy:
Module_utils string strategy: hybrid
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In ``module_utils`` code we use a hybrid string strategy. Although Ansible's
``module_utils`` code is largely like module code, some pieces of it are
used by the controller as well. So it needs to be compatible with modules
and with the controller's assumptions, particularly the string strategy.
The module_utils code attempts to accept native strings as input
to its functions and emit native strings as their output.
In ``module_utils`` code:
* Functions **must** accept string parameters as either text strings or byte strings.
* Functions may return either the same type of string as they were given or the native string type for the Python version they are run on.
* Functions that return strings **must** document whether they return strings of the same type as they were given or native strings.
Module-utils functions are therefore often very defensive in nature.
They convert their string parameters into text (using ``ansible.module_utils._text.to_text``)
at the beginning of the function, do their work, and then convert
the return values into the native string type (using ``ansible.module_utils._text.to_native``)
or back to the string type that their parameters received.
Tips, tricks, and idioms for Python 2/Python 3 compatibility
------------------------------------------------------------
Use forward-compatibility boilerplate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use the following boilerplate code at the top of all python files
to make certain constructs act the same way on Python 2 and Python 3:
.. code-block:: python
@ -247,8 +288,8 @@ The ``__future__`` imports do the following:
* `PEP 0238: Division <https://www.python.org/dev/peps/pep-0238>`_
* `PEP 3105: Print function <https://www.python.org/dev/peps/pep-3105>`_
Prefix byte strings with "b\_"
------------------------------
Prefix byte strings with ``b\_``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since mixing text and bytes types leads to tracebacks we want to be clear
about what variables hold text and what variables hold bytes. We do this by
@ -265,11 +306,11 @@ We do not prefix the text strings instead because we only operate
on byte strings at the borders, so there are fewer variables that need bytes
than text.
Bundled six
-----------
Import Ansible's bundled ``python-six`` library
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The third-party `python-six <https://pythonhosted.org/six/>`_ library exists
to help projects create code that runs on both Python-2 and Python-3. Ansible
to help projects create code that runs on both Python 2 and Python 3. Ansible
includes a version of the library in module_utils so that other modules can use it
without requiring that it is installed on the remote system. To make use of
it, import it like this:
@ -283,10 +324,10 @@ it, import it like this:
Ansible will use a system copy of six if the system copy is a later
version than the one Ansible bundles.
Exceptions
----------
Handle exceptions with ``as``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In order for code to function on Python-2.6+ and Python-3, use the
In order for code to function on Python 2.6+ and Python 3, use the
new exception-catching syntax which uses the ``as`` keyword:
.. code-block:: python
@ -296,7 +337,7 @@ new exception-catching syntax which uses the ``as`` keyword:
except ValueError as e:
module.fail_json(msg="Tried to divide by zero: %s" % e)
Do **not** use the following syntax as it will fail on every version of Python-3:
Do **not** use the following syntax as it will fail on every version of Python 3:
.. This code block won't highlight because python2 isn't recognized. This is necessary to pass tests under python 3.
.. code-block:: none
@ -306,25 +347,25 @@ Do **not** use the following syntax as it will fail on every version of Python-3
except ValueError, e:
module.fail_json(msg="Tried to divide by zero: %s" % e)
Octal numbers
-------------
Update octal numbers
^^^^^^^^^^^^^^^^^^^^
In Python-2.x, octal literals could be specified as ``0755``. In Python-3,
In Python 2.x, octal literals could be specified as ``0755``. In Python 3,
octals must be specified as ``0o755``.
String formatting
-----------------
String formatting for controller code
-------------------------------------
str.format() compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~~
Use ``str.format()`` for Python 2.6 compatibility
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Starting in Python-2.6, strings gained a method called ``format()`` to put
Starting in Python 2.6, strings gained a method called ``format()`` to put
strings together. However, one commonly used feature of ``format()`` wasn't
added until Python-2.7, so you need to remember not to use it in Ansible code:
added until Python 2.7, so you need to remember not to use it in Ansible code:
.. code-block:: python
# Does not work in Python-2.6!
# Does not work in Python 2.6!
new_string = "Dear {}, Welcome to {}".format(username, location)
# Use this instead
@ -332,120 +373,40 @@ added until Python-2.7, so you need to remember not to use it in Ansible code:
Both of the format strings above map positional arguments of the ``format()``
method into the string. However, the first version doesn't work in
Python-2.6. Always remember to put numbers into the placeholders so the code
is compatible with Python-2.6.
Python 2.6. Always remember to put numbers into the placeholders so the code
is compatible with Python 2.6.
.. seealso::
Python documentation on `format strings <https://docs.python.org/2/library/string.html#formatstrings>`_
Use percent format with byte strings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In Python-3.x, byte strings do not have a ``format()`` method. However, it
In Python 3.x, byte strings do not have a ``format()`` method. However, it
does have support for the older, percent-formatting.
.. code-block:: python
b_command_line = b'ansible-playbook --become-user %s -K %s' % (user, playbook_file)
.. note:: Percent formatting added in Python-3.5
.. note:: Percent formatting added in Python 3.5
Percent formatting of byte strings was added back into Python3 in 3.5.
This isn't a problem for us because Python-3.5 is our minimum version.
However, if you happen to be testing Ansible code with Python-3.4 or
Percent formatting of byte strings was added back into Python 3 in 3.5.
This isn't a problem for us because Python 3.5 is our minimum version.
However, if you happen to be testing Ansible code with Python 3.4 or
earlier, you will find that the byte string formatting here won't work.
Upgrade to Python-3.5 to test.
Upgrade to Python 3.5 to test.
.. seealso::
Python documentation on `percent formatting <https://docs.python.org/2/library/stdtypes.html#string-formatting>`_
---------------------------
Porting Modules to Python 3
---------------------------
.. _testing_modules_python_3:
Ansible modules are slightly harder to port than normal code from other
projects. A lot of mocking has to go into unit testing an Ansible module so
it's harder to test that your porting has fixed everything or to to make sure
that later commits haven't regressed the Python-3 support.
Testing modules on Python 3
===================================
Module String Strategy
======================
There are a large number of modules in Ansible. Most of those are maintained
by the Ansible community at large, not by a centralized team. To make life
easier on them, it was decided not to break backwards compatibility by
mandating that all strings inside of modules are text and converting between
text and bytes at the borders; instead, we're using a native string strategy
for now.
Native strings refer to the type that Python uses when you specify a bare
string literal:
.. code-block:: python
"This is a native string"
In Python-2, these are byte strings. In Python-3 these are text strings. The
module_utils shipped with Ansible attempts to accept native strings as input
to its functions and emit native strings as their output. Modules should be
coded to expect bytes on Python-2 and text on Python-3.
Tips, tricks, and idioms to adopt
=================================
Python-2.4 Compatible Exception Syntax
--------------------------------------
Until Ansible-2.4, modules needed to be compatible with Python-2.4 as
well. Python-2.4 did not understand the new exception-catching syntax so
we had to write a compatibility function that could work with both
Python-2 and Python-3. You may still see this used in some modules:
.. code-block:: python
from ansible.module_utils.pycompat24 import get_exception
try:
a = 2/0
except ValueError:
e = get_exception()
module.fail_json(msg="Tried to divide by zero: %s" % e)
Unless a change is going to be backported to Ansible-2.3, you should not
have to use this in new code.
Python 2.4 octal workaround
---------------------------
Before Ansible-2.4, modules had to be compatible with Python-2.4.
Python-2.4 did not understand the new syntax for octal literals so we used
the following workaround to specify octal values:
.. code-block:: python
# Can't use 0755 on Python-3 and can't use 0o755 on Python-2.4
EXECUTABLE_PERMS = int('0755', 8)
Unless a change is going to be backported to Ansible-2.3, you should not
have to use this in new code.
-------------------------------------
Porting module_utils code to Python 3
-------------------------------------
module_utils code is largely like module code. However, some pieces of it are
used by the controller as well. Because of this, it needs to be usable with
the controller's assumptions. This is most notable in the string strategy.
Module_utils String Strategy
============================
Module_utils **must** use the Native String Strategy. Functions in
module_utils receive either text strings or byte strings and may emit either
the same type as they were given or the native string for the Python version
they are run on depending on which makes the most sense for that function.
Functions which return strings **must** document whether they return text,
byte, or native strings. Module-utils functions are therefore often very
defensive in nature, converting from potential text or bytes at the
beginning of a function and converting to the native string type at the end.
Ansible modules are slightly harder to code to support Python 3 than normal code from other
projects. A lot of mocking has to go into unit testing an Ansible module, so
it's harder to test that your changes have fixed everything or to to make sure
that later commits haven't regressed the Python 3 support. Review our :ref:`testing <developing_testing>` pages
for more information.

View File

@ -1,5 +1,6 @@
Rebasing a Pull Request
```````````````````````
***********************
Rebasing a pull request
***********************
You may find that your pull request (PR) is out-of-date and needs to be rebased. This can happen for several reasons:
@ -8,8 +9,8 @@ You may find that your pull request (PR) is out-of-date and needs to be rebased.
Rebasing the branch used to create your PR will resolve both of these issues.
Configuring Your Remotes
++++++++++++++++++++++++
Configuring your remotes
========================
Before you can rebase your PR, you need to make sure you have the proper remotes configured.
Assuming you cloned your fork in the usual fashion, the ``origin`` remote will point to your fork::
@ -37,8 +38,8 @@ Checking the status of your branch should show you're up-to-date with your fork
Your branch is up-to-date with 'origin/YOUR_BRANCH'.
nothing to commit, working tree clean
Rebasing Your Branch
++++++++++++++++++++
Rebasing your branch
====================
Once you have an ``upstream`` remote configured, you can rebase the branch for your PR::
@ -59,8 +60,8 @@ Once you've rebased, the status of your branch will have changed::
Don't worry, this is normal after a rebase. You should ignore the ``git status`` instructions to use ``git pull``.
We'll cover what to do next in the following section.
Updating Your Pull Request
++++++++++++++++++++++++++
Updating your pull request
==========================
Now that you've rebased your branch, you need to push your changes to GitHub to update your PR.
@ -71,8 +72,13 @@ Since rebasing re-writes git history, you will need to use a force push::
Your PR on GitHub has now been updated. This will automatically trigger testing of your changes.
You should check in on the status of your PR after tests have completed to see if further changes are required.
Getting Help Rebasing
+++++++++++++++++++++
Getting help rebasing
=====================
For help with rebasing your PR, or other development related questions, join us on our #ansible-devel IRC chat channel
on `freenode.net <https://freenode.net>`_.
.. seealso::
:ref:`community_development_process`
Information on roadmaps, opening PRs, Ansibullbot, and more

View File

@ -4,26 +4,65 @@ Developer Guide
Welcome to the Ansible Developer Guide!
The purpose of this guide is to document all of the paths available to you for interacting and shaping Ansible with code, ranging from developing modules and plugins to helping to develop the Ansible Core Engine via pull requests.
**Who should use this guide?**
To get started, select one of the following topics.
If you want to extend Ansible by using a custom module or plugin locally, creating a module or plugin, adding functionality to an existing module, or expanding test coverage, this guide is for you. We've included detailed information for developers on how to test and document modules, as well as the prerequisites for getting your module or plugin accepted into the main Ansible repository.
Find the task that best describes what you want to do:
* I'm looking for a way to address a use case:
* I want to :ref:`add a custom plugin or module locally <developing_locally>`.
* I want to figure out if :ref:`developing a module is the right approach <module_dev_should_you>` for my use case.
* I'm ready to start developing:
* I want to :ref:`set up my Python development environment <environment_setup>`.
* I want to :ref:`get started writing a module <developing_modules_general>`.
* I want to :ref:`write a Windows module <developing_modules_general_windows>`.
* I want to :ref:`write a series of related modules <developing_modules_in_groups>` that integrate Ansible with a new product (for example, a database, cloud provider, network platform, etc.).
* I want to refine my code:
* I want to :ref:`debug my module code <debugging>`.
* I want to :ref:`test my module <developing_testing>`.
* I want to :ref:`document my module <module_documenting>`.
* I want to :ref:`make sure my code runs on Python 2 and Python 3 <developing_python_3>`.
* I want to work on other development projects:
* I want to :ref:`write a plugin <developing_plugins>`.
* I want to :ref:`connect Ansible to a new source of inventory <developing_inventory>`.
* I want to :ref:`deprecate an outdated module <deprecating_modules>`.
* I want to contribute back to the Ansible project:
* I want to :ref:`contribute my module or plugin <developing_modules_checklist>`.
* I want to :ref:`understand the license agreement <contributor_license_agreement>` for contributions to Ansible.
If you prefer to read the entire guide, here's a list of the pages in order.
.. toctree::
:maxdepth: 2
overview_architecture
developing_locally
developing_modules
developing_program_flow_modules
developing_module_utilities
developing_modules_general
developing_modules_checklist
developing_modules_best_practices
developing_python_3
debugging
developing_modules_documenting
developing_modules_general_windows
developing_modules_general_aci
developing_modules_in_groups
testing
module_lifecycle
developing_plugins
developing_inventory
developing_core
developing_python_3
developing_program_flow_modules
developing_api
developing_rebasing
testing
repomerge
../reference_appendices/release_and_maintenance
../community/committer_guidelines
./style_guide/index
developing_module_utilities
overview_architecture

View File

@ -0,0 +1,46 @@
.. _module_lifecycle:
**********************************
The lifecycle of an Ansible module
**********************************
Modules in the main Ansible repo have a defined life cycle, from first introduction to final removal. The module life cycle is tied to the `Ansible release cycle <release_cycle>` and reflected in the :ref:`ansible_metadata_block`. A module may move through these four states:
1. When a module is first accepted into Ansible, we consider it in tech preview and mark it ``preview``. Modules in ``preview`` are not stable. You may change the parameters or dependencies, expand or reduce the functionality of ``preview`` modules. Many modules remain ``preview`` for years.
2. If a module matures, we may mark it ``stableinterface`` and commit to maintaining its parameters, dependencies, and functionality. We support (though we cannot guarantee) backwards compatibility for ``stableinterface`` modules, which means their parameters should be maintained with stable meanings.
3. If a module's target API changes radically, or if someone creates a better implementation of its functionality, we may mark it ``deprecated``. Modules that are ``deprecated`` are still available but they are reaching the end of their life cycle. We retain deprecated modules for 4 release cycles with deprecation warnings to help users update playbooks and roles that use them.
4. When a module has been deprecated for four release cycles, we remove the code and mark the stub file ``removed``. Modules that are ``removed`` are no longer shipped with Ansible. The stub file helps users find alternative modules.
.. _deprecating_modules:
Deprecating modules
===================
To deprecate a module, you must:
1. Rename the file so it starts with an ``_``, for example, rename ``old_cloud.py`` to ``_old_cloud.py``. This keeps the module available and marks it as deprecated on the module index pages.
2. Mention the deprecation in the relevant ``CHANGELOG``.
3. Reference the deprecation in the relevant ``porting_guide_x.y.rst``.
4. Update ``ANSIBLE_METADATA`` to contain ``status: ['deprecated']``.
5. Add ``deprecated:`` to the documentation with the following sub-values:
:removed_in: A ``string``, such as ``"2.9"``; the version of Ansible where the module will be replaced with a docs-only module stub. Usually current release +4.
:why: Optional string that used to detail why this has been removed.
:alternative: Inform users they should do instead, i.e. ``Use M(whatmoduletouseinstead) instead.``.
* For an example of documenting deprecation, see this `PR that deprecates multiple modules <https://github.com/ansible/ansible/pull/43781/files>`_.
Changing a module name
======================
You can also rename a module and keep an alias to the old name by using a symlink that starts with _.
This example allows the ``stat`` module to be called with ``fileinfo``, making the following examples equivalent::
EXAMPLES = '''
ln -s stat.py _fileinfo.py
ansible -m stat -a "path=/tmp" localhost
ansible -m fileinfo -a "path=/tmp" localhost
'''

View File

@ -1,5 +1,6 @@
********************
Ansible Architecture
====================
********************
Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
@ -10,18 +11,19 @@ It uses no agents and no additional custom security infrastructure, so it's easy
In this section, we'll give you a really quick overview of how Ansible works so you can see how the pieces fit together.
Modules
`````````````````
=======
Ansible works by connecting to your nodes and pushing out small programs, called "Ansible Modules" to them. These programs are written to be resource models of the desired state of the system. Ansible then executes these modules (over SSH by default), and removes them when finished.
Your library of modules can reside on any machine, and there are no servers, daemons, or databases required. Typically you'll work with your favorite terminal program, a text editor, and probably a version control system to keep track of changes to your content.
Plugins
``````````````````
=======
Plugins are pieces of code that augment Ansible's core functionality. Ansible ships with a number of handy plugins, and you can easily write your own.
Inventory
````````````````````
=========
By default, Ansible represents what machines it manages using a very simple INI file that puts all of your managed machines in groups of your own choosing.
@ -45,7 +47,7 @@ Once inventory hosts are listed, variables can be assigned to them in simple tex
Or, as already mentioned, use a dynamic inventory to pull your inventory from data sources like EC2, Rackspace, or OpenStack.
Playbooks
````````````````````
=========
Playbooks can finely orchestrate multiple slices of your infrastructure topology, with very detailed control over how many machines to tackle at a time. This is where Ansible starts to get most interesting.
@ -66,7 +68,7 @@ Here's what a simple playbook looks like::
- content
Extending Ansible with Plug-ins and the API
````````````````````````````````````````````
Extending Ansible with plug-ins and the API
===========================================
Should you want to write your own, Ansible modules can be written in any language that can return JSON (Ruby, Python, bash, etc). Inventory can also plug in to any datasource by writing a program that speaks to that datasource and returns JSON. There's also various Python APIs for extending Ansible's connection types (SSH is not the only transport possible), callbacks (how Ansible logs, etc), and even for adding new server side behaviors.

View File

@ -1,29 +0,0 @@
==========
Repo Merge
==========
Background
----------
On Tuesday 6th December 2016, the Ansible Core Team re-merged the module repositories back into `ansible/ansible <https://github.com/ansible/ansible/>`_ in GitHub. The two module repos will be essentially locked, though they will be kept in place for the existing 2.1 and 2.2 dependencies. Once 2.2 moves out of official support (early 2018), these repositories will be fully readonly for all branches. Until then, any issues/PRs opened there will be auto-closed with a note to open it on `ansible/ansible <https://github.com/ansible/ansible/>`_.
Why Are We Doing This (Again...)?
-----------------------------------
For those who've been using Ansible long enough, you know that originally we started with a single repository. The original intention of the core vs. extras split was that core would be better supported/tested/etc. Extras would have been a bit more of a "wild-west" for modules, to allow new modules to make it into the distribution more quickly. Unfortunately this never really worked out, as well as the following:
1. Many modules in the core repo were also essentially "grand-fathered" in, despite not having a good set of tests or dedicated maintainers from the community.
2. The time in queue for modules to be merged into extras was not really any different from the time to merge modules into core.
3. The split introduced a few other problems for contributors such as having to submit multiple related PRs for modules with tests, or for those which rely on action plugins.
4. git submodules are notoriously complicated, even for contributors with decent git experience. The constant need to update git submodule pointers for devel and each stable branch can lead to testing surprises and really buys us nothing in terms of flexibility.
5. Users can already be confused about where to open issues, especially when the problem appears to be with a module but is actually an action plugin (ie. template) or something more fundamental like includes. Having everything back in one repo makes it easier to link issues, and you're always sure to open a bug report in the right place.
Metadata - Support/Ownership and Module Status
----------------------------------------------------------------------
As part of this move, we will be introducing module metadata, which will contain a couple of pieces of information regarding modules:
1. Support Status: This field indicates who supports the module, whether it's the core team, the community, the person who wrote it, or if it is an abandoned module which is not receiving regular updates. The Ansible team has gone through the list of modules and we have marked about 100 of them as "Core Supported", meaning a member of the Ansible core team should be actively fixing bugs on those modules. The vast majority of the rest will be community supported. This is not really a change from the status quo, this just makes it clearer.
2. Module Status: This field indicates how well supported that module may be. This generally applies to the maturity of the module's parameters, however, not necessarily its bug status.
The documentation pages for modules will be updated to reflect the above information as well, so that users can evaluate the status of a module before committing to using it in playbooks and roles.

View File

@ -0,0 +1,8 @@
.. note::
**LICENSING REQUIREMENTS** Ansible enforces the following licensing requirements:
* Utilities (files in ``lib/ansible/module_utils/``) may have one of two licenses:
* A ``module_util`` used **only** for a specific vendor's hardware, provider, or service may be licensed under GPLv3+.
* All other ``module_utils`` must be licensed under BSD, so GPL-licensed third-party and Galaxy modules can use them.
* If there's doubt about the appropriate license for a ``module_util``, the Ansible Core Team will decide during an Ansible Core Community Meeting.
* All other files shipped with Ansible, including all modules, must be licensed under the GPL license (GPLv3 or later).

View File

@ -3,29 +3,29 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
====================================
*******************
Ansible Style Guide
====================================
*******************
.. Welcome to Ansible Style Guide's documentation! ===============================================
Welcome to the Ansible Style Guide
==================================
Follow these guidelines to create clear, concise, useful community contributions and documentation. This guide helps us make the content on ansible.com consistent.
.. toctree::
:maxdepth: 1
:numbered:
self
why_use
resources
basic_rules
voice_style
trademarks
grammar_punctuation
spelling_word_choice
spelling_word_choice
resources
.. Indices and tables
.. ==================
.. * :ref:`genindex`
.. * :ref:`modindex`
.. Indices and tables
.. ==================
.. * :ref:`genindex`
.. * :ref:`modindex`
.. * :ref:`search`

View File

@ -1,3 +1,5 @@
:orphan:
Why Use a Style Guide?
`````````````````````````````````
@ -15,7 +17,7 @@ This style guide incorporates current Ansible resources and information so that
"If you don't find it in the index, look very carefully through the entire catalogue."
― Sears, Roebuck and Co., 1897 Sears Roebuck & Co. Catalogue
.. raw:: html
</blockquote>

View File

@ -1,8 +1,11 @@
.. _developing_testing:
***************
Testing Ansible
***************
.. contents:: Topics
:local:
Introduction
============
@ -19,17 +22,17 @@ Types of tests
At a high level we have the following classifications of tests:
:compile:
* :doc:`testing_compile`
* :ref:`testing_compile`
* Test python code against a variety of Python versions.
:sanity:
* :doc:`testing_sanity`
* :ref:`testing_sanity`
* Sanity tests are made up of scripts and tools used to perform static code analysis.
* The primary purpose of these tests is to enforce Ansible coding standards and requirements.
:integration:
* :doc:`testing_integration`
* :ref:`testing_integration`
* Functional tests of modules and Ansible core functionality.
:units:
* :doc:`testing_units`
* :ref:`testing_units`
* Tests directly against individual parts of the code base.

View File

@ -1,3 +1,5 @@
:orphan:
Sanity Tests » ansible-var-precedence-check
===========================================

View File

@ -1,3 +1,5 @@
:orphan:
Sanity Tests » docs-build
=========================

View File

@ -42,6 +42,7 @@ Aliases can be used to skip platforms using one of the following:
- ``skip/freebsd`` - Skip tests on FreeBSD.
- ``skip/osx`` - Skip tests on macOS.
- ``skip/rhel`` - Skip tests on RHEL.
- ``skip/docker`` - Skip tests when running on a Docker container
Aliases can be used to skip Python major versions using one of the following:

View File

@ -2,8 +2,8 @@ Sanity Tests » no-get-exception
===============================
We created a function, ``ansible.module_utils.pycompat24.get_exception`` to
help retrieve exceptions in a manner compatible with Python-2.4 through
Python-3.6. We no longer support Python-2.4 and Python-2.5 so this is
help retrieve exceptions in a manner compatible with Python 2.4 through
Python 3.6. We no longer support Python 2.4 and Python 2.5 so this is
extraneous and we want to deprecate the function. Porting code should look
something like this:

View File

@ -1,3 +1,5 @@
:orphan:
Sanity Tests » no-wildcard-import
=================================

View File

@ -1,3 +1,5 @@
:orphan:
Sanity Tests » pylint-ansible-test
==================================

View File

@ -1,3 +1,7 @@
:orphan:
.. _testing_compile:
*************
Compile Tests
*************

View File

@ -0,0 +1,26 @@
:orphan:
.. _testing_documentation:
*********************
Testing documentation
*********************
Before you submit a module for inclusion in the main Ansible repo, you must test your documentation for correct HTML rendering and to ensure that the argspec matches the documentation.
To check the HTML output of your module documentation:
#. Save your completed module file into the correct directory: ``lib/ansible/modules/$CATEGORY/my_code.py``.
#. Move to the docsite directory: ``cd /path/to/ansible/docs/docsite/``.
#. Run the command to build the docs for your module: ``MODULES=my_code make webdocs``.
#. View the HTML page at ``file:///path/to/ansible/docs/docsite/_build/html/my_code_module.html``.
To build the HTML documentation for multiple modules, use a comma-separated list of module names: ``MODULES=my_code,my_other_code make webdocs``.
To ensure that your documentation matches your ``argument_spec``, run the ``validate-modules`` test.
.. code-block:: bash
# If you don't already, ensure you are using your local checkout
source hacking/env-setup
./test/sanity/validate-modules/validate-modules --arg-spec --warnings lib/ansible/modules/$CATEGORY/my_code.py

View File

@ -1,3 +1,5 @@
:orphan:
**********
httptester
**********

View File

@ -1,3 +1,7 @@
:orphan:
.. _testing_integration:
*****************
Integration tests
*****************

View File

@ -1,105 +0,0 @@
*******************************************
Testing using the Legacy Integration system
*******************************************
.. contents:: Topics
This page details how to run the integration tests that haven't been ported to the new ``ansible-test`` framework.
The following areas are still tested using the legacy ``make tests`` command:
* amazon (some)
* azure
* cloudflare
* cloudscale
* cloudstack
* consul
* exoscale
* gce
* jenkins
* rackspace
Over time the above list will be reduced as tests are ported to the ``ansible-test`` framework.
Running Cloud Tests
====================
Cloud tests exercise capabilities of cloud modules (e.g. ec2_key). These are
not 'tests run in the cloud' so much as tests that leverage the cloud modules
and are organized by cloud provider.
Some AWS tests may use environment variables. It is recommended to either unset any AWS environment variables( such as ``AWS_DEFAULT_PROFILE``, ``AWS_SECRET_ACCESS_KEY``, etc) or be sure that the environment variables match the credentials provided in ``credentials.yml`` to ensure the tests run with consistency to their full capability on the expected account. See `AWS CLI docs <https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html>`_ for information on creating a profile.
Subsets of tests may be run by ``#commenting`` out unnecessary roles in the appropriate playbook, such as ``test/integration/amazon.yml``.
In order to run cloud tests, you must provide access credentials in a file
named ``credentials.yml``. A sample credentials file named
``credentials.template`` is available for syntax help.
Provide cloud credentials::
cp credentials.template credentials.yml
${EDITOR:-vi} credentials.yml
Other configuration
===================
In order to run some tests, you must provide access credentials in a file named
``credentials.yml``. A sample credentials file named ``credentials.template`` is available
for syntax help.
IAM policies for AWS
====================
In order to run the tests in an AWS account ansible needs fairly wide ranging powers which
can be provided to a dedicated user or temporary credentials using a specific policy
configured in the AWS account.
testing-iam-policy.json.j2
--------------------------
The testing-iam-policy.json.j2 file contains a policy which can be given to the user
running the tests to give close to minimum rights required to run the tests. Please note
that this does not fully restrict the user; The user has wide privileges for viewing
account definitions and is also able to manage some resources that are not related to
testing (e.g. AWS lambdas with different names) primarily due to the limitations of the
Amazon ARN notation. At the very least the policy limits the user to one region, however
tests should not be run in a primary production account in any case.
Other Definitions required
--------------------------
Apart from installing the policy and giving it to the user identity running
the tests, a lambda role `ansible_integration_tests` has to be created which
has lambda basic execution privileges.
Running Tests
=============
The tests are invoked via a ``Makefile``.
If you haven't already got Ansible available use the local checkout by doing::
source hacking/env-setup
Run the tests by doing::
cd test/integration/
# TARGET is the name of the test from the list at the top of this page
#make TARGET
# e.g.
make amazon
# To run all cloud tests you can do:
make cloud
.. warning:: Possible cost of running cloud tests
Running cloud integration tests will create and destroy cloud
resources. Running these tests may result in additional fees associated with
your cloud account. Care is taken to ensure that created resources are
removed. However, it is advisable to inspect your AWS console to ensure no
unexpected resources are running.

View File

@ -1,3 +1,7 @@
:orphan:
.. _testing_pep8:
*****
PEP 8
*****

View File

@ -1,3 +1,5 @@
:orphan:
.. _testing_running_locally:
***************
@ -40,13 +42,13 @@ Environment Variables
When using environment variables to manipulate tests there some limitations to keep in mind. Environment variables are:
* Not propagated from the host to the test environment when using the ``--docker`` or ``--remote`` options.
* Not propagated from the host to the test environment when using the ``--docker`` or ``--remote`` options.
* Not exposed to the test environment unless whitelisted in ``test/runner/lib/util.py`` in the ``common_environment`` function.
* Not exposed to the test environment when using the ``--tox`` option unless whitelisted in ``test/runner/tox.ini`` by the ``passenv`` definition.
Example: ``ANSIBLE_KEEP_REMOTE_FILES=1`` can be set when running ``ansible-test integration --tox``. However, using the ``--docker`` option would
require running ``ansible-test shell`` to gain access to the Docker environment. Once at the shell prompt, the environment variable could be set
and the tests executed. This is useful for debugging tests inside a container by following the
Example: ``ANSIBLE_KEEP_REMOTE_FILES=1`` can be set when running ``ansible-test integration --tox``. However, using the ``--docker`` option would
require running ``ansible-test shell`` to gain access to the Docker environment. Once at the shell prompt, the environment variable could be set
and the tests executed. This is useful for debugging tests inside a container by following the
:ref:`Debugging AnsibleModule-based modules <debugging_ansiblemodule_based_modules>` instructions.
Interactive Shell
@ -84,4 +86,3 @@ Reports can be generated in several different formats:
To clear data between test runs, use the ``ansible-test coverage erase`` command. For a full list of features see the online help::
ansible-test coverage --help

View File

@ -1,3 +1,7 @@
:orphan:
.. _testing_sanity:
************
Sanity Tests
************
@ -73,5 +77,3 @@ yamllint
~~~~~~~~
Check YAML files for syntax and formatting issues.

View File

@ -1,3 +1,7 @@
:orphan:
.. _testing_units:
**********
Unit Tests
**********
@ -89,7 +93,7 @@ Structuring Unit Tests
Ansible drives unit tests through `pytest <https://docs.pytest.org/en/latest/>`_. This
means that tests can either be written a simple functions which are included in any file
name like ``test_<something>.py`` or as classes.
name like ``test_<something>.py`` or as classes.
Here is an example of a function::
@ -100,23 +104,23 @@ Here is an example of a function::
b = 23
c = 33
assert a + b = c
Here is an example of a class::
import unittest
class AddTester(unittest.TestCase)
def SetUp()
self.a = 10
self.b = 23
# this function will
# this function will
def test_add()
c = 33
assert self.a + self.b = c
# this function will
# this function will
def test_subtract()
c = -13
assert self.a - self.b = c
@ -125,7 +129,7 @@ Both methods work fine in most circumstances; the function-based interface is si
quicker and so that's probably where you should start when you are just trying to add a
few basic tests for a module. The class-based test allows more tidy set up and tear down
of pre-requisites, so if you have many test cases for your module you may want to refactor
to use that.
to use that.
Assertions using the simple ``assert`` function inside the tests will give full
information on the cause of the failure with a trace-back of functions called during the
@ -200,9 +204,8 @@ reports.
:doc:`testing_running_locally`
Running tests locally including gathering and reporting coverage data
`Python 3 documentation - 26.4. unittest — Unit testing framework <https://docs.python.org/3/library/unittest.html>`_
The documentation of the unittest framework in python 3
The documentation of the unittest framework in python 3
`Python 2 documentation - 25.3. unittest — Unit testing framework <https://docs.python.org/3/library/unittest.html>`_
The documentation of the earliest supported unittest framework - from Python 2.6
`pytest: helps you write better programs <https://docs.pytest.org/en/latest/>`_
The documentation of pytest - the framework actually used to run Ansible unit tests

View File

@ -1,3 +1,5 @@
:orphan:
.. _testing_units_modules:
****************************
@ -15,7 +17,7 @@ This document explains why, how and when you should use unit tests for Ansible m
The document doesn't apply to other parts of Ansible for which the recommendations are
normally closer to the Python standard. There is basic documentation for Ansible unit
tests in the developer guide :doc:`testing_units`. This document should
be readable for a new Ansible module author. If you find it incomplete or confusing,
be readable for a new Ansible module author. If you find it incomplete or confusing,
please open a bug or ask for help on Ansible IRC.
What Are Unit Tests?
@ -69,10 +71,10 @@ When To Use Unit Tests
There are a number of situations where unit tests are a better choice than integration
tests. For example, testing things which are impossible, slow or very difficult to test
with integration tests, such as:
* Forcing rare / strange / random situations that can't be forced, such as specific network
failures and exceptions
* Extensive testing of slow configuration APIs
* Extensive testing of slow configuration APIs
* Situations where the integration tests cannot be run as part of the main Ansible
continuous integraiton running in Shippable.
@ -92,11 +94,11 @@ creating a unit test when bug fixing a module, even if those tests do not often
problems later. As a basic goal, every module should have at least one unit test which
will give quick feedback in easy cases without having to wait for the integration tests to
complete.
Ensuring correct use of external interfaces
-------------------------------------------
Unit tests can check the way in which external services are run to ensure that they match
Unit tests can check the way in which external services are run to ensure that they match
specifications or are as efficient as possible *even when the final output will not be changed*.
Example:
@ -113,12 +115,12 @@ which checks that the call happens properly for the old version can help avoid t
problem. In this situation it is very important to include version numbering in the test case
name (see `Naming unit tests`_ below).
Providing specific design tests
Providing specific design tests
--------------------------------
By building a requirement for a particular part of the
code and then coding to that requirement, unit tests _can_ sometimes improve the code and
help future developers understand that code.
help future developers understand that code.
Unit tests that test internal implementation details of code, on the other hand, almost
always do more harm than good. Testing that your packages to install are stored in a list
@ -126,7 +128,7 @@ would slow down and confuse a future developer who might need to change that lis
dictionary for efficiency. This problem can be reduced somewhat with clear test naming so
that the future developer immediately knows to delete the test case, but it is often
better to simply leave out the test case altogether and test for a real valuable feature
of the code, such as installing all of the packages supplied as arguments to the module.
of the code, such as installing all of the packages supplied as arguments to the module.
How to unit test Ansible modules
@ -148,7 +150,7 @@ If a unit test is designed to verify compatibility with a specific software or A
then include the version in the name of the unit test.
As an example, ``test_v2_state_present_should_call_create_server_with_name()`` would be a
good name, ``test_create_server()`` would not be.
good name, ``test_create_server()`` would not be.
Use of Mocks
@ -164,16 +166,16 @@ Ensuring failure cases are visible with mock objects
----------------------------------------------------
Functions like :meth:`module.fail_json` are normally expected to terminate execution. When you
run with a mock module object this doesn't happen since the mock always returns another mock
run with a mock module object this doesn't happen since the mock always returns another mock
from a function call. You can set up the mock to raise an exception as shown above, or you can
assert that these functions have not been called in each test. For example::
module = MagicMock()
function_to_test(module, argument)
module.fail_json.assert_not_called()
module.fail_json.assert_not_called()
This applies not only to calling the main module but almost any other
function in a module which gets the module object.
function in a module which gets the module object.
Mocking of the actual module
@ -193,9 +195,9 @@ above, either by throwing an exception or ensuring that they haven't been called
module.exit_json.side_effect = AnsibleExitJson(Exception)
with self.assertRaises(AnsibleExitJson) as result:
return = my_module.test_this_function(module, argument)
module.fail_json.assert_not_called()
module.fail_json.assert_not_called()
assert return["changed"] == True
API definition with unit test cases
-----------------------------------
@ -237,7 +239,7 @@ This is then used to create a list of states::
simple_instance_list('available', {}),
simple_instance_list('available', {}),
]
These states are then used as returns from a mock object to ensure that the ``await`` function
waits through all of the states that would mean the RDS instance has not yet completed
configuration::
@ -269,10 +271,10 @@ The most common are documented below, and suggestions for others can be found by
at the source code of the existing unit tests or asking on the Ansible IRC channel or mailing
lists.
Module argument processing
Module argument processing
--------------------------
There are two problems with running the main function of a module:
There are two problems with running the main function of a module:
* Since the module is supposed to accept arguments on ``STDIN`` it is a bit difficult to
set up the arguments correctly so that the module will get them as parameters.
@ -383,7 +385,7 @@ A Complete Example
The following example is a complete skeleton that reuses the mocks explained above and adds a new
mock for :meth:`Ansible.get_bin_path`::
import json
from ansible.compat.tests import unittest
@ -531,10 +533,10 @@ A helpful development approach to this should be to ensure that all of the tests
run under Python 2.6 and that each assertion in the test cases has been checked to work by breaking
the code in Ansible to trigger that failure.
.. warning:: Maintain Python-2.6 compatibility
.. warning:: Maintain Python 2.6 compatibility
Please remember that modules need to maintain compatibility with Python-2.6 so the unittests for
modules should also be compatible with Python-2.6.
Please remember that modules need to maintain compatibility with Python 2.6 so the unittests for
modules should also be compatible with Python 2.6.
.. seealso::
@ -546,7 +548,7 @@ the code in Ansible to trigger that failure.
:doc:`developing_modules`
How to develop modules
`Python 3 documentation - 26.4. unittest — Unit testing framework <https://docs.python.org/3/library/unittest.html>`_
The documentation of the unittest framework in python 3
The documentation of the unittest framework in python 3
`Python 2 documentation - 25.3. unittest — Unit testing framework <https://docs.python.org/3/library/unittest.html>`_
The documentation of the earliest supported unittest framework - from Python 2.6
`pytest: helps you write better programs <https://docs.pytest.org/en/latest/>`_
@ -560,5 +562,5 @@ the code in Ansible to trigger that failure.
Extreme Programming (XP), Clean Coding. Uncle Bob talks through how to benfit from this
`"Why Most Unit Testing is Waste" https://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf`
An article warning against the costs of unit testing
`'A Response to "Why Most Unit Testing is Waste"' https://henrikwarne.com/2014/09/04/a-response-to-why-most-unit-testing-is-waste/`
`'A Response to "Why Most Unit Testing is Waste"' https://henrikwarne.com/2014/09/04/a-response-to-why-most-unit-testing-is-waste/`
An response pointing to how to maintain the value of unit tests

View File

@ -1,3 +1,5 @@
:orphan:
****************
validate-modules
****************

View File

@ -47,19 +47,10 @@ Ansible releases a new major release of Ansible approximately every two months.
.. toctree::
:maxdepth: 2
:glob:
:caption: Scenario Guides
scenario_guides/guide_aci
scenario_guides/guide_aws
scenario_guides/guide_azure
scenario_guides/guide_cloudstack
scenario_guides/guide_docker
scenario_guides/guide_gce
scenario_guides/guide_packet
scenario_guides/guide_rax
scenario_guides/guide_rolling_upgrade
scenario_guides/guide_vagrant
scenario_guides/guide_vultr
scenario_guides/guide_*
.. toctree::
:maxdepth: 2
@ -74,7 +65,7 @@ Ansible releases a new major release of Ansible approximately every two months.
network/index
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Reference & Appendices
../modules/modules_by_category
@ -89,6 +80,8 @@ Ansible releases a new major release of Ansible approximately every two months.
dev_guide/testing/sanity/index
reference_appendices/faq
reference_appendices/glossary
reference_appendices/module_utils
reference_appendices/special_variables
reference_appendices/tower

View File

@ -147,8 +147,7 @@ To configure the PPA on your machine and install ansible run these commands:
$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt-get install ansible
.. note:: On older Ubuntu distributions, "software-properties-common" is called "python-software-properties".
@ -204,9 +203,19 @@ To install the newest version, you may need to unmask the ansible package prior
Latest Releases via pkg (FreeBSD)
+++++++++++++++++++++++++++++++++
Though Ansible works with both Python 2 and 3 versions, FreeBSD has different packages for each Python version.
So to install you can use:
.. code-block:: bash
$ sudo pkg install ansible
$ sudo pkg install py27-ansible
or:
.. code-block:: bash
$ sudo pkg install py36-ansible
You may also wish to install from ports, run:
@ -214,6 +223,14 @@ You may also wish to install from ports, run:
$ sudo make -C /usr/ports/sysutils/ansible install
You can also choose a specific version, i.e ``ansible25``.
Older versions of FreeBSD worked with something like this (substitute for your choice of package manager):
.. code-block:: bash
$ sudo pkg install ansible
.. _on_macos:
Latest Releases on macOS

View File

@ -1,3 +1,5 @@
:orphan:
.. _implicit_localhost:
Implicit 'localhost'
@ -26,6 +28,7 @@ You can override the built-in implicit version by creating a ``localhost`` host
.. note::
- This host is not targetable via any group, however it will use vars from ``host_vars`` and from the 'all' group.
- The ``inventory_file`` and ``inventory_dir`` magic variables are not available for the implicit localhost as they are dependent on **each inventory host**.
- This implicit host also gets triggered by using ``127.0.0.1`` or ``::1`` as they are the IPv4 and IPv6 representations of 'localhost'.
- Even though there are many ways to create it, there will only ever be ONE implicit localhost, using the name first used to create it.
- Having ``connection: local`` does NOT trigger an implicit localhost, you are just changing the connection for the ``inventory_hostname``.

View File

@ -2,7 +2,7 @@
Run Your First Command and Playbook
***************************************************
Put the concepts you learned to work with this quick tutorial. Install Ansible, execute a network configuration command manually, execute the same command with Ansible, then create a playbook so you can execute the command any time on multiple network devices.
Put the concepts you learned to work with this quick tutorial. Install Ansible, execute a network configuration command manually, execute the same command with Ansible, then create a playbook so you can execute the command any time on multiple network devices.
.. contents:: Topics
@ -86,22 +86,17 @@ The playbook contains one play with two tasks, and should generate output like t
.. code-block:: bash
$ ansible-playbook -i vyos.example.net, -u ansible -k -e ansible_network_os=vyos first_playbook.yml
PLAY [First Playbook]
***************************************************************************************************************************
TASK [Gathering Facts]
***************************************************************************************************************************
ok: [vyos.example.net]
TASK [Get config for VyOS devices]
***************************************************************************************************************************
ok: [vyos.example.net]
TASK [Display the config]
***************************************************************************************************************************
ok: [vyos.example.net] => {
"failed": false,
"msg": "The hostname is vyos and the OS is VyOS"
}
@ -114,15 +109,11 @@ The extended first playbook has four tasks in a single play. Run it with the sam
.. code-block:: bash
$ ansible-playbook -i vyos.example.net, -u ansible -k -e ansible_network_os=vyos first_playbook_ext.yml
$ ansible-playbook -i vyos.example.net, -u ansible -k -e ansible_network_os=vyos first_playbook_ext.yml
PLAY [First Playbook]
************************************************************************************************************************************
TASK [Gathering Facts]
***********************************************************************************************************************************
ok: [vyos.example.net]
TASK [Get config for VyOS devices]
**********************************************************************************************************************************
ok: [vyos.example.net]
@ -130,10 +121,9 @@ The extended first playbook has four tasks in a single play. Run it with the sam
TASK [Display the config]
*************************************************************************************************************************************
ok: [vyos.example.net] => {
"failed": false,
"msg": "The hostname is vyos and the OS is VyOS"
}
TASK [Update the hostname]
*************************************************************************************************************************************
changed: [vyos.example.net]
@ -141,17 +131,16 @@ The extended first playbook has four tasks in a single play. Run it with the sam
TASK [Get changed config for VyOS devices]
*************************************************************************************************************************************
ok: [vyos.example.net]
TASK [Display the changed config]
*************************************************************************************************************************************
ok: [vyos.example.net] => {
"failed": false,
"msg": "The hostname is vyos-changed and the OS is VyOS"
}
PLAY RECAP
************************************************************************************************************************************
vyos.example.net : ok=6 changed=1 unreachable=0 failed=0
vyos.example.net : ok=6 changed=1 unreachable=0 failed=0
This playbook is useful. However, running it still requires several command-line flags. Also, running a playbook against a single device is not a huge efficiency gain over making the same change manually. The next step to harnessing the full power of Ansible is to use an inventory file to organize your managed nodes into groups with information like the ``ansible_network_os`` and the SSH user.
This playbook is useful. However, running it still requires several command-line flags. Also, running a playbook against a single device is not a huge efficiency gain over making the same change manually. The next step to harnessing the full power of Ansible is to use an inventory file to organize your managed nodes into groups with information like the ``ansible_network_os`` and the SSH user.

View File

@ -2,6 +2,7 @@
- name: Network Getting Started First Playbook
connection: network_cli
gather_facts: false
hosts: all
tasks:

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