ansible_core-2.19.0b5/0000755000000000000000000000000015017704211013213 5ustar00rootrootansible_core-2.19.0b5/COPYING0000644000000000000000000010451515017704211014254 0ustar00rootroot GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ansible_core-2.19.0b5/MANIFEST.in0000644000000000000000000000054415017704211014754 0ustar00rootrootinclude COPYING include changelogs/CHANGELOG*.rst include changelogs/changelog.yaml include licenses/*.txt include requirements.txt recursive-include packaging *.py *.j2 recursive-include test/integration * recursive-include test/sanity *.in *.json *.py *.txt *.ini recursive-include test/support *.py *.ps1 *.psm1 *.cs *.md recursive-include test/units * ansible_core-2.19.0b5/PKG-INFO0000644000000000000000000001706415017704211014320 0ustar00rootrootMetadata-Version: 2.4 Name: ansible-core Version: 2.19.0b5 Summary: Radically simple IT automation Author: Ansible Project Project-URL: Homepage, https://ansible.com/ Project-URL: Source Code, https://github.com/ansible/ansible/ Project-URL: Bug Tracker, https://github.com/ansible/ansible/issues/ Project-URL: CI: Azure Pipelines, https://dev.azure.com/ansible/ansible/ Project-URL: Documentation, https://docs.ansible.com/ansible-core/ Project-URL: Code of Conduct, https://docs.ansible.com/ansible/latest/community/code_of_conduct.html Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Classifier: Natural Language :: English Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: System :: Installation/Setup Classifier: Topic :: System :: Systems Administration Classifier: Topic :: Utilities Requires-Python: >=3.11 Description-Content-Type: text/markdown License-File: COPYING License-File: licenses/Apache-License.txt License-File: licenses/BSD-3-Clause.txt License-File: licenses/MIT-license.txt License-File: licenses/PSF-license.txt License-File: licenses/simplified_bsd.txt Requires-Dist: jinja2>=3.1.0 Requires-Dist: PyYAML>=5.1 Requires-Dist: cryptography Requires-Dist: packaging Requires-Dist: resolvelib<2.0.0,>=0.5.3 Dynamic: license-file [![PyPI version](https://img.shields.io/pypi/v/ansible-core.svg)](https://pypi.org/project/ansible-core) [![Docs badge](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://docs.ansible.com/ansible/latest/) [![Chat badge](https://img.shields.io/badge/chat-IRC-brightgreen.svg)](https://docs.ansible.com/ansible/devel/community/communication.html) [![Build Status](https://dev.azure.com/ansible/ansible/_apis/build/status/CI?branchName=devel)](https://dev.azure.com/ansible/ansible/_build/latest?definitionId=20&branchName=devel) [![Ansible Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-Ansible-silver.svg)](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) [![Ansible mailing lists](https://img.shields.io/badge/mailing%20lists-Ansible-orange.svg)](https://docs.ansible.com/ansible/devel/community/communication.html#mailing-list-information) [![Repository License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](COPYING) [![Ansible CII Best Practices certification](https://bestpractices.coreinfrastructure.org/projects/2372/badge)](https://bestpractices.coreinfrastructure.org/projects/2372) # Ansible Ansible is a radically simple IT automation system. It handles configuration management, application deployment, cloud provisioning, ad-hoc task execution, network automation, and multi-node orchestration. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy. More information on the Ansible [website](https://ansible.com/). ## Design Principles * Have an extremely simple setup process with a minimal learning curve. * Manage machines quickly and in parallel. * Avoid custom-agents and additional open ports, be agentless by leveraging the existing SSH daemon. * Describe infrastructure in a language that is both machine and human friendly. * Focus on security and easy auditability/review/rewriting of content. * Manage new remote machines instantly, without bootstrapping any software. * Allow module development in any dynamic language, not just Python. * Be usable as non-root. * Be the easiest IT automation system to use, ever. ## Use Ansible You can install a released version of Ansible with `pip` or a package manager. See our [installation guide](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) for details on installing Ansible on a variety of platforms. Power users and developers can run the `devel` branch, which has the latest features and fixes, directly. Although it is reasonably stable, you are more likely to encounter breaking changes when running the `devel` branch. We recommend getting involved in the Ansible community if you want to run the `devel` branch. ## Communication Join the Ansible forum to ask questions, get help, and interact with the community. * [Get Help](https://forum.ansible.com/c/help/6): Find help or share your Ansible knowledge to help others. Use tags to filter and subscribe to posts, such as the following: * Posts tagged with [ansible](https://forum.ansible.com/tag/ansible) * Posts tagged with [ansible-core](https://forum.ansible.com/tag/ansible-core) * Posts tagged with [playbook](https://forum.ansible.com/tag/playbook) * [Social Spaces](https://forum.ansible.com/c/chat/4): Meet and interact with fellow enthusiasts. * [News & Announcements](https://forum.ansible.com/c/news/5): Track project-wide announcements including social events. * [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn): Get release announcements and important changes. For more ways to get in touch, see [Communicating with the Ansible community](https://docs.ansible.com/ansible/devel/community/communication.html). ## Contribute to Ansible * Check out the [Contributor's Guide](./.github/CONTRIBUTING.md). * Read [Community Information](https://docs.ansible.com/ansible/devel/community) for all kinds of ways to contribute to and interact with the project, including how to submit bug reports and code to Ansible. * Submit a proposed code update through a pull request to the `devel` branch. * Talk to us before making larger changes to avoid duplicate efforts. This not only helps everyone know what is going on, but it also helps save time and effort if we decide some changes are needed. ## Coding Guidelines We document our Coding Guidelines in the [Developer Guide](https://docs.ansible.com/ansible/devel/dev_guide/). We particularly suggest you review: * [Contributing your module to Ansible](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_checklist.html) * [Conventions, tips, and pitfalls](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html) ## Branch Info * The `devel` branch corresponds to the release actively under development. * The `stable-2.X` branches correspond to stable releases. * Create a branch based on `devel` and set up a [dev environment](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_general.html#common-environment-setup) if you want to open a PR. * See the [Ansible release and maintenance](https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html) page for information about active branches. ## Roadmap Based on team and community feedback, an initial roadmap will be published for a major or minor version (ex: 2.7, 2.8). The [Ansible Roadmap page](https://docs.ansible.com/ansible/devel/roadmap/) details what is planned and how to influence the roadmap. ## Authors Ansible was created by [Michael DeHaan](https://github.com/mpdehaan) and has contributions from over 5000 users (and growing). Thanks everyone! [Ansible](https://www.ansible.com) is sponsored by [Red Hat, Inc.](https://www.redhat.com) ## License GNU General Public License v3.0 or later See [COPYING](COPYING) to see the full text. ansible_core-2.19.0b5/README.md0000644000000000000000000001345215017704211014477 0ustar00rootroot[![PyPI version](https://img.shields.io/pypi/v/ansible-core.svg)](https://pypi.org/project/ansible-core) [![Docs badge](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://docs.ansible.com/ansible/latest/) [![Chat badge](https://img.shields.io/badge/chat-IRC-brightgreen.svg)](https://docs.ansible.com/ansible/devel/community/communication.html) [![Build Status](https://dev.azure.com/ansible/ansible/_apis/build/status/CI?branchName=devel)](https://dev.azure.com/ansible/ansible/_build/latest?definitionId=20&branchName=devel) [![Ansible Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-Ansible-silver.svg)](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) [![Ansible mailing lists](https://img.shields.io/badge/mailing%20lists-Ansible-orange.svg)](https://docs.ansible.com/ansible/devel/community/communication.html#mailing-list-information) [![Repository License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](COPYING) [![Ansible CII Best Practices certification](https://bestpractices.coreinfrastructure.org/projects/2372/badge)](https://bestpractices.coreinfrastructure.org/projects/2372) # Ansible Ansible is a radically simple IT automation system. It handles configuration management, application deployment, cloud provisioning, ad-hoc task execution, network automation, and multi-node orchestration. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy. More information on the Ansible [website](https://ansible.com/). ## Design Principles * Have an extremely simple setup process with a minimal learning curve. * Manage machines quickly and in parallel. * Avoid custom-agents and additional open ports, be agentless by leveraging the existing SSH daemon. * Describe infrastructure in a language that is both machine and human friendly. * Focus on security and easy auditability/review/rewriting of content. * Manage new remote machines instantly, without bootstrapping any software. * Allow module development in any dynamic language, not just Python. * Be usable as non-root. * Be the easiest IT automation system to use, ever. ## Use Ansible You can install a released version of Ansible with `pip` or a package manager. See our [installation guide](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) for details on installing Ansible on a variety of platforms. Power users and developers can run the `devel` branch, which has the latest features and fixes, directly. Although it is reasonably stable, you are more likely to encounter breaking changes when running the `devel` branch. We recommend getting involved in the Ansible community if you want to run the `devel` branch. ## Communication Join the Ansible forum to ask questions, get help, and interact with the community. * [Get Help](https://forum.ansible.com/c/help/6): Find help or share your Ansible knowledge to help others. Use tags to filter and subscribe to posts, such as the following: * Posts tagged with [ansible](https://forum.ansible.com/tag/ansible) * Posts tagged with [ansible-core](https://forum.ansible.com/tag/ansible-core) * Posts tagged with [playbook](https://forum.ansible.com/tag/playbook) * [Social Spaces](https://forum.ansible.com/c/chat/4): Meet and interact with fellow enthusiasts. * [News & Announcements](https://forum.ansible.com/c/news/5): Track project-wide announcements including social events. * [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn): Get release announcements and important changes. For more ways to get in touch, see [Communicating with the Ansible community](https://docs.ansible.com/ansible/devel/community/communication.html). ## Contribute to Ansible * Check out the [Contributor's Guide](./.github/CONTRIBUTING.md). * Read [Community Information](https://docs.ansible.com/ansible/devel/community) for all kinds of ways to contribute to and interact with the project, including how to submit bug reports and code to Ansible. * Submit a proposed code update through a pull request to the `devel` branch. * Talk to us before making larger changes to avoid duplicate efforts. This not only helps everyone know what is going on, but it also helps save time and effort if we decide some changes are needed. ## Coding Guidelines We document our Coding Guidelines in the [Developer Guide](https://docs.ansible.com/ansible/devel/dev_guide/). We particularly suggest you review: * [Contributing your module to Ansible](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_checklist.html) * [Conventions, tips, and pitfalls](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html) ## Branch Info * The `devel` branch corresponds to the release actively under development. * The `stable-2.X` branches correspond to stable releases. * Create a branch based on `devel` and set up a [dev environment](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_general.html#common-environment-setup) if you want to open a PR. * See the [Ansible release and maintenance](https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html) page for information about active branches. ## Roadmap Based on team and community feedback, an initial roadmap will be published for a major or minor version (ex: 2.7, 2.8). The [Ansible Roadmap page](https://docs.ansible.com/ansible/devel/roadmap/) details what is planned and how to influence the roadmap. ## Authors Ansible was created by [Michael DeHaan](https://github.com/mpdehaan) and has contributions from over 5000 users (and growing). Thanks everyone! [Ansible](https://www.ansible.com) is sponsored by [Red Hat, Inc.](https://www.redhat.com) ## License GNU General Public License v3.0 or later See [COPYING](COPYING) to see the full text. ansible_core-2.19.0b5/ansible_core.egg-info/0000755000000000000000000000000015017704211017332 5ustar00rootrootansible_core-2.19.0b5/ansible_core.egg-info/PKG-INFO0000644000000000000000000001706415017704211020437 0ustar00rootrootMetadata-Version: 2.4 Name: ansible-core Version: 2.19.0b5 Summary: Radically simple IT automation Author: Ansible Project Project-URL: Homepage, https://ansible.com/ Project-URL: Source Code, https://github.com/ansible/ansible/ Project-URL: Bug Tracker, https://github.com/ansible/ansible/issues/ Project-URL: CI: Azure Pipelines, https://dev.azure.com/ansible/ansible/ Project-URL: Documentation, https://docs.ansible.com/ansible-core/ Project-URL: Code of Conduct, https://docs.ansible.com/ansible/latest/community/code_of_conduct.html Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+) Classifier: Natural Language :: English Classifier: Operating System :: POSIX Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: System :: Installation/Setup Classifier: Topic :: System :: Systems Administration Classifier: Topic :: Utilities Requires-Python: >=3.11 Description-Content-Type: text/markdown License-File: COPYING License-File: licenses/Apache-License.txt License-File: licenses/BSD-3-Clause.txt License-File: licenses/MIT-license.txt License-File: licenses/PSF-license.txt License-File: licenses/simplified_bsd.txt Requires-Dist: jinja2>=3.1.0 Requires-Dist: PyYAML>=5.1 Requires-Dist: cryptography Requires-Dist: packaging Requires-Dist: resolvelib<2.0.0,>=0.5.3 Dynamic: license-file [![PyPI version](https://img.shields.io/pypi/v/ansible-core.svg)](https://pypi.org/project/ansible-core) [![Docs badge](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://docs.ansible.com/ansible/latest/) [![Chat badge](https://img.shields.io/badge/chat-IRC-brightgreen.svg)](https://docs.ansible.com/ansible/devel/community/communication.html) [![Build Status](https://dev.azure.com/ansible/ansible/_apis/build/status/CI?branchName=devel)](https://dev.azure.com/ansible/ansible/_build/latest?definitionId=20&branchName=devel) [![Ansible Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-Ansible-silver.svg)](https://docs.ansible.com/ansible/devel/community/code_of_conduct.html) [![Ansible mailing lists](https://img.shields.io/badge/mailing%20lists-Ansible-orange.svg)](https://docs.ansible.com/ansible/devel/community/communication.html#mailing-list-information) [![Repository License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](COPYING) [![Ansible CII Best Practices certification](https://bestpractices.coreinfrastructure.org/projects/2372/badge)](https://bestpractices.coreinfrastructure.org/projects/2372) # Ansible Ansible is a radically simple IT automation system. It handles configuration management, application deployment, cloud provisioning, ad-hoc task execution, network automation, and multi-node orchestration. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy. More information on the Ansible [website](https://ansible.com/). ## Design Principles * Have an extremely simple setup process with a minimal learning curve. * Manage machines quickly and in parallel. * Avoid custom-agents and additional open ports, be agentless by leveraging the existing SSH daemon. * Describe infrastructure in a language that is both machine and human friendly. * Focus on security and easy auditability/review/rewriting of content. * Manage new remote machines instantly, without bootstrapping any software. * Allow module development in any dynamic language, not just Python. * Be usable as non-root. * Be the easiest IT automation system to use, ever. ## Use Ansible You can install a released version of Ansible with `pip` or a package manager. See our [installation guide](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) for details on installing Ansible on a variety of platforms. Power users and developers can run the `devel` branch, which has the latest features and fixes, directly. Although it is reasonably stable, you are more likely to encounter breaking changes when running the `devel` branch. We recommend getting involved in the Ansible community if you want to run the `devel` branch. ## Communication Join the Ansible forum to ask questions, get help, and interact with the community. * [Get Help](https://forum.ansible.com/c/help/6): Find help or share your Ansible knowledge to help others. Use tags to filter and subscribe to posts, such as the following: * Posts tagged with [ansible](https://forum.ansible.com/tag/ansible) * Posts tagged with [ansible-core](https://forum.ansible.com/tag/ansible-core) * Posts tagged with [playbook](https://forum.ansible.com/tag/playbook) * [Social Spaces](https://forum.ansible.com/c/chat/4): Meet and interact with fellow enthusiasts. * [News & Announcements](https://forum.ansible.com/c/news/5): Track project-wide announcements including social events. * [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn): Get release announcements and important changes. For more ways to get in touch, see [Communicating with the Ansible community](https://docs.ansible.com/ansible/devel/community/communication.html). ## Contribute to Ansible * Check out the [Contributor's Guide](./.github/CONTRIBUTING.md). * Read [Community Information](https://docs.ansible.com/ansible/devel/community) for all kinds of ways to contribute to and interact with the project, including how to submit bug reports and code to Ansible. * Submit a proposed code update through a pull request to the `devel` branch. * Talk to us before making larger changes to avoid duplicate efforts. This not only helps everyone know what is going on, but it also helps save time and effort if we decide some changes are needed. ## Coding Guidelines We document our Coding Guidelines in the [Developer Guide](https://docs.ansible.com/ansible/devel/dev_guide/). We particularly suggest you review: * [Contributing your module to Ansible](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_checklist.html) * [Conventions, tips, and pitfalls](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html) ## Branch Info * The `devel` branch corresponds to the release actively under development. * The `stable-2.X` branches correspond to stable releases. * Create a branch based on `devel` and set up a [dev environment](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_general.html#common-environment-setup) if you want to open a PR. * See the [Ansible release and maintenance](https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html) page for information about active branches. ## Roadmap Based on team and community feedback, an initial roadmap will be published for a major or minor version (ex: 2.7, 2.8). The [Ansible Roadmap page](https://docs.ansible.com/ansible/devel/roadmap/) details what is planned and how to influence the roadmap. ## Authors Ansible was created by [Michael DeHaan](https://github.com/mpdehaan) and has contributions from over 5000 users (and growing). Thanks everyone! [Ansible](https://www.ansible.com) is sponsored by [Red Hat, Inc.](https://www.redhat.com) ## License GNU General Public License v3.0 or later See [COPYING](COPYING) to see the full text. ansible_core-2.19.0b5/ansible_core.egg-info/SOURCES.txt0000644000000000000000000121457215017704211021232 0ustar00rootrootCOPYING MANIFEST.in README.md pyproject.toml requirements.txt ansible_core.egg-info/PKG-INFO ansible_core.egg-info/SOURCES.txt ansible_core.egg-info/dependency_links.txt ansible_core.egg-info/entry_points.txt ansible_core.egg-info/requires.txt ansible_core.egg-info/top_level.txt changelogs/CHANGELOG-v2.19.rst changelogs/changelog.yaml lib/ansible/__init__.py lib/ansible/__main__.py lib/ansible/constants.py lib/ansible/context.py lib/ansible/keyword_desc.yml lib/ansible/release.py lib/ansible/_internal/__init__.py lib/ansible/_internal/_ansiballz.py lib/ansible/_internal/_collection_proxy.py lib/ansible/_internal/_event_formatting.py lib/ansible/_internal/_locking.py lib/ansible/_internal/_task.py lib/ansible/_internal/_testing.py lib/ansible/_internal/_wrapt.py lib/ansible/_internal/_datatag/__init__.py lib/ansible/_internal/_datatag/_tags.py lib/ansible/_internal/_datatag/_utils.py lib/ansible/_internal/_datatag/_wrappers.py lib/ansible/_internal/_errors/__init__.py lib/ansible/_internal/_errors/_alarm_timeout.py lib/ansible/_internal/_errors/_captured.py lib/ansible/_internal/_errors/_error_factory.py lib/ansible/_internal/_errors/_error_utils.py lib/ansible/_internal/_errors/_handler.py lib/ansible/_internal/_errors/_task_timeout.py lib/ansible/_internal/_json/__init__.py lib/ansible/_internal/_json/_legacy_encoder.py lib/ansible/_internal/_json/_profiles/__init__.py lib/ansible/_internal/_json/_profiles/_cache_persistence.py lib/ansible/_internal/_json/_profiles/_inventory_legacy.py lib/ansible/_internal/_json/_profiles/_legacy.py lib/ansible/_internal/_plugins/__init__.py lib/ansible/_internal/_plugins/_cache.py lib/ansible/_internal/_ssh/__init__.py lib/ansible/_internal/_ssh/_agent_launch.py lib/ansible/_internal/_ssh/_ssh_agent.py lib/ansible/_internal/_templating/__init__.py lib/ansible/_internal/_templating/_access.py lib/ansible/_internal/_templating/_chain_templar.py lib/ansible/_internal/_templating/_datatag.py lib/ansible/_internal/_templating/_engine.py lib/ansible/_internal/_templating/_errors.py lib/ansible/_internal/_templating/_jinja_bits.py lib/ansible/_internal/_templating/_jinja_common.py lib/ansible/_internal/_templating/_jinja_patches.py lib/ansible/_internal/_templating/_jinja_plugins.py lib/ansible/_internal/_templating/_lazy_containers.py lib/ansible/_internal/_templating/_marker_behaviors.py lib/ansible/_internal/_templating/_transform.py lib/ansible/_internal/_templating/_utils.py lib/ansible/_internal/_yaml/__init__.py lib/ansible/_internal/_yaml/_constructor.py lib/ansible/_internal/_yaml/_dumper.py lib/ansible/_internal/_yaml/_errors.py lib/ansible/_internal/_yaml/_loader.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/README.md lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml lib/ansible/_vendor/__init__.py lib/ansible/cli/__init__.py lib/ansible/cli/_ssh_askpass.py lib/ansible/cli/adhoc.py lib/ansible/cli/config.py lib/ansible/cli/console.py lib/ansible/cli/doc.py lib/ansible/cli/galaxy.py lib/ansible/cli/inventory.py lib/ansible/cli/playbook.py lib/ansible/cli/pull.py lib/ansible/cli/vault.py lib/ansible/cli/arguments/__init__.py lib/ansible/cli/arguments/option_helpers.py lib/ansible/cli/scripts/__init__.py lib/ansible/cli/scripts/ansible_connection_cli_stub.py lib/ansible/collections/__init__.py lib/ansible/collections/list.py lib/ansible/compat/__init__.py lib/ansible/compat/importlib_resources.py lib/ansible/config/__init__.py lib/ansible/config/ansible_builtin_runtime.yml lib/ansible/config/base.yml lib/ansible/config/manager.py lib/ansible/errors/__init__.py lib/ansible/executor/__init__.py lib/ansible/executor/interpreter_discovery.py lib/ansible/executor/module_common.py lib/ansible/executor/play_iterator.py lib/ansible/executor/playbook_executor.py lib/ansible/executor/stats.py lib/ansible/executor/task_executor.py lib/ansible/executor/task_queue_manager.py lib/ansible/executor/task_result.py lib/ansible/executor/discovery/__init__.py lib/ansible/executor/powershell/__init__.py lib/ansible/executor/powershell/async_watchdog.ps1 lib/ansible/executor/powershell/async_wrapper.ps1 lib/ansible/executor/powershell/become_wrapper.ps1 lib/ansible/executor/powershell/bootstrap_wrapper.ps1 lib/ansible/executor/powershell/coverage_wrapper.ps1 lib/ansible/executor/powershell/exec_wrapper.ps1 lib/ansible/executor/powershell/module_manifest.py lib/ansible/executor/powershell/module_wrapper.ps1 lib/ansible/executor/powershell/powershell_expand_user.ps1 lib/ansible/executor/powershell/powershell_mkdtemp.ps1 lib/ansible/executor/powershell/psrp_fetch_file.ps1 lib/ansible/executor/powershell/psrp_put_file.ps1 lib/ansible/executor/powershell/winrm_fetch_file.ps1 lib/ansible/executor/powershell/winrm_put_file.ps1 lib/ansible/executor/process/__init__.py lib/ansible/executor/process/worker.py lib/ansible/galaxy/__init__.py lib/ansible/galaxy/api.py lib/ansible/galaxy/role.py lib/ansible/galaxy/token.py lib/ansible/galaxy/user_agent.py lib/ansible/galaxy/collection/__init__.py lib/ansible/galaxy/collection/concrete_artifact_manager.py lib/ansible/galaxy/collection/galaxy_api_proxy.py lib/ansible/galaxy/collection/gpg.py lib/ansible/galaxy/data/COPYING lib/ansible/galaxy/data/collections_galaxy_meta.yml lib/ansible/galaxy/data/apb/Dockerfile.j2 lib/ansible/galaxy/data/apb/Makefile.j2 lib/ansible/galaxy/data/apb/README.md lib/ansible/galaxy/data/apb/apb.yml.j2 lib/ansible/galaxy/data/apb/defaults/main.yml.j2 lib/ansible/galaxy/data/apb/files/.git_keep lib/ansible/galaxy/data/apb/handlers/main.yml.j2 lib/ansible/galaxy/data/apb/meta/main.yml.j2 lib/ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 lib/ansible/galaxy/data/apb/playbooks/provision.yml.j2 lib/ansible/galaxy/data/apb/tasks/main.yml.j2 lib/ansible/galaxy/data/apb/templates/.git_keep lib/ansible/galaxy/data/apb/tests/ansible.cfg lib/ansible/galaxy/data/apb/tests/inventory lib/ansible/galaxy/data/apb/tests/test.yml.j2 lib/ansible/galaxy/data/apb/vars/main.yml.j2 lib/ansible/galaxy/data/container/README.md lib/ansible/galaxy/data/container/defaults/main.yml.j2 lib/ansible/galaxy/data/container/files/.git_keep lib/ansible/galaxy/data/container/handlers/main.yml.j2 lib/ansible/galaxy/data/container/meta/container.yml.j2 lib/ansible/galaxy/data/container/meta/main.yml.j2 lib/ansible/galaxy/data/container/tasks/main.yml.j2 lib/ansible/galaxy/data/container/templates/.git_keep lib/ansible/galaxy/data/container/tests/ansible.cfg lib/ansible/galaxy/data/container/tests/inventory lib/ansible/galaxy/data/container/tests/test.yml.j2 lib/ansible/galaxy/data/container/vars/main.yml.j2 lib/ansible/galaxy/data/default/collection/README.md.j2 lib/ansible/galaxy/data/default/collection/galaxy.yml.j2 lib/ansible/galaxy/data/default/collection/docs/.git_keep lib/ansible/galaxy/data/default/collection/meta/runtime.yml lib/ansible/galaxy/data/default/collection/plugins/README.md.j2 lib/ansible/galaxy/data/default/collection/roles/.git_keep lib/ansible/galaxy/data/default/role/README.md lib/ansible/galaxy/data/default/role/defaults/main.yml.j2 lib/ansible/galaxy/data/default/role/files/.git_keep lib/ansible/galaxy/data/default/role/handlers/main.yml.j2 lib/ansible/galaxy/data/default/role/meta/main.yml.j2 lib/ansible/galaxy/data/default/role/tasks/main.yml.j2 lib/ansible/galaxy/data/default/role/templates/.git_keep lib/ansible/galaxy/data/default/role/tests/inventory lib/ansible/galaxy/data/default/role/tests/test.yml.j2 lib/ansible/galaxy/data/default/role/vars/main.yml.j2 lib/ansible/galaxy/data/network/README.md lib/ansible/galaxy/data/network/cliconf_plugins/example.py.j2 lib/ansible/galaxy/data/network/defaults/main.yml.j2 lib/ansible/galaxy/data/network/files/.git_keep lib/ansible/galaxy/data/network/library/example_command.py.j2 lib/ansible/galaxy/data/network/library/example_config.py.j2 lib/ansible/galaxy/data/network/library/example_facts.py.j2 lib/ansible/galaxy/data/network/meta/main.yml.j2 lib/ansible/galaxy/data/network/module_utils/example.py.j2 lib/ansible/galaxy/data/network/netconf_plugins/example.py.j2 lib/ansible/galaxy/data/network/tasks/main.yml.j2 lib/ansible/galaxy/data/network/templates/.git_keep lib/ansible/galaxy/data/network/terminal_plugins/example.py.j2 lib/ansible/galaxy/data/network/tests/inventory lib/ansible/galaxy/data/network/tests/test.yml.j2 lib/ansible/galaxy/data/network/vars/main.yml.j2 lib/ansible/galaxy/dependency_resolution/__init__.py lib/ansible/galaxy/dependency_resolution/dataclasses.py lib/ansible/galaxy/dependency_resolution/errors.py lib/ansible/galaxy/dependency_resolution/providers.py lib/ansible/galaxy/dependency_resolution/reporters.py lib/ansible/galaxy/dependency_resolution/resolvers.py lib/ansible/galaxy/dependency_resolution/versioning.py lib/ansible/inventory/__init__.py lib/ansible/inventory/data.py lib/ansible/inventory/group.py lib/ansible/inventory/helpers.py lib/ansible/inventory/host.py lib/ansible/inventory/manager.py lib/ansible/module_utils/__init__.py lib/ansible/module_utils/_text.py lib/ansible/module_utils/ansible_release.py lib/ansible/module_utils/api.py lib/ansible/module_utils/basic.py lib/ansible/module_utils/connection.py lib/ansible/module_utils/datatag.py lib/ansible/module_utils/errors.py lib/ansible/module_utils/json_utils.py lib/ansible/module_utils/service.py lib/ansible/module_utils/splitter.py lib/ansible/module_utils/testing.py lib/ansible/module_utils/urls.py lib/ansible/module_utils/yumdnf.py lib/ansible/module_utils/_internal/__init__.py lib/ansible/module_utils/_internal/_ambient_context.py lib/ansible/module_utils/_internal/_ansiballz.py lib/ansible/module_utils/_internal/_dataclass_validation.py lib/ansible/module_utils/_internal/_debugging.py lib/ansible/module_utils/_internal/_deprecator.py lib/ansible/module_utils/_internal/_errors.py lib/ansible/module_utils/_internal/_event_utils.py lib/ansible/module_utils/_internal/_messages.py lib/ansible/module_utils/_internal/_plugin_info.py lib/ansible/module_utils/_internal/_stack.py lib/ansible/module_utils/_internal/_testing.py lib/ansible/module_utils/_internal/_text_utils.py lib/ansible/module_utils/_internal/_traceback.py lib/ansible/module_utils/_internal/_validation.py lib/ansible/module_utils/_internal/_concurrent/__init__.py lib/ansible/module_utils/_internal/_concurrent/_daemon_threading.py lib/ansible/module_utils/_internal/_concurrent/_futures.py lib/ansible/module_utils/_internal/_datatag/__init__.py lib/ansible/module_utils/_internal/_datatag/_tags.py lib/ansible/module_utils/_internal/_json/__init__.py lib/ansible/module_utils/_internal/_json/_legacy_encoder.py lib/ansible/module_utils/_internal/_json/_profiles/__init__.py lib/ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py lib/ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py lib/ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py lib/ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py lib/ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py lib/ansible/module_utils/_internal/_json/_profiles/_tagless.py lib/ansible/module_utils/_internal/_patches/__init__.py lib/ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py lib/ansible/module_utils/_internal/_patches/_socket_patch.py lib/ansible/module_utils/_internal/_patches/_sys_intern_patch.py lib/ansible/module_utils/common/__init__.py lib/ansible/module_utils/common/_collections_compat.py lib/ansible/module_utils/common/_utils.py lib/ansible/module_utils/common/arg_spec.py lib/ansible/module_utils/common/collections.py lib/ansible/module_utils/common/dict_transformations.py lib/ansible/module_utils/common/file.py lib/ansible/module_utils/common/json.py lib/ansible/module_utils/common/locale.py lib/ansible/module_utils/common/network.py lib/ansible/module_utils/common/parameters.py lib/ansible/module_utils/common/process.py lib/ansible/module_utils/common/respawn.py lib/ansible/module_utils/common/sentinel.py lib/ansible/module_utils/common/sys_info.py lib/ansible/module_utils/common/validation.py lib/ansible/module_utils/common/warnings.py lib/ansible/module_utils/common/yaml.py lib/ansible/module_utils/common/text/__init__.py lib/ansible/module_utils/common/text/converters.py lib/ansible/module_utils/common/text/formatters.py lib/ansible/module_utils/compat/__init__.py lib/ansible/module_utils/compat/datetime.py lib/ansible/module_utils/compat/paramiko.py lib/ansible/module_utils/compat/selinux.py lib/ansible/module_utils/compat/typing.py lib/ansible/module_utils/compat/version.py lib/ansible/module_utils/csharp/Ansible.AccessToken.cs lib/ansible/module_utils/csharp/Ansible.Basic.cs lib/ansible/module_utils/csharp/Ansible.Become.cs lib/ansible/module_utils/csharp/Ansible.Privilege.cs lib/ansible/module_utils/csharp/Ansible.Process.cs lib/ansible/module_utils/csharp/Ansible._Async.cs lib/ansible/module_utils/csharp/__init__.py lib/ansible/module_utils/distro/__init__.py lib/ansible/module_utils/distro/_distro.py lib/ansible/module_utils/facts/__init__.py lib/ansible/module_utils/facts/ansible_collector.py lib/ansible/module_utils/facts/collector.py lib/ansible/module_utils/facts/compat.py lib/ansible/module_utils/facts/default_collectors.py lib/ansible/module_utils/facts/namespace.py lib/ansible/module_utils/facts/packages.py lib/ansible/module_utils/facts/sysctl.py lib/ansible/module_utils/facts/timeout.py lib/ansible/module_utils/facts/utils.py lib/ansible/module_utils/facts/hardware/__init__.py lib/ansible/module_utils/facts/hardware/aix.py lib/ansible/module_utils/facts/hardware/base.py lib/ansible/module_utils/facts/hardware/darwin.py lib/ansible/module_utils/facts/hardware/dragonfly.py lib/ansible/module_utils/facts/hardware/freebsd.py lib/ansible/module_utils/facts/hardware/hpux.py lib/ansible/module_utils/facts/hardware/hurd.py lib/ansible/module_utils/facts/hardware/linux.py lib/ansible/module_utils/facts/hardware/netbsd.py lib/ansible/module_utils/facts/hardware/openbsd.py lib/ansible/module_utils/facts/hardware/sunos.py lib/ansible/module_utils/facts/network/__init__.py lib/ansible/module_utils/facts/network/aix.py lib/ansible/module_utils/facts/network/base.py lib/ansible/module_utils/facts/network/darwin.py lib/ansible/module_utils/facts/network/dragonfly.py lib/ansible/module_utils/facts/network/fc_wwn.py lib/ansible/module_utils/facts/network/freebsd.py lib/ansible/module_utils/facts/network/generic_bsd.py lib/ansible/module_utils/facts/network/hpux.py lib/ansible/module_utils/facts/network/hurd.py lib/ansible/module_utils/facts/network/iscsi.py lib/ansible/module_utils/facts/network/linux.py lib/ansible/module_utils/facts/network/netbsd.py lib/ansible/module_utils/facts/network/nvme.py lib/ansible/module_utils/facts/network/openbsd.py lib/ansible/module_utils/facts/network/sunos.py lib/ansible/module_utils/facts/other/__init__.py lib/ansible/module_utils/facts/other/facter.py lib/ansible/module_utils/facts/other/ohai.py lib/ansible/module_utils/facts/system/__init__.py lib/ansible/module_utils/facts/system/apparmor.py lib/ansible/module_utils/facts/system/caps.py lib/ansible/module_utils/facts/system/chroot.py lib/ansible/module_utils/facts/system/cmdline.py lib/ansible/module_utils/facts/system/date_time.py lib/ansible/module_utils/facts/system/distribution.py lib/ansible/module_utils/facts/system/dns.py lib/ansible/module_utils/facts/system/env.py lib/ansible/module_utils/facts/system/fips.py lib/ansible/module_utils/facts/system/loadavg.py lib/ansible/module_utils/facts/system/local.py lib/ansible/module_utils/facts/system/lsb.py lib/ansible/module_utils/facts/system/pkg_mgr.py lib/ansible/module_utils/facts/system/platform.py lib/ansible/module_utils/facts/system/python.py lib/ansible/module_utils/facts/system/selinux.py lib/ansible/module_utils/facts/system/service_mgr.py lib/ansible/module_utils/facts/system/ssh_pub_keys.py lib/ansible/module_utils/facts/system/systemd.py lib/ansible/module_utils/facts/system/user.py lib/ansible/module_utils/facts/virtual/__init__.py lib/ansible/module_utils/facts/virtual/base.py lib/ansible/module_utils/facts/virtual/dragonfly.py lib/ansible/module_utils/facts/virtual/freebsd.py lib/ansible/module_utils/facts/virtual/hpux.py lib/ansible/module_utils/facts/virtual/linux.py lib/ansible/module_utils/facts/virtual/netbsd.py lib/ansible/module_utils/facts/virtual/openbsd.py lib/ansible/module_utils/facts/virtual/sunos.py lib/ansible/module_utils/facts/virtual/sysctl.py lib/ansible/module_utils/parsing/__init__.py lib/ansible/module_utils/parsing/convert_bool.py lib/ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.ArgvParser.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Backup.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.FileUtil.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.Legacy.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.LinkUtil.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.PrivilegeUtil.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.SID.psm1 lib/ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 lib/ansible/module_utils/powershell/__init__.py lib/ansible/module_utils/six/__init__.py lib/ansible/modules/__init__.py lib/ansible/modules/add_host.py lib/ansible/modules/apt.py lib/ansible/modules/apt_key.py lib/ansible/modules/apt_repository.py lib/ansible/modules/assemble.py lib/ansible/modules/assert.py lib/ansible/modules/async_status.py lib/ansible/modules/async_wrapper.py lib/ansible/modules/blockinfile.py lib/ansible/modules/command.py lib/ansible/modules/copy.py lib/ansible/modules/cron.py lib/ansible/modules/deb822_repository.py lib/ansible/modules/debconf.py lib/ansible/modules/debug.py lib/ansible/modules/dnf.py lib/ansible/modules/dnf5.py lib/ansible/modules/dpkg_selections.py lib/ansible/modules/expect.py lib/ansible/modules/fail.py lib/ansible/modules/fetch.py lib/ansible/modules/file.py lib/ansible/modules/find.py lib/ansible/modules/gather_facts.py lib/ansible/modules/get_url.py lib/ansible/modules/getent.py lib/ansible/modules/git.py lib/ansible/modules/group.py lib/ansible/modules/group_by.py lib/ansible/modules/hostname.py lib/ansible/modules/import_playbook.py lib/ansible/modules/import_role.py lib/ansible/modules/import_tasks.py lib/ansible/modules/include_role.py lib/ansible/modules/include_tasks.py lib/ansible/modules/include_vars.py lib/ansible/modules/iptables.py lib/ansible/modules/known_hosts.py lib/ansible/modules/lineinfile.py lib/ansible/modules/meta.py lib/ansible/modules/mount_facts.py lib/ansible/modules/package.py lib/ansible/modules/package_facts.py lib/ansible/modules/pause.py lib/ansible/modules/ping.py lib/ansible/modules/pip.py lib/ansible/modules/raw.py lib/ansible/modules/reboot.py lib/ansible/modules/replace.py lib/ansible/modules/rpm_key.py lib/ansible/modules/script.py lib/ansible/modules/service.py lib/ansible/modules/service_facts.py lib/ansible/modules/set_fact.py lib/ansible/modules/set_stats.py lib/ansible/modules/setup.py lib/ansible/modules/shell.py lib/ansible/modules/slurp.py lib/ansible/modules/stat.py lib/ansible/modules/subversion.py lib/ansible/modules/systemd.py lib/ansible/modules/systemd_service.py lib/ansible/modules/sysvinit.py lib/ansible/modules/tempfile.py lib/ansible/modules/template.py lib/ansible/modules/unarchive.py lib/ansible/modules/uri.py lib/ansible/modules/user.py lib/ansible/modules/validate_argument_spec.py lib/ansible/modules/wait_for.py lib/ansible/modules/wait_for_connection.py lib/ansible/modules/yum_repository.py lib/ansible/parsing/__init__.py lib/ansible/parsing/ajson.py lib/ansible/parsing/dataloader.py lib/ansible/parsing/mod_args.py lib/ansible/parsing/plugin_docs.py lib/ansible/parsing/quoting.py lib/ansible/parsing/splitter.py lib/ansible/parsing/utils/__init__.py lib/ansible/parsing/utils/addresses.py lib/ansible/parsing/utils/jsonify.py lib/ansible/parsing/utils/yaml.py lib/ansible/parsing/vault/__init__.py lib/ansible/parsing/yaml/__init__.py lib/ansible/parsing/yaml/dumper.py lib/ansible/parsing/yaml/loader.py lib/ansible/parsing/yaml/objects.py lib/ansible/playbook/__init__.py lib/ansible/playbook/attribute.py lib/ansible/playbook/base.py lib/ansible/playbook/block.py lib/ansible/playbook/collectionsearch.py lib/ansible/playbook/conditional.py lib/ansible/playbook/delegatable.py lib/ansible/playbook/handler.py lib/ansible/playbook/handler_task_include.py lib/ansible/playbook/helpers.py lib/ansible/playbook/included_file.py lib/ansible/playbook/loop_control.py lib/ansible/playbook/notifiable.py lib/ansible/playbook/play.py lib/ansible/playbook/play_context.py lib/ansible/playbook/playbook_include.py lib/ansible/playbook/role_include.py lib/ansible/playbook/taggable.py lib/ansible/playbook/task.py lib/ansible/playbook/task_include.py lib/ansible/playbook/role/__init__.py lib/ansible/playbook/role/definition.py lib/ansible/playbook/role/include.py lib/ansible/playbook/role/metadata.py lib/ansible/playbook/role/requirement.py lib/ansible/plugins/__init__.py lib/ansible/plugins/list.py lib/ansible/plugins/loader.py lib/ansible/plugins/action/__init__.py lib/ansible/plugins/action/add_host.py lib/ansible/plugins/action/assemble.py lib/ansible/plugins/action/assert.py lib/ansible/plugins/action/async_status.py lib/ansible/plugins/action/command.py lib/ansible/plugins/action/copy.py lib/ansible/plugins/action/debug.py lib/ansible/plugins/action/dnf.py lib/ansible/plugins/action/fail.py lib/ansible/plugins/action/fetch.py lib/ansible/plugins/action/gather_facts.py lib/ansible/plugins/action/group_by.py lib/ansible/plugins/action/include_vars.py lib/ansible/plugins/action/normal.py lib/ansible/plugins/action/package.py lib/ansible/plugins/action/pause.py lib/ansible/plugins/action/raw.py lib/ansible/plugins/action/reboot.py lib/ansible/plugins/action/script.py lib/ansible/plugins/action/service.py lib/ansible/plugins/action/set_fact.py lib/ansible/plugins/action/set_stats.py lib/ansible/plugins/action/shell.py lib/ansible/plugins/action/template.py lib/ansible/plugins/action/unarchive.py lib/ansible/plugins/action/uri.py lib/ansible/plugins/action/validate_argument_spec.py lib/ansible/plugins/action/wait_for_connection.py lib/ansible/plugins/become/__init__.py lib/ansible/plugins/become/runas.py lib/ansible/plugins/become/su.py lib/ansible/plugins/become/sudo.py lib/ansible/plugins/cache/__init__.py lib/ansible/plugins/cache/base.py lib/ansible/plugins/cache/jsonfile.py lib/ansible/plugins/cache/memory.py lib/ansible/plugins/callback/__init__.py lib/ansible/plugins/callback/default.py lib/ansible/plugins/callback/junit.py lib/ansible/plugins/callback/minimal.py lib/ansible/plugins/callback/oneline.py lib/ansible/plugins/callback/tree.py lib/ansible/plugins/cliconf/__init__.py lib/ansible/plugins/connection/__init__.py lib/ansible/plugins/connection/local.py lib/ansible/plugins/connection/paramiko_ssh.py lib/ansible/plugins/connection/psrp.py lib/ansible/plugins/connection/ssh.py lib/ansible/plugins/connection/winrm.py lib/ansible/plugins/doc_fragments/__init__.py lib/ansible/plugins/doc_fragments/action_common_attributes.py lib/ansible/plugins/doc_fragments/action_core.py lib/ansible/plugins/doc_fragments/backup.py lib/ansible/plugins/doc_fragments/checksum_common.py lib/ansible/plugins/doc_fragments/connection_pipelining.py lib/ansible/plugins/doc_fragments/constructed.py lib/ansible/plugins/doc_fragments/decrypt.py lib/ansible/plugins/doc_fragments/default_callback.py lib/ansible/plugins/doc_fragments/files.py lib/ansible/plugins/doc_fragments/inventory_cache.py lib/ansible/plugins/doc_fragments/result_format_callback.py lib/ansible/plugins/doc_fragments/return_common.py lib/ansible/plugins/doc_fragments/shell_common.py lib/ansible/plugins/doc_fragments/shell_windows.py lib/ansible/plugins/doc_fragments/template_common.py lib/ansible/plugins/doc_fragments/url.py lib/ansible/plugins/doc_fragments/url_windows.py lib/ansible/plugins/doc_fragments/validate.py lib/ansible/plugins/doc_fragments/vars_plugin_staging.py lib/ansible/plugins/filter/__init__.py lib/ansible/plugins/filter/b64decode.yml lib/ansible/plugins/filter/b64encode.yml lib/ansible/plugins/filter/basename.yml lib/ansible/plugins/filter/bool.yml lib/ansible/plugins/filter/checksum.yml lib/ansible/plugins/filter/combinations.yml lib/ansible/plugins/filter/combine.yml lib/ansible/plugins/filter/comment.yml lib/ansible/plugins/filter/commonpath.yml lib/ansible/plugins/filter/core.py lib/ansible/plugins/filter/dict2items.yml lib/ansible/plugins/filter/difference.yml lib/ansible/plugins/filter/dirname.yml lib/ansible/plugins/filter/encryption.py lib/ansible/plugins/filter/expanduser.yml lib/ansible/plugins/filter/expandvars.yml lib/ansible/plugins/filter/extract.yml lib/ansible/plugins/filter/fileglob.yml lib/ansible/plugins/filter/flatten.yml lib/ansible/plugins/filter/from_json.yml lib/ansible/plugins/filter/from_yaml.yml lib/ansible/plugins/filter/from_yaml_all.yml lib/ansible/plugins/filter/hash.yml lib/ansible/plugins/filter/human_readable.yml lib/ansible/plugins/filter/human_to_bytes.yml lib/ansible/plugins/filter/intersect.yml lib/ansible/plugins/filter/items2dict.yml lib/ansible/plugins/filter/log.yml lib/ansible/plugins/filter/mandatory.yml lib/ansible/plugins/filter/mathstuff.py lib/ansible/plugins/filter/md5.yml lib/ansible/plugins/filter/normpath.yml lib/ansible/plugins/filter/password_hash.yml lib/ansible/plugins/filter/path_join.yml lib/ansible/plugins/filter/permutations.yml lib/ansible/plugins/filter/pow.yml lib/ansible/plugins/filter/product.yml lib/ansible/plugins/filter/quote.yml lib/ansible/plugins/filter/random.yml lib/ansible/plugins/filter/realpath.yml lib/ansible/plugins/filter/regex_escape.yml lib/ansible/plugins/filter/regex_findall.yml lib/ansible/plugins/filter/regex_replace.yml lib/ansible/plugins/filter/regex_search.yml lib/ansible/plugins/filter/rekey_on_member.yml lib/ansible/plugins/filter/relpath.yml lib/ansible/plugins/filter/root.yml lib/ansible/plugins/filter/sha1.yml lib/ansible/plugins/filter/shuffle.yml lib/ansible/plugins/filter/split.yml lib/ansible/plugins/filter/splitext.yml lib/ansible/plugins/filter/strftime.yml lib/ansible/plugins/filter/subelements.yml lib/ansible/plugins/filter/symmetric_difference.yml lib/ansible/plugins/filter/ternary.yml lib/ansible/plugins/filter/to_datetime.yml lib/ansible/plugins/filter/to_json.yml lib/ansible/plugins/filter/to_nice_json.yml lib/ansible/plugins/filter/to_nice_yaml.yml lib/ansible/plugins/filter/to_uuid.yml lib/ansible/plugins/filter/to_yaml.yml lib/ansible/plugins/filter/type_debug.yml lib/ansible/plugins/filter/union.yml lib/ansible/plugins/filter/unique.yml lib/ansible/plugins/filter/unvault.yml lib/ansible/plugins/filter/urldecode.yml lib/ansible/plugins/filter/urls.py lib/ansible/plugins/filter/urlsplit.py lib/ansible/plugins/filter/vault.yml lib/ansible/plugins/filter/win_basename.yml lib/ansible/plugins/filter/win_dirname.yml lib/ansible/plugins/filter/win_splitdrive.yml lib/ansible/plugins/filter/zip.yml lib/ansible/plugins/filter/zip_longest.yml lib/ansible/plugins/httpapi/__init__.py lib/ansible/plugins/inventory/__init__.py lib/ansible/plugins/inventory/advanced_host_list.py lib/ansible/plugins/inventory/auto.py lib/ansible/plugins/inventory/constructed.py lib/ansible/plugins/inventory/generator.py lib/ansible/plugins/inventory/host_list.py lib/ansible/plugins/inventory/ini.py lib/ansible/plugins/inventory/script.py lib/ansible/plugins/inventory/toml.py lib/ansible/plugins/inventory/yaml.py lib/ansible/plugins/lookup/__init__.py lib/ansible/plugins/lookup/config.py lib/ansible/plugins/lookup/csvfile.py lib/ansible/plugins/lookup/dict.py lib/ansible/plugins/lookup/env.py lib/ansible/plugins/lookup/file.py lib/ansible/plugins/lookup/fileglob.py lib/ansible/plugins/lookup/first_found.py lib/ansible/plugins/lookup/indexed_items.py lib/ansible/plugins/lookup/ini.py lib/ansible/plugins/lookup/inventory_hostnames.py lib/ansible/plugins/lookup/items.py lib/ansible/plugins/lookup/lines.py lib/ansible/plugins/lookup/list.py lib/ansible/plugins/lookup/nested.py lib/ansible/plugins/lookup/password.py lib/ansible/plugins/lookup/pipe.py lib/ansible/plugins/lookup/random_choice.py lib/ansible/plugins/lookup/sequence.py lib/ansible/plugins/lookup/subelements.py lib/ansible/plugins/lookup/template.py lib/ansible/plugins/lookup/together.py lib/ansible/plugins/lookup/unvault.py lib/ansible/plugins/lookup/url.py lib/ansible/plugins/lookup/varnames.py lib/ansible/plugins/lookup/vars.py lib/ansible/plugins/netconf/__init__.py lib/ansible/plugins/shell/__init__.py lib/ansible/plugins/shell/cmd.py lib/ansible/plugins/shell/powershell.py lib/ansible/plugins/shell/sh.py lib/ansible/plugins/strategy/__init__.py lib/ansible/plugins/strategy/debug.py lib/ansible/plugins/strategy/free.py lib/ansible/plugins/strategy/host_pinned.py lib/ansible/plugins/strategy/linear.py lib/ansible/plugins/terminal/__init__.py lib/ansible/plugins/test/__init__.py lib/ansible/plugins/test/abs.yml lib/ansible/plugins/test/all.yml lib/ansible/plugins/test/any.yml lib/ansible/plugins/test/change.yml lib/ansible/plugins/test/changed.yml lib/ansible/plugins/test/contains.yml lib/ansible/plugins/test/core.py lib/ansible/plugins/test/directory.yml lib/ansible/plugins/test/exists.yml lib/ansible/plugins/test/failed.yml lib/ansible/plugins/test/failure.yml lib/ansible/plugins/test/falsy.yml lib/ansible/plugins/test/file.yml lib/ansible/plugins/test/files.py lib/ansible/plugins/test/finished.yml lib/ansible/plugins/test/is_abs.yml lib/ansible/plugins/test/is_dir.yml lib/ansible/plugins/test/is_file.yml lib/ansible/plugins/test/is_link.yml lib/ansible/plugins/test/is_mount.yml lib/ansible/plugins/test/is_same_file.yml lib/ansible/plugins/test/isnan.yml lib/ansible/plugins/test/issubset.yml lib/ansible/plugins/test/issuperset.yml lib/ansible/plugins/test/link.yml lib/ansible/plugins/test/link_exists.yml lib/ansible/plugins/test/match.yml lib/ansible/plugins/test/mathstuff.py lib/ansible/plugins/test/mount.yml lib/ansible/plugins/test/nan.yml lib/ansible/plugins/test/reachable.yml lib/ansible/plugins/test/regex.yml lib/ansible/plugins/test/same_file.yml lib/ansible/plugins/test/search.yml lib/ansible/plugins/test/skip.yml lib/ansible/plugins/test/skipped.yml lib/ansible/plugins/test/started.yml lib/ansible/plugins/test/subset.yml lib/ansible/plugins/test/succeeded.yml lib/ansible/plugins/test/success.yml lib/ansible/plugins/test/successful.yml lib/ansible/plugins/test/superset.yml lib/ansible/plugins/test/timedout.yml lib/ansible/plugins/test/truthy.yml lib/ansible/plugins/test/unreachable.yml lib/ansible/plugins/test/uri.py lib/ansible/plugins/test/uri.yml lib/ansible/plugins/test/url.yml lib/ansible/plugins/test/urn.yml lib/ansible/plugins/test/vault_encrypted.yml lib/ansible/plugins/test/vaulted_file.yml lib/ansible/plugins/test/version.yml lib/ansible/plugins/test/version_compare.yml lib/ansible/plugins/vars/__init__.py lib/ansible/plugins/vars/host_group_vars.py lib/ansible/template/__init__.py lib/ansible/utils/__init__.py lib/ansible/utils/_junit_xml.py lib/ansible/utils/cmd_functions.py lib/ansible/utils/color.py lib/ansible/utils/context_objects.py lib/ansible/utils/display.py lib/ansible/utils/encrypt.py lib/ansible/utils/fqcn.py lib/ansible/utils/galaxy.py lib/ansible/utils/hashing.py lib/ansible/utils/helpers.py lib/ansible/utils/jsonrpc.py lib/ansible/utils/listify.py lib/ansible/utils/lock.py lib/ansible/utils/multiprocessing.py lib/ansible/utils/path.py lib/ansible/utils/plugin_docs.py lib/ansible/utils/py3compat.py lib/ansible/utils/sentinel.py lib/ansible/utils/shlex.py lib/ansible/utils/singleton.py lib/ansible/utils/ssh_functions.py lib/ansible/utils/unicode.py lib/ansible/utils/unsafe_proxy.py lib/ansible/utils/vars.py lib/ansible/utils/version.py lib/ansible/utils/collection_loader/__init__.py lib/ansible/utils/collection_loader/_collection_config.py lib/ansible/utils/collection_loader/_collection_finder.py lib/ansible/utils/collection_loader/_collection_meta.py lib/ansible/vars/__init__.py lib/ansible/vars/clean.py lib/ansible/vars/hostvars.py lib/ansible/vars/manager.py lib/ansible/vars/plugins.py lib/ansible/vars/reserved.py licenses/Apache-License.txt licenses/BSD-3-Clause.txt licenses/MIT-license.txt licenses/PSF-license.txt licenses/simplified_bsd.txt packaging/release.py packaging/cli-doc/build.py packaging/cli-doc/man.j2 packaging/cli-doc/rst.j2 test/integration/network-integration.cfg test/integration/network-integration.requirements.txt test/integration/targets/add_host/aliases test/integration/targets/add_host/tasks/main.yml test/integration/targets/adhoc/aliases test/integration/targets/adhoc/runme.sh test/integration/targets/ansiballz_debug/aliases test/integration/targets/ansiballz_debug/tasks/main.yml test/integration/targets/ansiballz_python/aliases test/integration/targets/ansiballz_python/library/check_rlimit_and_maxfd.py test/integration/targets/ansiballz_python/library/custom_module.py test/integration/targets/ansiballz_python/library/sys_check.py test/integration/targets/ansiballz_python/module_utils/custom_util.py test/integration/targets/ansiballz_python/tasks/main.yml test/integration/targets/ansible/adhoc-callback.stdout test/integration/targets/ansible/aliases test/integration/targets/ansible/ansible-testé.cfg test/integration/targets/ansible/module_common_regex_regression.sh test/integration/targets/ansible/no-extension test/integration/targets/ansible/playbook.yml test/integration/targets/ansible/playbookdir_cfg.ini test/integration/targets/ansible/runme.sh test/integration/targets/ansible/vars.yml test/integration/targets/ansible-config/aliases test/integration/targets/ansible-config/files/base_all_valid.cfg test/integration/targets/ansible-config/files/base_valid.cfg test/integration/targets/ansible-config/files/empty.cfg test/integration/targets/ansible-config/files/galaxy_server.ini test/integration/targets/ansible-config/files/ini_dupes.py test/integration/targets/ansible-config/files/invalid_base.cfg test/integration/targets/ansible-config/files/invalid_plugins_config.ini test/integration/targets/ansible-config/tasks/main.yml test/integration/targets/ansible-console/aliases test/integration/targets/ansible-console/runme.sh test/integration/targets/ansible-doc/aliases test/integration/targets/ansible-doc/fakecollrole.output test/integration/targets/ansible-doc/fakemodule.output test/integration/targets/ansible-doc/fakerole.output test/integration/targets/ansible-doc/fix-urls.py test/integration/targets/ansible-doc/inventory test/integration/targets/ansible-doc/noop.output test/integration/targets/ansible-doc/noop_vars_plugin.output test/integration/targets/ansible-doc/notjsonfile.output test/integration/targets/ansible-doc/randommodule-text-verbose.output test/integration/targets/ansible-doc/randommodule-text.output test/integration/targets/ansible-doc/randommodule.output test/integration/targets/ansible-doc/runme.sh test/integration/targets/ansible-doc/test.yml test/integration/targets/ansible-doc/test_docs_returns.output test/integration/targets/ansible-doc/test_docs_suboptions.output test/integration/targets/ansible-doc/test_docs_yaml_anchors.output test/integration/targets/ansible-doc/yolo-text.output test/integration/targets/ansible-doc/yolo.output test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/MANIFEST.json test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/cache/notjsonfile.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/inventory/statichost.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/lookup/noop.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/modules/fakemodule.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/modules/notrealmodule.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/modules/randommodule.py test/integration/targets/ansible-doc/broken-docs/collections/ansible_collections/testns/testcol/plugins/vars/noop_vars_plugin.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/MANIFEST.json test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/cache/notjsonfile.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/filter/grouped.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/filter/ultimatequestion.yml test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/filter/filter_subdir/in_subdir.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/inventory/statichost.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/lookup/noop.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/modules/fakemodule.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/modules/notrealmodule.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/modules/randommodule.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/modules/database/database_type/subdir_module.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/test/test_test.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/test/yolo.yml test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/plugins/vars/noop_vars_plugin.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/roles/testrole/meta/main.yml test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol/roles/testrole_with_no_argspecs/meta/empty test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol2/MANIFEST.json test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol2/plugins/doc_fragments/deprecation.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol2/plugins/doc_fragments/module.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol2/plugins/doc_fragments/plugin.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol2/plugins/doc_fragments/version_added.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol3/galaxy.yml test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol3/plugins/modules/test1.py test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol4/galaxy.yml test/integration/targets/ansible-doc/collections/ansible_collections/testns/testcol4/plugins/modules/test2.py test/integration/targets/ansible-doc/filter_plugins/donothing.yml test/integration/targets/ansible-doc/filter_plugins/other.py test/integration/targets/ansible-doc/filter_plugins/split.yml test/integration/targets/ansible-doc/library/double_doc.py test/integration/targets/ansible-doc/library/test_docs.py test/integration/targets/ansible-doc/library/test_docs_missing_description.py test/integration/targets/ansible-doc/library/test_docs_no_metadata.py test/integration/targets/ansible-doc/library/test_docs_no_status.py test/integration/targets/ansible-doc/library/test_docs_non_iterable_status.py test/integration/targets/ansible-doc/library/test_docs_removed_precedence.py test/integration/targets/ansible-doc/library/test_docs_removed_status.py test/integration/targets/ansible-doc/library/test_docs_returns.py test/integration/targets/ansible-doc/library/test_docs_returns_broken.py test/integration/targets/ansible-doc/library/test_docs_suboptions.py test/integration/targets/ansible-doc/library/test_docs_yaml_anchors.py test/integration/targets/ansible-doc/library/test_empty.py test/integration/targets/ansible-doc/library/test_no_docs.py test/integration/targets/ansible-doc/library/test_no_docs_no_metadata.py test/integration/targets/ansible-doc/library/test_no_docs_no_status.py test/integration/targets/ansible-doc/library/test_no_docs_non_iterable_status.py test/integration/targets/ansible-doc/library/test_win_module.ps1 test/integration/targets/ansible-doc/library/test_win_module.yml test/integration/targets/ansible-doc/lookup_plugins/_deprecated_with_adj_docs.py test/integration/targets/ansible-doc/lookup_plugins/_deprecated_with_docs.py test/integration/targets/ansible-doc/lookup_plugins/broken_docs.py test/integration/targets/ansible-doc/lookup_plugins/deprecated_with_adj_docs.yml test/integration/targets/ansible-doc/roles/test_role1/meta/argument_specs.yml test/integration/targets/ansible-doc/roles/test_role1/meta/main.yml test/integration/targets/ansible-doc/roles/test_role2/meta/empty test/integration/targets/ansible-doc/roles/test_role3/meta/main.yml test/integration/targets/ansible-doc/test_role1/README.txt test/integration/targets/ansible-doc/test_role1/meta/main.yml test/integration/targets/ansible-galaxy/aliases test/integration/targets/ansible-galaxy/cleanup-default.yml test/integration/targets/ansible-galaxy/cleanup-freebsd.yml test/integration/targets/ansible-galaxy/cleanup.yml test/integration/targets/ansible-galaxy/runme.sh test/integration/targets/ansible-galaxy/setup.yml test/integration/targets/ansible-galaxy-collection/aliases test/integration/targets/ansible-galaxy-collection-cli/aliases test/integration/targets/ansible-galaxy-collection-cli/files/empty_manifest_galaxy.yml test/integration/targets/ansible-galaxy-collection-cli/files/expected.txt test/integration/targets/ansible-galaxy-collection-cli/files/expected_empty.txt test/integration/targets/ansible-galaxy-collection-cli/files/expected_full_manifest.txt test/integration/targets/ansible-galaxy-collection-cli/files/full_manifest_galaxy.yml test/integration/targets/ansible-galaxy-collection-cli/files/galaxy.yml test/integration/targets/ansible-galaxy-collection-cli/files/make_collection_dir.py test/integration/targets/ansible-galaxy-collection-cli/tasks/main.yml test/integration/targets/ansible-galaxy-collection-cli/tasks/manifest.yml test/integration/targets/ansible-galaxy-collection-scm/aliases test/integration/targets/ansible-galaxy-collection-scm/meta/main.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/download.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/empty_installed_collections.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/individual_collection_repo.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/main.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/multi_collection_repo_all.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/multi_collection_repo_individual.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/reinstalling.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/requirements.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/scm_dependency.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/scm_dependency_deduplication.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/setup.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/setup_collection_bad_version.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/setup_multi_collection_repo.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/setup_recursive_scm_dependency.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/test_invalid_version.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/test_manifest_metadata.yml test/integration/targets/ansible-galaxy-collection-scm/tasks/test_supported_resolvelib_versions.yml test/integration/targets/ansible-galaxy-collection-scm/templates/git_prefix_name.yml test/integration/targets/ansible-galaxy-collection-scm/templates/name_and_type.yml test/integration/targets/ansible-galaxy-collection-scm/templates/name_without_type.yml test/integration/targets/ansible-galaxy-collection-scm/templates/source_and_name.yml test/integration/targets/ansible-galaxy-collection-scm/templates/source_and_name_and_type.yml test/integration/targets/ansible-galaxy-collection-scm/templates/source_only.yml test/integration/targets/ansible-galaxy-collection-scm/vars/main.yml test/integration/targets/ansible-galaxy-collection/files/build_bad_tar.py test/integration/targets/ansible-galaxy-collection/files/test_module.py test/integration/targets/ansible-galaxy-collection/handlers/main.yml test/integration/targets/ansible-galaxy-collection/library/reset_pulp.py test/integration/targets/ansible-galaxy-collection/library/setup_collections.py test/integration/targets/ansible-galaxy-collection/meta/main.yml test/integration/targets/ansible-galaxy-collection/tasks/build.yml test/integration/targets/ansible-galaxy-collection/tasks/download.yml test/integration/targets/ansible-galaxy-collection/tasks/fail_fast_resolvelib.yml test/integration/targets/ansible-galaxy-collection/tasks/init.yml test/integration/targets/ansible-galaxy-collection/tasks/install.yml test/integration/targets/ansible-galaxy-collection/tasks/install_offline.yml test/integration/targets/ansible-galaxy-collection/tasks/list.yml test/integration/targets/ansible-galaxy-collection/tasks/main.yml test/integration/targets/ansible-galaxy-collection/tasks/pinned_pre_releases_in_deptree.yml test/integration/targets/ansible-galaxy-collection/tasks/publish.yml test/integration/targets/ansible-galaxy-collection/tasks/pulp.yml test/integration/targets/ansible-galaxy-collection/tasks/revoke_gpg_key.yml test/integration/targets/ansible-galaxy-collection/tasks/setup_gpg.yml test/integration/targets/ansible-galaxy-collection/tasks/supported_resolvelib.yml test/integration/targets/ansible-galaxy-collection/tasks/unsupported_resolvelib.yml test/integration/targets/ansible-galaxy-collection/tasks/upgrade.yml test/integration/targets/ansible-galaxy-collection/tasks/verify.yml test/integration/targets/ansible-galaxy-collection/tasks/virtual_direct_requests.yml test/integration/targets/ansible-galaxy-collection/templates/ansible.cfg.j2 test/integration/targets/ansible-galaxy-collection/vars/main.yml test/integration/targets/ansible-galaxy-role/aliases test/integration/targets/ansible-galaxy-role/files/create-role-archive.py test/integration/targets/ansible-galaxy-role/files/safe-symlinks/defaults/main.yml test/integration/targets/ansible-galaxy-role/files/safe-symlinks/defaults/common_vars/subdir/group0/main.yml test/integration/targets/ansible-galaxy-role/files/safe-symlinks/handlers/utils.yml test/integration/targets/ansible-galaxy-role/files/safe-symlinks/meta/main.yml test/integration/targets/ansible-galaxy-role/files/safe-symlinks/tasks/utils/suite.yml test/integration/targets/ansible-galaxy-role/meta/main.yml test/integration/targets/ansible-galaxy-role/tasks/dir-traversal.yml test/integration/targets/ansible-galaxy-role/tasks/main.yml test/integration/targets/ansible-galaxy-role/tasks/valid-role-symlinks.yml test/integration/targets/ansible-galaxy/files/testserver.py test/integration/targets/ansible-inventory/aliases test/integration/targets/ansible-inventory/post_inventory.yml test/integration/targets/ansible-inventory/runme.sh test/integration/targets/ansible-inventory/test.yml test/integration/targets/ansible-inventory/with_untrusted.yml test/integration/targets/ansible-inventory/with_untrusted_expected.json test/integration/targets/ansible-inventory/files/complex.ini test/integration/targets/ansible-inventory/files/unicode.yml test/integration/targets/ansible-inventory/files/valid_sample.toml test/integration/targets/ansible-inventory/files/valid_sample.yml test/integration/targets/ansible-inventory/filter_plugins/toml.py test/integration/targets/ansible-inventory/tasks/json_output.yml test/integration/targets/ansible-inventory/tasks/main.yml test/integration/targets/ansible-inventory/tasks/toml.yml test/integration/targets/ansible-inventory/tasks/toml_output.yml test/integration/targets/ansible-inventory/tasks/yaml_output.yml test/integration/targets/ansible-playbook-callbacks/aliases test/integration/targets/ansible-playbook-callbacks/all-callbacks.yml test/integration/targets/ansible-playbook-callbacks/callback_list_include_role_fail.expected test/integration/targets/ansible-playbook-callbacks/callbacks_list.expected test/integration/targets/ansible-playbook-callbacks/include_me.yml test/integration/targets/ansible-playbook-callbacks/include_role-fail.yml test/integration/targets/ansible-playbook-callbacks/runme.sh test/integration/targets/ansible-pull/aliases test/integration/targets/ansible-pull/cleanup.yml test/integration/targets/ansible-pull/runme.sh test/integration/targets/ansible-pull/setup.yml test/integration/targets/ansible-pull/pull-integration-test/ansible.cfg test/integration/targets/ansible-pull/pull-integration-test/conn_secret.yml test/integration/targets/ansible-pull/pull-integration-test/gather_facts.yml test/integration/targets/ansible-pull/pull-integration-test/inventory test/integration/targets/ansible-pull/pull-integration-test/local.yml test/integration/targets/ansible-pull/pull-integration-test/multi_play_1.yml test/integration/targets/ansible-pull/pull-integration-test/multi_play_2.yml test/integration/targets/ansible-pull/pull-integration-test/secret_connection_password test/integration/targets/ansible-pull/pull-integration-test/test_empty_facts.yml test/integration/targets/ansible-test/aliases test/integration/targets/ansible-test/venv-pythons.py test/integration/targets/ansible-test-cloud-acme/aliases test/integration/targets/ansible-test-cloud-acme/tasks/main.yml test/integration/targets/ansible-test-cloud-aws/aliases test/integration/targets/ansible-test-cloud-aws/tasks/main.yml test/integration/targets/ansible-test-cloud-azure/aliases test/integration/targets/ansible-test-cloud-azure/tasks/main.yml test/integration/targets/ansible-test-cloud-cs/aliases test/integration/targets/ansible-test-cloud-cs/tasks/main.yml test/integration/targets/ansible-test-cloud-galaxy/aliases test/integration/targets/ansible-test-cloud-galaxy/tasks/main.yml test/integration/targets/ansible-test-cloud-httptester/aliases test/integration/targets/ansible-test-cloud-httptester-windows/aliases test/integration/targets/ansible-test-cloud-httptester-windows/tasks/main.yml test/integration/targets/ansible-test-cloud-httptester/tasks/main.yml test/integration/targets/ansible-test-cloud-nios/aliases test/integration/targets/ansible-test-cloud-nios/tasks/main.yml test/integration/targets/ansible-test-cloud-openshift/aliases test/integration/targets/ansible-test-cloud-openshift/tasks/main.yml test/integration/targets/ansible-test-config/aliases test/integration/targets/ansible-test-config/runme.sh test/integration/targets/ansible-test-config-invalid/aliases test/integration/targets/ansible-test-config-invalid/runme.sh test/integration/targets/ansible-test-config-invalid/ansible_collections/ns/col/tests/config.yml test/integration/targets/ansible-test-config-invalid/ansible_collections/ns/col/tests/integration/targets/test/aliases test/integration/targets/ansible-test-config-invalid/ansible_collections/ns/col/tests/integration/targets/test/runme.sh test/integration/targets/ansible-test-config-invalid/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_test.py test/integration/targets/ansible-test-config/ansible_collections/ns/col/plugins/module_utils/test.py test/integration/targets/ansible-test-config/ansible_collections/ns/col/tests/config.yml test/integration/targets/ansible-test-config/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_test.py test/integration/targets/ansible-test-container/aliases test/integration/targets/ansible-test-container/runme.py test/integration/targets/ansible-test-container/runme.sh test/integration/targets/ansible-test-coverage/aliases test/integration/targets/ansible-test-coverage/runme.sh test/integration/targets/ansible-test-coverage-windows/aliases test/integration/targets/ansible-test-coverage-windows/runme.sh test/integration/targets/ansible-test-coverage-windows/test-coverage.py test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/plugins/module_utils/CollectionPwshCoverage.psm1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/plugins/modules/win_collection.ps1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/tests/integration/targets/win_collection/library/test_win_collection_async.ps1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/tests/integration/targets/win_collection/library/test_win_collection_become.ps1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/tests/integration/targets/win_collection/library/test_win_collection_normal.ps1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/tests/integration/targets/win_collection/module_utils/Ansible.ModuleUtils.AdjacentPwshCoverage.psm1 test/integration/targets/ansible-test-coverage-windows/ansible_collections/ns/col/tests/integration/targets/win_collection/tasks/main.yml test/integration/targets/ansible-test-coverage/ansible_collections/ns/col/plugins/module_utils/test_util.py test/integration/targets/ansible-test-docker/aliases test/integration/targets/ansible-test-docker/runme.sh test/integration/targets/ansible-test-docker/ansible_collections/ns/col/galaxy.yml test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/doc_fragments/ps_util.py test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/module_utils/PSUtil.psm1 test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/module_utils/my_util.py test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/modules/hello.py test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/modules/win_util_args.ps1 test/integration/targets/ansible-test-docker/ansible_collections/ns/col/plugins/modules/win_util_args.py test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/integration/targets/minimal/aliases test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/integration/targets/minimal/tasks/main.yml test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_my_util.py test/integration/targets/ansible-test-docker/ansible_collections/ns/col/tests/unit/plugins/modules/test_hello.py test/integration/targets/ansible-test-git/aliases test/integration/targets/ansible-test-git/runme.sh test/integration/targets/ansible-test-git/ansible_collections/ns/col/tests/.keep test/integration/targets/ansible-test-git/collection-tests/git-at-collection-base.sh test/integration/targets/ansible-test-git/collection-tests/git-at-collection-root.sh test/integration/targets/ansible-test-git/collection-tests/git-common.bash test/integration/targets/ansible-test-git/collection-tests/install-git.yml test/integration/targets/ansible-test-git/collection-tests/uninstall-git.yml test/integration/targets/ansible-test-installed/aliases test/integration/targets/ansible-test-installed/runme.sh test/integration/targets/ansible-test-installed/ansible_collections/ns/col/tests/integration/targets/installed/aliases test/integration/targets/ansible-test-installed/ansible_collections/ns/col/tests/integration/targets/installed/runme.sh test/integration/targets/ansible-test-integration/aliases test/integration/targets/ansible-test-integration/runme.sh test/integration/targets/ansible-test-integration-constraints/aliases test/integration/targets/ansible-test-integration-constraints/runme.sh test/integration/targets/ansible-test-integration-constraints/ansible_collections/ns/col/tests/integration/constraints.txt test/integration/targets/ansible-test-integration-constraints/ansible_collections/ns/col/tests/integration/requirements.txt test/integration/targets/ansible-test-integration-constraints/ansible_collections/ns/col/tests/integration/targets/constraints/aliases test/integration/targets/ansible-test-integration-constraints/ansible_collections/ns/col/tests/integration/targets/constraints/tasks/main.yml test/integration/targets/ansible-test-integration-no-exec-script/aliases test/integration/targets/ansible-test-integration-no-exec-script/runme.sh test/integration/targets/ansible-test-integration-no-exec-script/ansible_collections/ns/col/tests/integration/targets/hello/aliases test/integration/targets/ansible-test-integration-no-exec-script/ansible_collections/ns/col/tests/integration/targets/hello/runme.sh test/integration/targets/ansible-test-integration-targets/aliases test/integration/targets/ansible-test-integration-targets/runme.sh test/integration/targets/ansible-test-integration-targets/test.py test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/target-prefixes.something test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/destructive_a/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/destructive_b/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/disabled_a/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/disabled_b/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/one-part_test/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/two_part_test/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/unstable_a/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/unstable_b/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/unsupported_a/aliases test/integration/targets/ansible-test-integration-targets/ansible_collections/ns/col/tests/integration/targets/unsupported_b/aliases test/integration/targets/ansible-test-integration/ansible_collections/ns/col/plugins/module_utils/my_util.py test/integration/targets/ansible-test-integration/ansible_collections/ns/col/plugins/modules/hello.py test/integration/targets/ansible-test-integration/ansible_collections/ns/col/tests/integration/targets/hello/aliases test/integration/targets/ansible-test-integration/ansible_collections/ns/col/tests/integration/targets/hello/tasks/main.yml test/integration/targets/ansible-test-no-tty/aliases test/integration/targets/ansible-test-no-tty/runme.sh test/integration/targets/ansible-test-no-tty/ansible_collections/ns/col/run-with-pty.py test/integration/targets/ansible-test-no-tty/ansible_collections/ns/col/vendored_pty.py test/integration/targets/ansible-test-no-tty/ansible_collections/ns/col/tests/integration/targets/no-tty/aliases test/integration/targets/ansible-test-no-tty/ansible_collections/ns/col/tests/integration/targets/no-tty/assert-no-tty.py test/integration/targets/ansible-test-no-tty/ansible_collections/ns/col/tests/integration/targets/no-tty/runme.sh test/integration/targets/ansible-test-sanity/aliases test/integration/targets/ansible-test-sanity/runme.sh test/integration/targets/ansible-test-sanity-action-plugin-docs/aliases test/integration/targets/ansible-test-sanity-action-plugin-docs/runme.sh test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/action/other.yml test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/action/with_py.py test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/action/with_yaml.py test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/action/with_yml.py test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/modules/with_py.py test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/modules/with_yaml.yaml test/integration/targets/ansible-test-sanity-action-plugin-docs/ansible_collections/ns/col/plugins/modules/with_yml.yml test/integration/targets/ansible-test-sanity-ansible-doc/aliases test/integration/targets/ansible-test-sanity-ansible-doc/runme.sh test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/lookup/lookup1.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/lookup/a/b/lookup2.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/_module3.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/module1.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/a/b/module2.py test/integration/targets/ansible-test-sanity-import/aliases test/integration/targets/ansible-test-sanity-import/expected.txt test/integration/targets/ansible-test-sanity-import/runme.sh test/integration/targets/ansible-test-sanity-import/ansible_collections/ns/col/plugins/lookup/vendor1.py test/integration/targets/ansible-test-sanity-import/ansible_collections/ns/col/plugins/lookup/vendor2.py test/integration/targets/ansible-test-sanity-lint/aliases test/integration/targets/ansible-test-sanity-lint/expected.txt test/integration/targets/ansible-test-sanity-lint/runme.sh test/integration/targets/ansible-test-sanity-no-get-exception/aliases test/integration/targets/ansible-test-sanity-no-get-exception/expected.txt test/integration/targets/ansible-test-sanity-no-get-exception/runme.sh test/integration/targets/ansible-test-sanity-no-get-exception/ansible_collections/ns/col/do-not-check-me.py test/integration/targets/ansible-test-sanity-no-get-exception/ansible_collections/ns/col/plugins/modules/check-me.py test/integration/targets/ansible-test-sanity-pylint/aliases test/integration/targets/ansible-test-sanity-pylint/deprecated_thing.py test/integration/targets/ansible-test-sanity-pylint/expected.txt test/integration/targets/ansible-test-sanity-pylint/runme.sh test/integration/targets/ansible-test-sanity-pylint/ansible_collections/ns/col/galaxy.yml test/integration/targets/ansible-test-sanity-pylint/ansible_collections/ns/col/plugins/action/do_deprecated_stuff.py test/integration/targets/ansible-test-sanity-pylint/ansible_collections/ns/col/plugins/lookup/deprecated.py test/integration/targets/ansible-test-sanity-pylint/ansible_collections/ns/col/plugins/module_utils/deprecated_utils.py test/integration/targets/ansible-test-sanity-replace-urlopen/aliases test/integration/targets/ansible-test-sanity-replace-urlopen/expected.txt test/integration/targets/ansible-test-sanity-replace-urlopen/runme.sh test/integration/targets/ansible-test-sanity-replace-urlopen/ansible_collections/ns/col/do-not-check-me.py test/integration/targets/ansible-test-sanity-replace-urlopen/ansible_collections/ns/col/plugins/modules/check-me.py test/integration/targets/ansible-test-sanity-runtime-metadata/aliases test/integration/targets/ansible-test-sanity-runtime-metadata/expected-no_version.txt test/integration/targets/ansible-test-sanity-runtime-metadata/expected-version.txt test/integration/targets/ansible-test-sanity-runtime-metadata/runme.sh test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/galaxy.yml test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/meta/runtime.yml test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/galaxy.yml test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/meta/runtime.yml test/integration/targets/ansible-test-sanity-shebang/aliases test/integration/targets/ansible-test-sanity-shebang/expected.txt test/integration/targets/ansible-test-sanity-shebang/runme.sh test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/plugins/modules/powershell.ps1 test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/plugins/modules/python-no-shebang.py test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/plugins/modules/python.py test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/scripts/env_bash.sh test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/scripts/env_python.py test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/scripts/sh.sh test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/tests/integration/targets/valid/env_bash.sh test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/tests/integration/targets/valid/env_python.py test/integration/targets/ansible-test-sanity-shebang/ansible_collections/ns/col/tests/integration/targets/valid/sh.sh test/integration/targets/ansible-test-sanity-use-compat-six/aliases test/integration/targets/ansible-test-sanity-use-compat-six/expected.txt test/integration/targets/ansible-test-sanity-use-compat-six/runme.sh test/integration/targets/ansible-test-sanity-use-compat-six/ansible_collections/ns/col/do-not-check-me.py test/integration/targets/ansible-test-sanity-use-compat-six/ansible_collections/ns/col/plugins/modules/check-me.py test/integration/targets/ansible-test-sanity-validate-modules/aliases test/integration/targets/ansible-test-sanity-validate-modules/expected.txt test/integration/targets/ansible-test-sanity-validate-modules/runme.sh test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/meta/runtime.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/lookup/import_order_lookup.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/_not_deprecated.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_1.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_2.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_3.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_4.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_5.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_6.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/check_mode_attribute_7.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/import_order.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/invalid_argument_spec_extra_key.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/invalid_argument_spec_incorrect_context.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/invalid_choice_value.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/invalid_yaml_syntax.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/no_callable.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/option_name_casing.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/semantic_markup.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/sidecar.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/sidecar.yaml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/unsupported_extension.nope test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/valid_argument_spec_context.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/col/plugins/modules/wrong_aliases.py test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/README.md test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/galaxy.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/meta/main.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/meta/runtime.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/plugins/modules/failure_ps.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/failure/plugins/modules/failure_ps.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/README.md test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/galaxy.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/meta/runtime.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/module_utils/share_module.psm1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/module_utils/validate.psm1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/in_function.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/in_function.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/sidecar.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/sidecar.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_ansible_requires.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/util_optional.yml test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/validate.ps1 test/integration/targets/ansible-test-sanity-validate-modules/ansible_collections/ns/ps_only/plugins/modules/validate.py test/integration/targets/ansible-test-sanity-yamllint/aliases test/integration/targets/ansible-test-sanity-yamllint/expected.txt test/integration/targets/ansible-test-sanity-yamllint/runme.sh test/integration/targets/ansible-test-sanity-yamllint/ansible_collections/ns/col/plugins/inventory/inventory1.py test/integration/targets/ansible-test-sanity-yamllint/ansible_collections/ns/col/plugins/modules/module1.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/README.md test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/galaxy.yml test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/meta/runtime.yml test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/lookup/bad.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/lookup/world.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/module_utils/__init__.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/modules/bad.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/plugin_utils/check_pylint.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/plugins/random_directory/bad.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/tests/integration/targets/hello/files/bad.py test/integration/targets/ansible-test-sanity/ansible_collections/ns/col/tests/sanity/ignore.txt test/integration/targets/ansible-test-shell/aliases test/integration/targets/ansible-test-shell/expected-stderr.txt test/integration/targets/ansible-test-shell/expected-stdout.txt test/integration/targets/ansible-test-shell/runme.sh test/integration/targets/ansible-test-shell/ansible_collections/ns/col/.keep test/integration/targets/ansible-test-units/aliases test/integration/targets/ansible-test-units/runme.sh test/integration/targets/ansible-test-units-assertions/aliases test/integration/targets/ansible-test-units-assertions/runme.sh test/integration/targets/ansible-test-units-assertions/ansible_collections/ns/col/tests/unit/plugins/modules/test_assertion.py test/integration/targets/ansible-test-units-constraints/aliases test/integration/targets/ansible-test-units-constraints/runme.sh test/integration/targets/ansible-test-units-constraints/ansible_collections/ns/col/tests/unit/constraints.txt test/integration/targets/ansible-test-units-constraints/ansible_collections/ns/col/tests/unit/requirements.txt test/integration/targets/ansible-test-units-constraints/ansible_collections/ns/col/tests/unit/plugins/modules/test_constraints.py test/integration/targets/ansible-test-units-forked/aliases test/integration/targets/ansible-test-units-forked/runme.sh test/integration/targets/ansible-test-units-forked/ansible_collections/ns/col/tests/unit/plugins/modules/test_ansible_forked.py test/integration/targets/ansible-test-units/ansible_collections/ns/col/plugins/module_utils/my_util.py test/integration/targets/ansible-test-units/ansible_collections/ns/col/plugins/modules/hello.py test/integration/targets/ansible-test-units/ansible_collections/ns/col/tests/unit/plugins/module_utils/test_my_util.py test/integration/targets/ansible-test-units/ansible_collections/ns/col/tests/unit/plugins/modules/test_hello.py test/integration/targets/ansible-test-unsupported-directory/aliases test/integration/targets/ansible-test-unsupported-directory/runme.sh test/integration/targets/ansible-test-unsupported-directory/ansible_collections/ns/col/.keep test/integration/targets/ansible-test-vendoring/aliases test/integration/targets/ansible-test-vendoring/runme.sh test/integration/targets/ansible-test-vendoring/ansible_collections/ns/col/tests/config.yml test/integration/targets/ansible-vault/aliases test/integration/targets/ansible-vault/empty-password test/integration/targets/ansible-vault/encrypted-vault-password test/integration/targets/ansible-vault/encrypted_file_encrypted_var_password test/integration/targets/ansible-vault/example1_password test/integration/targets/ansible-vault/example2_password test/integration/targets/ansible-vault/example3_password test/integration/targets/ansible-vault/faux-editor.py test/integration/targets/ansible-vault/format_1_1_AES256.yml test/integration/targets/ansible-vault/format_1_2_AES256.yml test/integration/targets/ansible-vault/inventory.toml test/integration/targets/ansible-vault/password-script.py test/integration/targets/ansible-vault/realpath.yml test/integration/targets/ansible-vault/runme.sh test/integration/targets/ansible-vault/single_vault_as_string.yml test/integration/targets/ansible-vault/symlink.yml test/integration/targets/ansible-vault/test-vault-client.py test/integration/targets/ansible-vault/test_dangling_temp.yml test/integration/targets/ansible-vault/test_utf8_value_in_filename.yml test/integration/targets/ansible-vault/test_vault.yml test/integration/targets/ansible-vault/test_vault_embedded.yml test/integration/targets/ansible-vault/test_vault_embedded_ids.yml test/integration/targets/ansible-vault/test_vault_file_encrypted_embedded.yml test/integration/targets/ansible-vault/test_vaulted_inventory.yml test/integration/targets/ansible-vault/test_vaulted_inventory_toml.yml test/integration/targets/ansible-vault/test_vaulted_template.yml test/integration/targets/ansible-vault/test_vaulted_utf8_value.yml test/integration/targets/ansible-vault/vault-café.yml test/integration/targets/ansible-vault/vault-password test/integration/targets/ansible-vault/vault-password-ansible test/integration/targets/ansible-vault/vault-password-wrong test/integration/targets/ansible-vault/vault-secret.txt test/integration/targets/ansible-vault/vaulted.inventory test/integration/targets/ansible-vault/files/test_assemble/nonsecret.txt test/integration/targets/ansible-vault/files/test_assemble/secret.vault test/integration/targets/ansible-vault/host_vars/myhost.yml test/integration/targets/ansible-vault/host_vars/testhost.yml test/integration/targets/ansible-vault/invalid_format/README.md test/integration/targets/ansible-vault/invalid_format/broken-group-vars-tasks.yml test/integration/targets/ansible-vault/invalid_format/broken-host-vars-tasks.yml test/integration/targets/ansible-vault/invalid_format/inventory test/integration/targets/ansible-vault/invalid_format/original-broken-host-vars test/integration/targets/ansible-vault/invalid_format/original-group-vars.yml test/integration/targets/ansible-vault/invalid_format/some-vars test/integration/targets/ansible-vault/invalid_format/vault-secret test/integration/targets/ansible-vault/invalid_format/group_vars/broken-group-vars.yml test/integration/targets/ansible-vault/invalid_format/host_vars/broken-host-vars.example.com/vars test/integration/targets/ansible-vault/roles/test_vault/tasks/main.yml test/integration/targets/ansible-vault/roles/test_vault/vars/main.yml test/integration/targets/ansible-vault/roles/test_vault_embedded/tasks/main.yml test/integration/targets/ansible-vault/roles/test_vault_embedded/vars/main.yml test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/tasks/main.yml test/integration/targets/ansible-vault/roles/test_vault_embedded_ids/vars/main.yml test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/README.md test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/tasks/main.yml test/integration/targets/ansible-vault/roles/test_vault_file_encrypted_embedded/vars/main.yml test/integration/targets/ansible-vault/roles/test_vaulted_template/tasks/main.yml test/integration/targets/ansible-vault/roles/test_vaulted_template/templates/vaulted_template.j2 test/integration/targets/ansible-vault/script/vault-secret.sh test/integration/targets/ansible-vault/symlink/get-password-symlink test/integration/targets/ansible-vault/vars/vaulted.yml test/integration/targets/ansible/callback_plugins/callback_meta.py test/integration/targets/ansible_log/aliases test/integration/targets/ansible_log/logit.yml test/integration/targets/ansible_log/runme.sh test/integration/targets/any_errors_fatal/31543.yml test/integration/targets/any_errors_fatal/36308.yml test/integration/targets/any_errors_fatal/50897.yml test/integration/targets/any_errors_fatal/73246.yml test/integration/targets/any_errors_fatal/80981.yml test/integration/targets/any_errors_fatal/aliases test/integration/targets/any_errors_fatal/always_block.yml test/integration/targets/any_errors_fatal/inventory test/integration/targets/any_errors_fatal/on_includes.yml test/integration/targets/any_errors_fatal/play_level.yml test/integration/targets/any_errors_fatal/runme.sh test/integration/targets/any_errors_fatal/test_fatal.yml test/integration/targets/apt/aliases test/integration/targets/apt/defaults/main.yml test/integration/targets/apt/handlers/main.yml test/integration/targets/apt/meta/main.yml test/integration/targets/apt/tasks/apt-builddep.yml test/integration/targets/apt/tasks/apt-multiarch.yml test/integration/targets/apt/tasks/apt.yml test/integration/targets/apt/tasks/downgrade.yml test/integration/targets/apt/tasks/main.yml test/integration/targets/apt/tasks/repo.yml test/integration/targets/apt/tasks/upgrade.yml test/integration/targets/apt/tasks/upgrade_autoremove.yml test/integration/targets/apt/tasks/upgrade_scenarios.yml test/integration/targets/apt/tasks/url-with-deps.yml test/integration/targets/apt/vars/Ubuntu-22.yml test/integration/targets/apt/vars/Ubuntu-24.yml test/integration/targets/apt/vars/default.yml test/integration/targets/apt/vars/arch/amd64.yml test/integration/targets/apt/vars/arch/arm64.yml test/integration/targets/apt_key/aliases test/integration/targets/apt_key/meta/main.yml test/integration/targets/apt_key/tasks/apt_key.yml test/integration/targets/apt_key/tasks/apt_key_binary.yml test/integration/targets/apt_key/tasks/apt_key_inline_data.yml test/integration/targets/apt_key/tasks/file.yml test/integration/targets/apt_key/tasks/main.yml test/integration/targets/apt_repository/aliases test/integration/targets/apt_repository/tasks/apt.yml test/integration/targets/apt_repository/tasks/cleanup.yml test/integration/targets/apt_repository/tasks/main.yml test/integration/targets/apt_repository/tasks/mode.yaml test/integration/targets/apt_repository/tasks/mode_cleanup.yaml test/integration/targets/args/aliases test/integration/targets/args/runme.sh test/integration/targets/argspec/aliases test/integration/targets/argspec/runme.sh test/integration/targets/argspec/collections/ansible_collections/foo/bar/plugins/modules/argspec.py test/integration/targets/argspec/roles/argspec/meta/main.yml test/integration/targets/argspec/roles/argspec/tasks/main.yml test/integration/targets/argspec/roles/argspec/tasks/password_no_log.yml test/integration/targets/assemble/aliases test/integration/targets/assemble/files/fragment1 test/integration/targets/assemble/files/fragment2 test/integration/targets/assemble/files/fragment3 test/integration/targets/assemble/files/fragment4 test/integration/targets/assemble/files/fragment5 test/integration/targets/assemble/meta/main.yml test/integration/targets/assemble/tasks/main.yml test/integration/targets/assert/aliases test/integration/targets/assert/lookup_plugins/yield_terms.py test/integration/targets/assert/tasks/main.yml test/integration/targets/async/aliases test/integration/targets/async/callback_test.yml test/integration/targets/async/check_task_test.yml test/integration/targets/async/library/async_test.py test/integration/targets/async/meta/main.yml test/integration/targets/async/tasks/main.yml test/integration/targets/async_extra_data/aliases test/integration/targets/async_extra_data/runme.sh test/integration/targets/async_extra_data/test_async.yml test/integration/targets/async_extra_data/library/junkping.py test/integration/targets/async_fail/aliases test/integration/targets/async_fail/action_plugins/normal.py test/integration/targets/async_fail/library/async_test.py test/integration/targets/async_fail/meta/main.yml test/integration/targets/async_fail/tasks/main.yml test/integration/targets/become/aliases test/integration/targets/become/files/copy.txt test/integration/targets/become/meta/main.yml test/integration/targets/become/tasks/become.yml test/integration/targets/become/tasks/main.yml test/integration/targets/become/vars/main.yml test/integration/targets/become_su/aliases test/integration/targets/become_su/files/sushim.sh test/integration/targets/become_su/tasks/main.yml test/integration/targets/become_sudo/aliases test/integration/targets/become_sudo/files/sudoshim.sh test/integration/targets/become_sudo/tasks/main.yml test/integration/targets/become_unprivileged/aliases test/integration/targets/become_unprivileged/cleanup_unpriv_users.yml test/integration/targets/become_unprivileged/inventory test/integration/targets/become_unprivileged/runme.sh test/integration/targets/become_unprivileged/setup_unpriv_users.yml test/integration/targets/become_unprivileged/action_plugins/tmpdir.py test/integration/targets/become_unprivileged/chmod_acl_macos/test.yml test/integration/targets/become_unprivileged/common_remote_group/cleanup.yml test/integration/targets/become_unprivileged/common_remote_group/setup.yml test/integration/targets/become_unprivileged/common_remote_group/test.yml test/integration/targets/binary/aliases test/integration/targets/binary/files/b64_latin1 test/integration/targets/binary/files/b64_utf8 test/integration/targets/binary/files/from_playbook test/integration/targets/binary/meta/main.yml test/integration/targets/binary/tasks/main.yml test/integration/targets/binary/templates/b64_latin1_template.j2 test/integration/targets/binary/templates/b64_utf8_template.j2 test/integration/targets/binary/templates/from_playbook_template.j2 test/integration/targets/binary/vars/main.yml test/integration/targets/binary_modules/aliases test/integration/targets/binary_modules/build.py test/integration/targets/binary_modules/download_binary_modules.yml test/integration/targets/binary_modules/test.sh test/integration/targets/binary_modules/test_binary_modules.yml test/integration/targets/binary_modules/group_vars/all test/integration/targets/binary_modules/library/.gitignore test/integration/targets/binary_modules/library/helloworld.go test/integration/targets/binary_modules/roles/test_binary_modules/tasks/main.yml test/integration/targets/binary_modules_posix/aliases test/integration/targets/binary_modules_posix/runme.sh test/integration/targets/binary_modules_winrm/aliases test/integration/targets/binary_modules_winrm/runme.sh test/integration/targets/blockinfile/aliases test/integration/targets/blockinfile/files/sshd_config test/integration/targets/blockinfile/meta/main.yml test/integration/targets/blockinfile/tasks/add_block_to_existing_file.yml test/integration/targets/blockinfile/tasks/append_newline.yml test/integration/targets/blockinfile/tasks/block_without_trailing_newline.yml test/integration/targets/blockinfile/tasks/create_dir.yml test/integration/targets/blockinfile/tasks/create_file.yml test/integration/targets/blockinfile/tasks/diff.yml test/integration/targets/blockinfile/tasks/file_without_trailing_newline.yml test/integration/targets/blockinfile/tasks/insertafter.yml test/integration/targets/blockinfile/tasks/insertbefore.yml test/integration/targets/blockinfile/tasks/main.yml test/integration/targets/blockinfile/tasks/multiline_search.yml test/integration/targets/blockinfile/tasks/prepend_newline.yml test/integration/targets/blockinfile/tasks/preserve_line_endings.yml test/integration/targets/blockinfile/tasks/validate.yml test/integration/targets/blocks/43191-2.yml test/integration/targets/blocks/43191.yml test/integration/targets/blocks/69848.yml test/integration/targets/blocks/72725.yml test/integration/targets/blocks/72781.yml test/integration/targets/blocks/78612.yml test/integration/targets/blocks/79711.yml test/integration/targets/blocks/aliases test/integration/targets/blocks/always_failure_no_rescue_rc.yml test/integration/targets/blocks/always_failure_with_rescue_rc.yml test/integration/targets/blocks/always_no_rescue_rc.yml test/integration/targets/blocks/block_fail.yml test/integration/targets/blocks/block_fail_tasks.yml test/integration/targets/blocks/block_in_rescue.yml test/integration/targets/blocks/block_rescue_vars.yml test/integration/targets/blocks/fail.yml test/integration/targets/blocks/finalized_task.yml test/integration/targets/blocks/inherit_notify.yml test/integration/targets/blocks/issue29047.yml test/integration/targets/blocks/issue29047_tasks.yml test/integration/targets/blocks/issue71306.yml test/integration/targets/blocks/main.yml test/integration/targets/blocks/nested_fail.yml test/integration/targets/blocks/nested_nested_fail.yml test/integration/targets/blocks/runme.sh test/integration/targets/blocks/unsafe_failed_task.yml test/integration/targets/blocks/roles/fail/tasks/main.yml test/integration/targets/blocks/roles/role-69848-1/meta/main.yml test/integration/targets/blocks/roles/role-69848-2/meta/main.yml test/integration/targets/blocks/roles/role-69848-3/tasks/main.yml test/integration/targets/builtin_vars_prompt/aliases test/integration/targets/builtin_vars_prompt/runme.sh test/integration/targets/builtin_vars_prompt/test-vars_prompt.py test/integration/targets/builtin_vars_prompt/unsafe.yml test/integration/targets/builtin_vars_prompt/unsupported.yml test/integration/targets/builtin_vars_prompt/vars_prompt-1.yml test/integration/targets/builtin_vars_prompt/vars_prompt-2.yml test/integration/targets/builtin_vars_prompt/vars_prompt-3.yml test/integration/targets/builtin_vars_prompt/vars_prompt-4.yml test/integration/targets/builtin_vars_prompt/vars_prompt-5.yml test/integration/targets/builtin_vars_prompt/vars_prompt-6.yml test/integration/targets/builtin_vars_prompt/vars_prompt-7.yml test/integration/targets/cache-plugins/aliases test/integration/targets/cache-plugins/inspect_cache.yml test/integration/targets/cache-plugins/inspect_inventory_cache.yml test/integration/targets/cache-plugins/runme.sh test/integration/targets/cache-plugins/test.inventoryconfig.yml test/integration/targets/cache-plugins/test_fact_gathering.yml test/integration/targets/cache-plugins/test_inventory_cache.yml test/integration/targets/cache-plugins/cache_plugins/dummy_cache.py test/integration/targets/cache-plugins/inventory_plugins/test_inventoryconfig.py test/integration/targets/callback-legacy-warnings/aliases test/integration/targets/callback-legacy-warnings/runme.sh test/integration/targets/callback-legacy-warnings/test.yml test/integration/targets/callback-legacy-warnings/callback_plugins/legacy_warning_display.py test/integration/targets/callback-legacy-warnings/library/noisy.py test/integration/targets/callback_default/aliases test/integration/targets/callback_default/callback_default.out.check_markers_dry.stderr test/integration/targets/callback_default/callback_default.out.check_markers_dry.stdout test/integration/targets/callback_default/callback_default.out.check_markers_wet.stderr test/integration/targets/callback_default/callback_default.out.check_markers_wet.stdout test/integration/targets/callback_default/callback_default.out.check_nomarkers_dry.stderr test/integration/targets/callback_default/callback_default.out.check_nomarkers_dry.stdout test/integration/targets/callback_default/callback_default.out.check_nomarkers_wet.stderr test/integration/targets/callback_default/callback_default.out.check_nomarkers_wet.stdout test/integration/targets/callback_default/callback_default.out.default.stderr test/integration/targets/callback_default/callback_default.out.default.stdout test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stderr test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stdout test/integration/targets/callback_default/callback_default.out.failed_to_stderr.stderr test/integration/targets/callback_default/callback_default.out.failed_to_stderr.stdout test/integration/targets/callback_default/callback_default.out.fqcn_free.stdout test/integration/targets/callback_default/callback_default.out.free.stdout test/integration/targets/callback_default/callback_default.out.hide_ok.stderr test/integration/targets/callback_default/callback_default.out.hide_ok.stdout test/integration/targets/callback_default/callback_default.out.hide_skipped.stderr test/integration/targets/callback_default/callback_default.out.hide_skipped.stdout test/integration/targets/callback_default/callback_default.out.hide_skipped_ok.stderr test/integration/targets/callback_default/callback_default.out.hide_skipped_ok.stdout test/integration/targets/callback_default/callback_default.out.host_pinned.stdout test/integration/targets/callback_default/callback_default.out.include_role_fails.stderr test/integration/targets/callback_default/callback_default.out.include_role_fails.stdout test/integration/targets/callback_default/callback_default.out.result_format_yaml.stderr test/integration/targets/callback_default/callback_default.out.result_format_yaml.stdout test/integration/targets/callback_default/callback_default.out.result_format_yaml_lossy_verbose.stderr test/integration/targets/callback_default/callback_default.out.result_format_yaml_lossy_verbose.stdout test/integration/targets/callback_default/callback_default.out.result_format_yaml_verbose.stderr test/integration/targets/callback_default/callback_default.out.result_format_yaml_verbose.stdout test/integration/targets/callback_default/callback_default.out.yaml_result_format_yaml_verbose.stderr test/integration/targets/callback_default/callback_default.out.yaml_result_format_yaml_verbose.stdout test/integration/targets/callback_default/include_me.yml test/integration/targets/callback_default/inventory test/integration/targets/callback_default/no_implicit_meta_banners.yml test/integration/targets/callback_default/runme.sh test/integration/targets/callback_default/test.yml test/integration/targets/callback_default/test_2.yml test/integration/targets/callback_default/test_async.yml test/integration/targets/callback_default/test_dryrun.yml test/integration/targets/callback_default/test_include_role_fails.yml test/integration/targets/callback_default/test_non_lockstep.yml test/integration/targets/callback_default/test_yaml.yml test/integration/targets/callback_results/aliases test/integration/targets/callback_results/runme.sh test/integration/targets/callback_results/task_name.yml test/integration/targets/callback_results/callback_plugins/track_connections.py test/integration/targets/changed_when/aliases test/integration/targets/changed_when/meta/main.yml test/integration/targets/changed_when/tasks/main.yml test/integration/targets/check_mode/aliases test/integration/targets/check_mode/check_mode-not-on-cli.yml test/integration/targets/check_mode/check_mode-on-cli.yml test/integration/targets/check_mode/check_mode.yml test/integration/targets/check_mode/runme.sh test/integration/targets/check_mode/roles/test_always_run/meta/main.yml test/integration/targets/check_mode/roles/test_always_run/tasks/main.yml test/integration/targets/check_mode/roles/test_check_mode/files/foo.txt test/integration/targets/check_mode/roles/test_check_mode/tasks/main.yml test/integration/targets/check_mode/roles/test_check_mode/templates/foo.j2 test/integration/targets/check_mode/roles/test_check_mode/vars/main.yml test/integration/targets/cli/aliases test/integration/targets/cli/runme.sh test/integration/targets/cli/setup.yml test/integration/targets/cli/test-cli.py test/integration/targets/cli/test_k_and_K.py test/integration/targets/cli/test_syntax/syntax_check.yml test/integration/targets/cli/test_syntax/files/vaultsecret test/integration/targets/cli/test_syntax/group_vars/all/testvault.yml test/integration/targets/cli/test_syntax/roles/some_role/tasks/main.yml test/integration/targets/collection/aliases test/integration/targets/collection/setup.sh test/integration/targets/collection/update-ignore.py test/integration/targets/collections/a.statichost.yml test/integration/targets/collections/aliases test/integration/targets/collections/cache.statichost.yml test/integration/targets/collections/check_populated_inventory.yml test/integration/targets/collections/import_collection_pb.yml test/integration/targets/collections/includeme.yml test/integration/targets/collections/inventory_test.yml test/integration/targets/collections/invocation_tests.yml test/integration/targets/collections/noop.yml test/integration/targets/collections/posix.yml test/integration/targets/collections/redirected.statichost.yml test/integration/targets/collections/runme.sh test/integration/targets/collections/test_bypass_host_loop.yml test/integration/targets/collections/test_collection_meta.yml test/integration/targets/collections/test_redirect_list.yml test/integration/targets/collections/test_task_resolved_plugin.sh test/integration/targets/collections/vars_plugin_tests.sh test/integration/targets/collections/windows.yml test/integration/targets/collections/ansiballz_dupe/test_ansiballz_cache_dupe_shortname.yml test/integration/targets/collections/ansiballz_dupe/collections/ansible_collections/duplicate/name/plugins/modules/ping.py test/integration/targets/collections/collection_root_sys/ansible_collections/testns/coll_in_sys/plugins/modules/systestmodule.py test/integration/targets/collections/collection_root_sys/ansible_collections/testns/testcoll/plugins/modules/maskedmodule.py test/integration/targets/collections/collection_root_sys/ansible_collections/testns/testcoll/plugins/modules/testmodule.py test/integration/targets/collections/collection_root_sys/ansible_collections/testns/testcoll/roles/maskedrole/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/ansible/builtin/plugins/modules/ping.py test/integration/targets/collections/collection_root_user/ansible_collections/ansible/bullcoll/plugins/modules/bullmodule.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/othercoll/plugins/module_utils/formerly_testcoll_pkg/__init__.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/othercoll/plugins/module_utils/formerly_testcoll_pkg/submod.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testbroken/plugins/filter/broken_filter.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/meta/runtime.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/default_collection_playbook.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/play.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/library/embedded_module.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/roles/non_coll_role_to_call/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/play.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/playbooks/type/subtype/play.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/bypass_host_loop.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/plugin_lookup.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/subclassed_normal.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/uses_redirected_import.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/action/action_subdir/subdir_ping_action.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/callback/usercallback.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/connection/localconn.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/doc_fragments/frag.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/myfilters2.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/filter/filter_subdir/my_subdir_filters.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/mylookup2.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/lookup/lookup_subdir/my_subdir_lookup.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/AnotherCSMU.cs test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMU.cs test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyCSMUOptional.cs test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMU.psm1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/MyPSMUOptional.psm1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/base.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/leaf.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/secondary.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/__init__.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/__init__.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/nested_same/nested_same/nested_same.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/__init__.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subcs.cs test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/submod.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg/subps.psm1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/__init__.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/module_utils/subpkg_with_init/mod_in_subpkg_with_init.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/deprecated_ping.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/ping.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/testmodule_bad_docfrags.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_base_mu_granular_nested_import.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_collection_redirected_mu.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_core_redirected_mu.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.bak test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_flat_import.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_granular_import.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_leaf_mu_module_import_from.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_collection.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_mu_missing_redirect_module.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_func.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/uses_nested_same_as_module.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_csbasic_only.ps1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.ps1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_selfcontained.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_csmu.ps1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_coll_psmu.ps1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/win_uses_optional.ps1 test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/modules/module_subdir/subdir_ping_module.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/mytests2.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/test/test_subdir/my_subdir_tests.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/plugins/vars/custom_vars.py test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/call_standalone/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/meta/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/calls_intra_collection_dep_role_unqualified/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/common_handlers/handlers/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/role_subdir/subdir_testrole/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/meta/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/test_fqcn_handlers/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/meta/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/meta/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testcoll/roles/testrole_main_yaml/tasks/main.yml test/integration/targets/collections/collection_root_user/ansible_collections/testns/testredirect/meta/runtime.yml test/integration/targets/collections/collections/ansible_collections/me/mycoll1/plugins/action/action1.py test/integration/targets/collections/collections/ansible_collections/me/mycoll1/plugins/modules/action1.py test/integration/targets/collections/collections/ansible_collections/me/mycoll2/plugins/modules/module1.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/cache/custom_jsonfile.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/inventory/statichost.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/module_utils/__init__.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/module_utils/sub1/__init__.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/module_utils/sub1/foomodule.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/modules/contentadjmodule.py test/integration/targets/collections/collections/ansible_collections/testns/content_adj/plugins/vars/custom_adj_vars.py test/integration/targets/collections/custom_vars_plugins/v1_vars_plugin.py test/integration/targets/collections/custom_vars_plugins/v2_vars_plugin.py test/integration/targets/collections/filter_plugins/override_formerly_core_masked_filter.py test/integration/targets/collections/library/ping.py test/integration/targets/collections/roles/standalone/tasks/main.yml test/integration/targets/collections/roles/testrole/tasks/main.yml test/integration/targets/collections/test_plugins/override_formerly_core_masked_test.py test/integration/targets/collections/test_task_resolved_plugin/fqcn.yml test/integration/targets/collections/test_task_resolved_plugin/unqualified.yml test/integration/targets/collections/test_task_resolved_plugin/unqualified_and_collections_kw.yml test/integration/targets/collections/test_task_resolved_plugin/action_plugins/legacy_action.py test/integration/targets/collections/test_task_resolved_plugin/callback_plugins/display_resolved_action.py test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/meta/runtime.yml test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/action/collection_action.py test/integration/targets/collections/test_task_resolved_plugin/collections/ansible_collections/test_ns/test_coll/plugins/modules/collection_module.py test/integration/targets/collections/test_task_resolved_plugin/library/legacy_module.py test/integration/targets/collections/testcoll2/plugins/modules/testmodule2.py test/integration/targets/collections_plugin_namespace/aliases test/integration/targets/collections_plugin_namespace/runme.sh test/integration/targets/collections_plugin_namespace/test.yml test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/plugins/filter/test_filter.py test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/plugins/lookup/lookup_name.py test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/plugins/lookup/lookup_no_future_boilerplate.py test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/plugins/test/test_test.py test/integration/targets/collections_plugin_namespace/collection_root/ansible_collections/my_ns/my_col/roles/test/tasks/main.yml test/integration/targets/collections_relative_imports/aliases test/integration/targets/collections_relative_imports/runme.sh test/integration/targets/collections_relative_imports/test.yml test/integration/targets/collections_relative_imports/windows.yml test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/PSRel1.psm1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/PSRel4.psm1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/my_util1.py test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/my_util2.py test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/my_util3.py test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/module_utils/sub_pkg/PSRel2.psm1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/my_module.py test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/win_relative.ps1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/plugins/modules/win_relative_optional.ps1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col/roles/test/tasks/main.yml test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col2/plugins/module_utils/PSRel3.psm1 test/integration/targets/collections_relative_imports/collection_root/ansible_collections/my_ns/my_col2/plugins/module_utils/sub_pkg/CSRel4.cs test/integration/targets/collections_runtime_pythonpath/aliases test/integration/targets/collections_runtime_pythonpath/runme.sh test/integration/targets/collections_runtime_pythonpath/ansible-collection-python-dist-boo/pyproject.toml test/integration/targets/collections_runtime_pythonpath/ansible-collection-python-dist-boo/setup.cfg test/integration/targets/collections_runtime_pythonpath/ansible-collection-python-dist-boo/ansible_collections/python/dist/plugins/modules/boo.py test/integration/targets/collections_runtime_pythonpath/ansible-collection-python-dist-foo/ansible_collections/python/dist/plugins/modules/boo.py test/integration/targets/command_shell/aliases test/integration/targets/command_shell/files/create_afile.sh test/integration/targets/command_shell/files/remove_afile.sh test/integration/targets/command_shell/files/test.sh test/integration/targets/command_shell/meta/main.yml test/integration/targets/command_shell/scripts/yoink.sh test/integration/targets/command_shell/tasks/main.yml test/integration/targets/common_network/aliases test/integration/targets/common_network/tasks/main.yml test/integration/targets/common_network/test_plugins/is_mac.py test/integration/targets/conditionals/aliases test/integration/targets/conditionals/broken_conditionals.yml test/integration/targets/conditionals/output_validation_tests.yml test/integration/targets/conditionals/play.yml test/integration/targets/conditionals/runme.sh test/integration/targets/conditionals/vars/main.yml test/integration/targets/config/aliases test/integration/targets/config/inline_comment_ansible.cfg test/integration/targets/config/runme.sh test/integration/targets/config/type_munging.cfg test/integration/targets/config/types.yml test/integration/targets/config/validation.yml test/integration/targets/config/files/types.env test/integration/targets/config/files/types.ini test/integration/targets/config/files/types.vars test/integration/targets/config/files/types_dump.txt test/integration/targets/config/lookup_plugins/bogus.py test/integration/targets/config/lookup_plugins/casting.py test/integration/targets/config/lookup_plugins/casting_individual.py test/integration/targets/config/lookup_plugins/types.py test/integration/targets/connection/aliases test/integration/targets/connection/test.sh test/integration/targets/connection/test_connection.yml test/integration/targets/connection/test_reset_connection.yml test/integration/targets/connection/test_reset_connection_templated.yml test/integration/targets/connection_delegation/aliases test/integration/targets/connection_delegation/inventory.ini test/integration/targets/connection_delegation/runme.sh test/integration/targets/connection_delegation/test.yml test/integration/targets/connection_delegation/action_plugins/delegation_action.py test/integration/targets/connection_delegation/connection_plugins/delegation_connection.py test/integration/targets/connection_local/aliases test/integration/targets/connection_local/runme.sh test/integration/targets/connection_local/test_become_password_handling.yml test/integration/targets/connection_local/test_connection.inventory test/integration/targets/connection_local/test_network_connection.inventory test/integration/targets/connection_local/connection_plugins/network_noop.py test/integration/targets/connection_local/files/sudoshim.sh test/integration/targets/connection_paramiko_ssh/aliases test/integration/targets/connection_paramiko_ssh/runme.sh test/integration/targets/connection_paramiko_ssh/test.sh test/integration/targets/connection_paramiko_ssh/test_connection.inventory test/integration/targets/connection_psrp/aliases test/integration/targets/connection_psrp/runme.sh test/integration/targets/connection_psrp/test_connection.inventory.j2 test/integration/targets/connection_psrp/tests.yml test/integration/targets/connection_psrp/files/empty.txt test/integration/targets/connection_remote_is_local/aliases test/integration/targets/connection_remote_is_local/test.yml test/integration/targets/connection_remote_is_local/connection_plugins/remote_is_local.py test/integration/targets/connection_remote_is_local/tasks/main.yml test/integration/targets/connection_ssh/aliases test/integration/targets/connection_ssh/check_ssh_defaults.yml test/integration/targets/connection_ssh/posix.sh test/integration/targets/connection_ssh/runme.sh test/integration/targets/connection_ssh/test_connection.inventory test/integration/targets/connection_ssh/test_ssh_askpass.yml test/integration/targets/connection_ssh/test_ssh_defaults.cfg test/integration/targets/connection_ssh/test_unreachable_become_timeout.yml test/integration/targets/connection_ssh/verify_config.yml test/integration/targets/connection_ssh/files/port_override_ssh.cfg test/integration/targets/connection_windows_ssh/aliases test/integration/targets/connection_windows_ssh/runme.sh test/integration/targets/connection_windows_ssh/test_connection.inventory.j2 test/integration/targets/connection_windows_ssh/tests.yml test/integration/targets/connection_windows_ssh/tests_fetch.yml test/integration/targets/connection_windows_ssh/windows.sh test/integration/targets/connection_winrm/aliases test/integration/targets/connection_winrm/runme.sh test/integration/targets/connection_winrm/test_connection.inventory.j2 test/integration/targets/connection_winrm/tests.yml test/integration/targets/controller/aliases test/integration/targets/controller/tasks/main.yml test/integration/targets/copy/aliases test/integration/targets/copy/defaults/main.yml test/integration/targets/copy/files/foo.txt test/integration/targets/copy/files-different/vault/readme.txt test/integration/targets/copy/files-different/vault/vault-file test/integration/targets/copy/files-different/vault/folder/nested-vault-file test/integration/targets/copy/files/subdir/bar.txt test/integration/targets/copy/files/subdir/subdir1/empty.txt test/integration/targets/copy/files/subdir/subdir2/baz.txt test/integration/targets/copy/files/subdir/subdir2/subdir3/subdir4/qux.txt test/integration/targets/copy/meta/main.yml test/integration/targets/copy/tasks/acls.yml test/integration/targets/copy/tasks/check_mode.yml test/integration/targets/copy/tasks/dest_in_non_existent_directories.yml test/integration/targets/copy/tasks/dest_in_non_existent_directories_remote_src.yml test/integration/targets/copy/tasks/main.yml test/integration/targets/copy/tasks/no_log.yml test/integration/targets/copy/tasks/selinux.yml test/integration/targets/copy/tasks/setgid.yml test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir.yml test/integration/targets/copy/tasks/src_file_dest_file_in_non_existent_dir_remote_src.yml test/integration/targets/copy/tasks/src_remote_file_is_not_file.yml test/integration/targets/copy/tasks/tests.yml test/integration/targets/cron/aliases test/integration/targets/cron/meta/main.yml test/integration/targets/cron/tasks/main.yml test/integration/targets/cron/vars/alpine.yml test/integration/targets/cron/vars/default.yml test/integration/targets/data_tagging_controller/aliases test/integration/targets/data_tagging_controller/expected_stderr.txt test/integration/targets/data_tagging_controller/expected_stdout.txt test/integration/targets/data_tagging_controller/hosts test/integration/targets/data_tagging_controller/output_tests.yml test/integration/targets/data_tagging_controller/runme.sh test/integration/targets/data_tagging_controller/untrusted_propagation.yml test/integration/targets/data_tagging_controller/library/deepresp.py test/integration/targets/data_tagging_controller/library/tagging_sample.py test/integration/targets/dataloader/aliases test/integration/targets/dataloader/attempt_to_load_invalid_json.yml test/integration/targets/dataloader/runme.sh test/integration/targets/dataloader/vars/invalid.json test/integration/targets/deb822_repository/aliases test/integration/targets/deb822_repository/meta/main.yml test/integration/targets/deb822_repository/tasks/install.yml test/integration/targets/deb822_repository/tasks/main.yml test/integration/targets/deb822_repository/tasks/test.yml test/integration/targets/debconf/aliases test/integration/targets/debconf/meta/main.yml test/integration/targets/debconf/tasks/main.yml test/integration/targets/debug/aliases test/integration/targets/debug/args_templating.yml test/integration/targets/debug/errors.yml test/integration/targets/debug/main.yml test/integration/targets/debug/main_fqcn.yml test/integration/targets/debug/nosetfacts.yml test/integration/targets/debug/runme.sh test/integration/targets/debugger/aliases test/integration/targets/debugger/inventory test/integration/targets/debugger/runme.sh test/integration/targets/debugger/test_run_once.py test/integration/targets/debugger/test_run_once_playbook.yml test/integration/targets/delegate_to/aliases test/integration/targets/delegate_to/delegate_and_nolog.yml test/integration/targets/delegate_to/delegate_facts_block.yml test/integration/targets/delegate_to/delegate_facts_loop.yml test/integration/targets/delegate_to/delegate_local_from_root.yml test/integration/targets/delegate_to/delegate_to_lookup_context.yml test/integration/targets/delegate_to/delegate_vars_handling.yml test/integration/targets/delegate_to/delegate_with_fact_from_delegate_host.yml test/integration/targets/delegate_to/discovery_applied.yml test/integration/targets/delegate_to/has_hostvars.yml test/integration/targets/delegate_to/inventory test/integration/targets/delegate_to/inventory_interpreters test/integration/targets/delegate_to/resolve_vars.yml test/integration/targets/delegate_to/runme.sh test/integration/targets/delegate_to/test_delegate_to.yml test/integration/targets/delegate_to/test_delegate_to_lookup_context.yml test/integration/targets/delegate_to/test_delegate_to_loop_caching.yml test/integration/targets/delegate_to/test_delegate_to_loop_randomness.yml test/integration/targets/delegate_to/test_loop_control.yml test/integration/targets/delegate_to/test_random_delegate_to_with_loop.yml test/integration/targets/delegate_to/test_random_delegate_to_without_loop.yml test/integration/targets/delegate_to/verify_interpreter.yml test/integration/targets/delegate_to/connection_plugins/fakelocal.py test/integration/targets/delegate_to/files/testfile test/integration/targets/delegate_to/library/detect_interpreter.py test/integration/targets/delegate_to/roles/delegate_to_lookup_context/tasks/main.yml test/integration/targets/delegate_to/roles/delegate_to_lookup_context/templates/one.j2 test/integration/targets/delegate_to/roles/delegate_to_lookup_context/templates/two.j2 test/integration/targets/delegate_to/roles/test_template/templates/foo.j2 test/integration/targets/deprecations/aliases test/integration/targets/deprecations/deprecated.yml test/integration/targets/deprecations/entry_key_deprecated.cfg test/integration/targets/deprecations/entry_key_deprecated2.cfg test/integration/targets/deprecations/entry_key_not_deprecated.cfg test/integration/targets/deprecations/runme.sh test/integration/targets/deprecations/cache_plugins/notjsonfile.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/__init__.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/action/__init__.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/action/noisy_action.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/module_utils/shared_deprecation.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/modules/__init__.py test/integration/targets/deprecations/collections/ansible_collections/foo/bar/plugins/modules/noisy.py test/integration/targets/deprecations/library/removeoption.py test/integration/targets/deprecations/library/willremove.py test/integration/targets/dict_transformations/aliases test/integration/targets/dict_transformations/library/convert_camelCase.py test/integration/targets/dict_transformations/library/convert_snake_case.py test/integration/targets/dict_transformations/tasks/main.yml test/integration/targets/dict_transformations/tasks/test_convert_camelCase.yml test/integration/targets/dict_transformations/tasks/test_convert_snake_case.yml test/integration/targets/display-newline/aliases test/integration/targets/display-newline/library/noisy.py test/integration/targets/display-newline/tasks/main.yml test/integration/targets/dnf/aliases test/integration/targets/dnf/filter_plugins/dnf_module_list.py test/integration/targets/dnf/meta/main.yml test/integration/targets/dnf/tasks/cacheonly.yml test/integration/targets/dnf/tasks/dnf.yml test/integration/targets/dnf/tasks/dnf_group_remove.yml test/integration/targets/dnf/tasks/dnfinstallroot.yml test/integration/targets/dnf/tasks/dnfreleasever.yml test/integration/targets/dnf/tasks/filters.yml test/integration/targets/dnf/tasks/filters_check_mode.yml test/integration/targets/dnf/tasks/gpg.yml test/integration/targets/dnf/tasks/logging.yml test/integration/targets/dnf/tasks/main.yml test/integration/targets/dnf/tasks/modularity.yml test/integration/targets/dnf/tasks/multilib.yml test/integration/targets/dnf/tasks/repo.yml test/integration/targets/dnf/tasks/skip_broken_and_nobest.yml test/integration/targets/dnf/tasks/test_sos_removal.yml test/integration/targets/dpkg_selections/aliases test/integration/targets/dpkg_selections/defaults/main.yaml test/integration/targets/dpkg_selections/tasks/dpkg_selections.yaml test/integration/targets/dpkg_selections/tasks/main.yaml test/integration/targets/embedded_module/aliases test/integration/targets/embedded_module/library/test_integration_module test/integration/targets/embedded_module/tasks/main.yml test/integration/targets/entry_points/aliases test/integration/targets/entry_points/runme.sh test/integration/targets/environment/aliases test/integration/targets/environment/runme.sh test/integration/targets/environment/test_environment.yml test/integration/targets/error_from_connection/aliases test/integration/targets/error_from_connection/inventory test/integration/targets/error_from_connection/play.yml test/integration/targets/error_from_connection/runme.sh test/integration/targets/error_from_connection/connection_plugins/dummy.py test/integration/targets/expect/aliases test/integration/targets/expect/files/foo.txt test/integration/targets/expect/files/test_command.py test/integration/targets/expect/files/test_non_utf8_command.py test/integration/targets/expect/meta/main.yml test/integration/targets/expect/tasks/main.yml test/integration/targets/facts_d/aliases test/integration/targets/facts_d/files/bad.fact test/integration/targets/facts_d/files/basdscript.fact test/integration/targets/facts_d/files/goodscript.fact test/integration/targets/facts_d/files/preferences.fact test/integration/targets/facts_d/files/unreadable.fact test/integration/targets/facts_d/meta/main.yml test/integration/targets/facts_d/tasks/main.yml test/integration/targets/facts_linux_network/aliases test/integration/targets/facts_linux_network/meta/main.yml test/integration/targets/facts_linux_network/tasks/main.yml test/integration/targets/failed_when/aliases test/integration/targets/failed_when/tasks/main.yml test/integration/targets/fetch/aliases test/integration/targets/fetch/cleanup.yml test/integration/targets/fetch/run_fetch_tests.yml test/integration/targets/fetch/runme.sh test/integration/targets/fetch/setup_unreadable_test.yml test/integration/targets/fetch/test_unreadable_with_stat.yml test/integration/targets/fetch/injection/avoid_slurp_return.yml test/integration/targets/fetch/injection/here.txt test/integration/targets/fetch/injection/library/slurp.py test/integration/targets/fetch/roles/fetch_tests/defaults/main.yml test/integration/targets/fetch/roles/fetch_tests/handlers/main.yml test/integration/targets/fetch/roles/fetch_tests/meta/main.yml test/integration/targets/fetch/roles/fetch_tests/tasks/fail_on_missing.yml test/integration/targets/fetch/roles/fetch_tests/tasks/failures.yml test/integration/targets/fetch/roles/fetch_tests/tasks/main.yml test/integration/targets/fetch/roles/fetch_tests/tasks/normal.yml test/integration/targets/fetch/roles/fetch_tests/tasks/setup.yml test/integration/targets/fetch/roles/fetch_tests/tasks/symlink.yml test/integration/targets/fetch/roles/fetch_tests/vars/Darwin.yml test/integration/targets/fetch/roles/fetch_tests/vars/default.yml test/integration/targets/file/aliases test/integration/targets/file/defaults/main.yml test/integration/targets/file/files/foo.txt test/integration/targets/file/files/foobar/fileA test/integration/targets/file/files/foobar/fileB test/integration/targets/file/files/foobar/directory/fileC test/integration/targets/file/files/foobar/directory/fileD test/integration/targets/file/handlers/main.yml test/integration/targets/file/meta/main.yml test/integration/targets/file/tasks/diff.yml test/integration/targets/file/tasks/diff_peek.yml test/integration/targets/file/tasks/directory_as_dest.yml test/integration/targets/file/tasks/initialize.yml test/integration/targets/file/tasks/link_follow.yml test/integration/targets/file/tasks/link_rewrite.yml test/integration/targets/file/tasks/main.yml test/integration/targets/file/tasks/modification_time.yml test/integration/targets/file/tasks/selinux_tests.yml test/integration/targets/file/tasks/state_link.yml test/integration/targets/file/tasks/unicode_path.yml test/integration/targets/filter_core/aliases test/integration/targets/filter_core/handle_undefined_type_errors.yml test/integration/targets/filter_core/runme.sh test/integration/targets/filter_core/runme.yml test/integration/targets/filter_core/files/9851.txt test/integration/targets/filter_core/files/foo.txt test/integration/targets/filter_core/files/fileglob/one.txt test/integration/targets/filter_core/files/fileglob/two.txt test/integration/targets/filter_core/host_vars/localhost test/integration/targets/filter_core/tasks/main.yml test/integration/targets/filter_core/templates/foo.j2 test/integration/targets/filter_core/vars/main.yml test/integration/targets/filter_encryption/aliases test/integration/targets/filter_encryption/tasks/main.yml test/integration/targets/filter_encryption/vars/main.yml test/integration/targets/filter_mathstuff/aliases test/integration/targets/filter_mathstuff/runme.sh test/integration/targets/filter_mathstuff/runme.yml test/integration/targets/filter_mathstuff/host_vars/localhost.yml test/integration/targets/filter_mathstuff/tasks/main.yml test/integration/targets/filter_mathstuff/vars/defined_later.yml test/integration/targets/filter_mathstuff/vars/main.yml test/integration/targets/filter_urls/aliases test/integration/targets/filter_urls/tasks/main.yml test/integration/targets/filter_urlsplit/aliases test/integration/targets/filter_urlsplit/tasks/main.yml test/integration/targets/find/aliases test/integration/targets/find/files/a.txt test/integration/targets/find/files/hello_world.gbk test/integration/targets/find/files/log.txt test/integration/targets/find/meta/main.yml test/integration/targets/find/tasks/main.yml test/integration/targets/find/tasks/mode.yml test/integration/targets/fork_safe_stdio/aliases test/integration/targets/fork_safe_stdio/hosts test/integration/targets/fork_safe_stdio/run-with-pty.py test/integration/targets/fork_safe_stdio/runme.sh test/integration/targets/fork_safe_stdio/test.yml test/integration/targets/fork_safe_stdio/vendored_pty.py test/integration/targets/fork_safe_stdio/callback_plugins/spewstdio.py test/integration/targets/gather_facts-errors/aliases test/integration/targets/gather_facts-errors/test_gather_facts.yml test/integration/targets/gather_facts-errors/library/fail1.py test/integration/targets/gather_facts-errors/library/fail2.py test/integration/targets/gather_facts-errors/library/success1.py test/integration/targets/gather_facts-errors/tasks/main.yml test/integration/targets/gathering/aliases test/integration/targets/gathering/explicit.yml test/integration/targets/gathering/implicit.yml test/integration/targets/gathering/runme.sh test/integration/targets/gathering/smart.yml test/integration/targets/gathering/uuid.fact test/integration/targets/gathering_facts/aliases test/integration/targets/gathering_facts/inventory test/integration/targets/gathering_facts/one_two.json test/integration/targets/gathering_facts/prevent_clobbering.yml test/integration/targets/gathering_facts/runme.sh test/integration/targets/gathering_facts/smart_added.yml test/integration/targets/gathering_facts/test_gathering_facts.yml test/integration/targets/gathering_facts/test_module_defaults.yml test/integration/targets/gathering_facts/test_prevent_injection.yml test/integration/targets/gathering_facts/test_run_once.yml test/integration/targets/gathering_facts/two_one.json test/integration/targets/gathering_facts/uuid.fact test/integration/targets/gathering_facts/verify_merge_facts.yml test/integration/targets/gathering_facts/verify_subset.yml test/integration/targets/gathering_facts/cache_plugins/none.py test/integration/targets/gathering_facts/collections/ansible_collections/cisco/ios/plugins/modules/ios_facts.py test/integration/targets/gathering_facts/library/bogus_facts test/integration/targets/gathering_facts/library/dummy1 test/integration/targets/gathering_facts/library/dummy2 test/integration/targets/gathering_facts/library/dummy3 test/integration/targets/gathering_facts/library/facts_one test/integration/targets/gathering_facts/library/facts_two test/integration/targets/gathering_facts/library/file_utils.py test/integration/targets/gathering_facts/library/slow test/integration/targets/get_url/aliases test/integration/targets/get_url/files/testserver.py test/integration/targets/get_url/meta/main.yml test/integration/targets/get_url/tasks/ciphers.yml test/integration/targets/get_url/tasks/hashlib.yml test/integration/targets/get_url/tasks/main.yml test/integration/targets/get_url/tasks/use_gssapi.yml test/integration/targets/get_url/tasks/use_netrc.yml test/integration/targets/getent/aliases test/integration/targets/getent/meta/main.yml test/integration/targets/getent/tasks/main.yml test/integration/targets/git/aliases test/integration/targets/git/handlers/cleanup-default.yml test/integration/targets/git/handlers/cleanup-freebsd.yml test/integration/targets/git/handlers/main.yml test/integration/targets/git/meta/main.yml test/integration/targets/git/tasks/ambiguous-ref.yml test/integration/targets/git/tasks/archive.yml test/integration/targets/git/tasks/change-repo-url.yml test/integration/targets/git/tasks/checkout-new-tag.yml test/integration/targets/git/tasks/depth.yml test/integration/targets/git/tasks/forcefully-fetch-tag.yml test/integration/targets/git/tasks/formats.yml test/integration/targets/git/tasks/gpg-verification.yml test/integration/targets/git/tasks/localmods.yml test/integration/targets/git/tasks/main.yml test/integration/targets/git/tasks/missing_hostkey.yml test/integration/targets/git/tasks/missing_hostkey_acceptnew.yml test/integration/targets/git/tasks/no-destination.yml test/integration/targets/git/tasks/reset-origin.yml test/integration/targets/git/tasks/separate-git-dir.yml test/integration/targets/git/tasks/setup-local-repos.yml test/integration/targets/git/tasks/setup.yml test/integration/targets/git/tasks/single-branch.yml test/integration/targets/git/tasks/specific-revision.yml test/integration/targets/git/tasks/submodules.yml test/integration/targets/git/vars/main.yml test/integration/targets/group/aliases test/integration/targets/group/files/get_free_gid.py test/integration/targets/group/files/get_gid_for_group.py test/integration/targets/group/files/grouplist.sh test/integration/targets/group/meta/main.yml test/integration/targets/group/tasks/main.yml test/integration/targets/group/tasks/test_create_group_min_max.yml test/integration/targets/group/tasks/tests.yml test/integration/targets/group_by/aliases test/integration/targets/group_by/create_groups.yml test/integration/targets/group_by/inventory.group_by test/integration/targets/group_by/runme.sh test/integration/targets/group_by/test_group_by.yml test/integration/targets/group_by/test_group_by_skipped.yml test/integration/targets/group_by/group_vars/all test/integration/targets/group_by/group_vars/camelus test/integration/targets/group_by/group_vars/vicugna test/integration/targets/handler_race/aliases test/integration/targets/handler_race/inventory test/integration/targets/handler_race/runme.sh test/integration/targets/handler_race/test_handler_race.yml test/integration/targets/handler_race/roles/do_handlers/handlers/main.yml test/integration/targets/handler_race/roles/do_handlers/tasks/main.yml test/integration/targets/handler_race/roles/more_sleep/tasks/main.yml test/integration/targets/handler_race/roles/random_sleep/tasks/main.yml test/integration/targets/handlers/46447.yml test/integration/targets/handlers/52561.yml test/integration/targets/handlers/54991.yml test/integration/targets/handlers/58841.yml test/integration/targets/handlers/79776-handlers.yml test/integration/targets/handlers/79776.yml test/integration/targets/handlers/80880.yml test/integration/targets/handlers/82241.yml test/integration/targets/handlers/aliases test/integration/targets/handlers/force_handlers_blocks_81533-1.yml test/integration/targets/handlers/force_handlers_blocks_81533-2.yml test/integration/targets/handlers/from_handlers.yml test/integration/targets/handlers/handler_notify_earlier_handler.yml test/integration/targets/handlers/handlers.yml test/integration/targets/handlers/handlers_lockstep_82307.yml test/integration/targets/handlers/handlers_lockstep_83019-include-nested.yml test/integration/targets/handlers/handlers_lockstep_83019-include.yml test/integration/targets/handlers/handlers_lockstep_83019.yml test/integration/targets/handlers/include_handlers_fail_force-handlers.yml test/integration/targets/handlers/include_handlers_fail_force.yml test/integration/targets/handlers/inventory.handlers test/integration/targets/handlers/nested_flush_handlers_failure_force.yml test/integration/targets/handlers/order.yml test/integration/targets/handlers/runme.sh test/integration/targets/handlers/tagged_play.yml test/integration/targets/handlers/test_block_as_handler-import.yml test/integration/targets/handlers/test_block_as_handler-include.yml test/integration/targets/handlers/test_block_as_handler-include_import-handlers.yml test/integration/targets/handlers/test_block_as_handler.yml test/integration/targets/handlers/test_flush_handlers_as_handler.yml test/integration/targets/handlers/test_flush_handlers_rescue_always.yml test/integration/targets/handlers/test_flush_in_rescue_always.yml test/integration/targets/handlers/test_force_handlers.yml test/integration/targets/handlers/test_fqcn_meta_flush_handlers.yml test/integration/targets/handlers/test_handlers.yml test/integration/targets/handlers/test_handlers_any_errors_fatal.yml test/integration/targets/handlers/test_handlers_include.yml test/integration/targets/handlers/test_handlers_include_role.yml test/integration/targets/handlers/test_handlers_including_task.yml test/integration/targets/handlers/test_handlers_inexistent_notify.yml test/integration/targets/handlers/test_handlers_infinite_loop.yml test/integration/targets/handlers/test_handlers_listen.yml test/integration/targets/handlers/test_handlers_meta.yml test/integration/targets/handlers/test_handlers_template_run_once.yml test/integration/targets/handlers/test_include_role_handler_once.yml test/integration/targets/handlers/test_include_tasks_in_include_role.yml test/integration/targets/handlers/test_listen_role_dedup.yml test/integration/targets/handlers/test_listening_handlers.yml test/integration/targets/handlers/test_multiple_handlers_with_recursive_notification.yml test/integration/targets/handlers/test_notify_included-handlers.yml test/integration/targets/handlers/test_notify_included.yml test/integration/targets/handlers/test_role_as_handler.yml test/integration/targets/handlers/test_role_handlers_including_tasks.yml test/integration/targets/handlers/test_run_once.yml test/integration/targets/handlers/test_skip_flush.yml test/integration/targets/handlers/test_templating_in_handlers.yml test/integration/targets/handlers/collections/ansible_collections/ns/col/roles/test_handlers_listen/handlers/main.yml test/integration/targets/handlers/roles/import_template_handler_names/tasks/main.yml test/integration/targets/handlers/roles/include_role_include_tasks_handler/handlers/include_handlers.yml test/integration/targets/handlers/roles/include_role_include_tasks_handler/handlers/main.yml test/integration/targets/handlers/roles/include_role_include_tasks_handler/tasks/main.yml test/integration/targets/handlers/roles/r1-dep_chain-vars/defaults/main.yml test/integration/targets/handlers/roles/r1-dep_chain-vars/tasks/main.yml test/integration/targets/handlers/roles/r2-dep_chain-vars/handlers/main.yml test/integration/targets/handlers/roles/r2-dep_chain-vars/tasks/main.yml test/integration/targets/handlers/roles/role-82241/handlers/main.yml test/integration/targets/handlers/roles/role-82241/tasks/entry_point.yml test/integration/targets/handlers/roles/role-82241/tasks/included_tasks.yml test/integration/targets/handlers/roles/template_handler_names/handlers/main.yml test/integration/targets/handlers/roles/template_handler_names/tasks/evaluation_time.yml test/integration/targets/handlers/roles/template_handler_names/tasks/lazy_evaluation.yml test/integration/targets/handlers/roles/test_force_handlers/handlers/main.yml test/integration/targets/handlers/roles/test_force_handlers/tasks/main.yml test/integration/targets/handlers/roles/test_handlers/handlers/main.yml test/integration/targets/handlers/roles/test_handlers/meta/main.yml test/integration/targets/handlers/roles/test_handlers/tasks/main.yml test/integration/targets/handlers/roles/test_handlers_include/handlers/main.yml test/integration/targets/handlers/roles/test_handlers_include/tasks/main.yml test/integration/targets/handlers/roles/test_handlers_include_role/handlers/main.yml test/integration/targets/handlers/roles/test_handlers_include_role/meta/main.yml test/integration/targets/handlers/roles/test_handlers_include_role/tasks/main.yml test/integration/targets/handlers/roles/test_handlers_listen/handlers/main.yml test/integration/targets/handlers/roles/test_handlers_listen/tasks/main.yml test/integration/targets/handlers/roles/test_handlers_meta/handlers/alternate.yml test/integration/targets/handlers/roles/test_handlers_meta/handlers/main.yml test/integration/targets/handlers/roles/test_handlers_meta/tasks/main.yml test/integration/targets/handlers/roles/test_listen_role_dedup_global/handlers/main.yml test/integration/targets/handlers/roles/test_listen_role_dedup_role1/meta/main.yml test/integration/targets/handlers/roles/test_listen_role_dedup_role1/tasks/main.yml test/integration/targets/handlers/roles/test_listen_role_dedup_role2/meta/main.yml test/integration/targets/handlers/roles/test_listen_role_dedup_role2/tasks/main.yml test/integration/targets/handlers/roles/test_role_handlers_include_tasks/handlers/A.yml test/integration/targets/handlers/roles/test_role_handlers_include_tasks/handlers/main.yml test/integration/targets/handlers/roles/test_role_handlers_include_tasks/tasks/B.yml test/integration/targets/handlers/roles/test_templating_in_handlers/handlers/main.yml test/integration/targets/handlers/roles/test_templating_in_handlers/tasks/main.yml test/integration/targets/handlers/roles/two_tasks_files_role/handlers/main.yml test/integration/targets/handlers/roles/two_tasks_files_role/tasks/main.yml test/integration/targets/handlers/roles/two_tasks_files_role/tasks/other.yml test/integration/targets/hardware_facts/aliases test/integration/targets/hardware_facts/meta/main.yml test/integration/targets/hardware_facts/tasks/Linux.yml test/integration/targets/hardware_facts/tasks/main.yml test/integration/targets/hash/aliases test/integration/targets/hash/runme.sh test/integration/targets/hash/test_hash.yml test/integration/targets/hash/test_inv1.yml test/integration/targets/hash/test_inv2.yml test/integration/targets/hash/test_inventory_hash.yml test/integration/targets/hash/group_vars/all test/integration/targets/hash/host_vars/testhost test/integration/targets/hash/roles/test_hash_behaviour/defaults/main.yml test/integration/targets/hash/roles/test_hash_behaviour/meta/main.yml test/integration/targets/hash/roles/test_hash_behaviour/tasks/main.yml test/integration/targets/hash/roles/test_hash_behaviour/vars/main.yml test/integration/targets/hash/vars/test_hash_vars.yml test/integration/targets/hostname/aliases test/integration/targets/hostname/tasks/Debian.yml test/integration/targets/hostname/tasks/MacOSX.yml test/integration/targets/hostname/tasks/RedHat.yml test/integration/targets/hostname/tasks/check_mode.yml test/integration/targets/hostname/tasks/default.yml test/integration/targets/hostname/tasks/main.yml test/integration/targets/hostname/tasks/test_check_mode.yml test/integration/targets/hostname/tasks/test_normal.yml test/integration/targets/hostname/vars/FreeBSD.yml test/integration/targets/hostname/vars/RedHat.yml test/integration/targets/hostname/vars/default.yml test/integration/targets/hosts_field/aliases test/integration/targets/hosts_field/inventory.hosts_field test/integration/targets/hosts_field/runme.sh test/integration/targets/hosts_field/test_hosts_field.json test/integration/targets/hosts_field/test_hosts_field.yml test/integration/targets/ignore_errors/aliases test/integration/targets/ignore_errors/runme.sh test/integration/targets/ignore_errors/test_ignore_errors.yml test/integration/targets/ignore_errors/test_ignore_errors_false.yml test/integration/targets/ignore_errors/tasks/main.yml test/integration/targets/ignore_unreachable/aliases test/integration/targets/ignore_unreachable/inventory test/integration/targets/ignore_unreachable/runme.sh test/integration/targets/ignore_unreachable/test_base_cannot_connect.yml test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml test/integration/targets/ignore_unreachable/test_cannot_connect.yml test/integration/targets/ignore_unreachable/test_with_bad_plugins.yml test/integration/targets/ignore_unreachable/fake_connectors/bad_exec.py test/integration/targets/ignore_unreachable/fake_connectors/bad_put_file.py test/integration/targets/ignore_unreachable/meta/main.yml test/integration/targets/import-role-tasks/aliases test/integration/targets/import-role-tasks/import.yml test/integration/targets/import-role-tasks/runme.sh test/integration/targets/import-role-tasks/roles/test_environment/tasks/main.yml test/integration/targets/import_tasks/aliases test/integration/targets/import_tasks/inherit_notify.yml test/integration/targets/import_tasks/runme.sh test/integration/targets/import_tasks/tasks/trigger_change.yml test/integration/targets/incidental_ios_file/aliases test/integration/targets/incidental_ios_file/ios1.cfg test/integration/targets/incidental_ios_file/nonascii.bin test/integration/targets/incidental_ios_file/defaults/main.yaml test/integration/targets/incidental_ios_file/tasks/cli.yaml test/integration/targets/incidental_ios_file/tasks/main.yaml test/integration/targets/incidental_ios_file/tests/cli/net_get.yaml test/integration/targets/incidental_ios_file/tests/cli/net_put.yaml test/integration/targets/incidental_win_reboot/aliases test/integration/targets/incidental_win_reboot/tasks/main.yml test/integration/targets/incidental_win_reboot/templates/post_reboot.ps1 test/integration/targets/include_import/aliases test/integration/targets/include_import/inventory test/integration/targets/include_import/issue73657.yml test/integration/targets/include_import/issue73657_tasks.yml test/integration/targets/include_import/runme.sh test/integration/targets/include_import/test_copious_include_tasks.yml test/integration/targets/include_import/test_copious_include_tasks_fqcn.yml test/integration/targets/include_import/test_grandparent_inheritance.yml test/integration/targets/include_import/test_grandparent_inheritance_fqcn.yml test/integration/targets/include_import/test_include_loop.yml test/integration/targets/include_import/test_include_loop_fqcn.yml test/integration/targets/include_import/test_loop_var_bleed.yaml test/integration/targets/include_import/test_nested_tasks.yml test/integration/targets/include_import/test_nested_tasks_fqcn.yml test/integration/targets/include_import/test_null_include_filename.yml test/integration/targets/include_import/test_role_recursion.yml test/integration/targets/include_import/test_role_recursion_fqcn.yml test/integration/targets/include_import/apply/import_apply.yml test/integration/targets/include_import/apply/include_apply.yml test/integration/targets/include_import/apply/include_apply_65710.yml test/integration/targets/include_import/apply/include_tasks.yml test/integration/targets/include_import/apply/roles/include_role/tasks/main.yml test/integration/targets/include_import/apply/roles/include_role2/tasks/main.yml test/integration/targets/include_import/empty_group_warning/playbook.yml test/integration/targets/include_import/empty_group_warning/tasks.yml test/integration/targets/include_import/grandchild/block_include_tasks.yml test/integration/targets/include_import/grandchild/import.yml test/integration/targets/include_import/grandchild/import_include_include_tasks.yml test/integration/targets/include_import/grandchild/include_level_1.yml test/integration/targets/include_import/handler_addressing/playbook.yml test/integration/targets/include_import/handler_addressing/roles/import_handler_test/handlers/main.yml test/integration/targets/include_import/handler_addressing/roles/import_handler_test/tasks/handlers.yml test/integration/targets/include_import/handler_addressing/roles/import_handler_test/tasks/main.yml test/integration/targets/include_import/handler_addressing/roles/include_handler_test/handlers/main.yml test/integration/targets/include_import/handler_addressing/roles/include_handler_test/tasks/handlers.yml test/integration/targets/include_import/handler_addressing/roles/include_handler_test/tasks/main.yml test/integration/targets/include_import/include_role_omit/playbook.yml test/integration/targets/include_import/include_role_omit/roles/foo/tasks/main.yml test/integration/targets/include_import/nestedtasks/nested/nested.yml test/integration/targets/include_import/null_filename/tasks.yml test/integration/targets/include_import/parent_templating/playbook.yml test/integration/targets/include_import/parent_templating/roles/test/tasks/localhost.yml test/integration/targets/include_import/parent_templating/roles/test/tasks/main.yml test/integration/targets/include_import/parent_templating/roles/test/tasks/other.yml test/integration/targets/include_import/playbook/playbook1.yml test/integration/targets/include_import/playbook/playbook2.yml test/integration/targets/include_import/playbook/playbook3.yml test/integration/targets/include_import/playbook/playbook4.yml test/integration/targets/include_import/playbook/playbook_needing_vars.yml test/integration/targets/include_import/playbook/test_import_playbook.yml test/integration/targets/include_import/playbook/test_import_playbook_tags.yml test/integration/targets/include_import/playbook/test_templated_filenames.yml test/integration/targets/include_import/playbook/validate1.yml test/integration/targets/include_import/playbook/validate2.yml test/integration/targets/include_import/playbook/validate34.yml test/integration/targets/include_import/playbook/validate_tags.yml test/integration/targets/include_import/playbook/validate_templated_playbook.yml test/integration/targets/include_import/playbook/validate_templated_tasks.yml test/integration/targets/include_import/playbook/group_vars/all.yml test/integration/targets/include_import/playbook/roles/import_playbook_role/tasks/main.yml test/integration/targets/include_import/playbook/sub_playbook/sub_playbook.yml test/integration/targets/include_import/playbook/sub_playbook/library/helloworld.py test/integration/targets/include_import/public_exposure/no_bleeding.yml test/integration/targets/include_import/public_exposure/no_overwrite_roles.yml test/integration/targets/include_import/public_exposure/playbook.yml test/integration/targets/include_import/public_exposure/roles/call_import/tasks/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic/defaults/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic/tasks/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic/vars/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic_private/defaults/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic_private/tasks/main.yml test/integration/targets/include_import/public_exposure/roles/dynamic_private/vars/main.yml test/integration/targets/include_import/public_exposure/roles/from/defaults/from.yml test/integration/targets/include_import/public_exposure/roles/from/tasks/from.yml test/integration/targets/include_import/public_exposure/roles/from/vars/from.yml test/integration/targets/include_import/public_exposure/roles/regular/defaults/main.yml test/integration/targets/include_import/public_exposure/roles/regular/tasks/main.yml test/integration/targets/include_import/public_exposure/roles/regular/vars/main.yml test/integration/targets/include_import/public_exposure/roles/static/defaults/main.yml test/integration/targets/include_import/public_exposure/roles/static/tasks/main.yml test/integration/targets/include_import/public_exposure/roles/static/vars/main.yml test/integration/targets/include_import/role/test_import_role.yml test/integration/targets/include_import/role/test_include_role.yml test/integration/targets/include_import/role/test_include_role_vars_from.yml test/integration/targets/include_import/roles/delegated_handler/handlers/main.yml test/integration/targets/include_import/roles/delegated_handler/tasks/main.yml test/integration/targets/include_import/roles/dup_allowed_role/meta/main.yml test/integration/targets/include_import/roles/dup_allowed_role/tasks/main.yml test/integration/targets/include_import/roles/loop_name_assert/tasks/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2/defaults/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2/meta/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2/tasks/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2/tasks/rund.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2/vars/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2a/defaults/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2a/meta/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2a/tasks/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2a/tasks/rune.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2a/vars/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2b/defaults/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2b/meta/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2b/tasks/main.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2b/tasks/runf.yml test/integration/targets/include_import/roles/nested/nested/nested_dep_role2b/vars/main.yml test/integration/targets/include_import/roles/nested/nested_dep_role/defaults/main.yml test/integration/targets/include_import/roles/nested/nested_dep_role/meta/main.yml test/integration/targets/include_import/roles/nested/nested_dep_role/tasks/main.yml test/integration/targets/include_import/roles/nested/nested_dep_role/tasks/runc.yml test/integration/targets/include_import/roles/nested/nested_dep_role/vars/main.yml test/integration/targets/include_import/roles/nested_include_task/meta/main.yml test/integration/targets/include_import/roles/nested_include_task/tasks/main.yml test/integration/targets/include_import/roles/nested_include_task/tasks/runa.yml test/integration/targets/include_import/roles/role1/tasks/canary1.yml test/integration/targets/include_import/roles/role1/tasks/canary2.yml test/integration/targets/include_import/roles/role1/tasks/canary3.yml test/integration/targets/include_import/roles/role1/tasks/fail.yml test/integration/targets/include_import/roles/role1/tasks/main.yml test/integration/targets/include_import/roles/role1/tasks/r1t01.yml test/integration/targets/include_import/roles/role1/tasks/r1t02.yml test/integration/targets/include_import/roles/role1/tasks/r1t03.yml test/integration/targets/include_import/roles/role1/tasks/r1t04.yml test/integration/targets/include_import/roles/role1/tasks/r1t05.yml test/integration/targets/include_import/roles/role1/tasks/r1t06.yml test/integration/targets/include_import/roles/role1/tasks/r1t07.yml test/integration/targets/include_import/roles/role1/tasks/r1t08.yml test/integration/targets/include_import/roles/role1/tasks/r1t09.yml test/integration/targets/include_import/roles/role1/tasks/r1t10.yml test/integration/targets/include_import/roles/role1/tasks/r1t11.yml test/integration/targets/include_import/roles/role1/tasks/r1t12.yml test/integration/targets/include_import/roles/role1/tasks/tasks.yml test/integration/targets/include_import/roles/role1/tasks/templated.yml test/integration/targets/include_import/roles/role1/tasks/vartest.yml test/integration/targets/include_import/roles/role1/vars/main.yml test/integration/targets/include_import/roles/role1/vars/role1vars.yml test/integration/targets/include_import/roles/role2/tasks/main.yml test/integration/targets/include_import/roles/role3/defaults/main.yml test/integration/targets/include_import/roles/role3/handlers/main.yml test/integration/targets/include_import/roles/role3/tasks/main.yml test/integration/targets/include_import/roles/role3/tasks/tasks.yml test/integration/targets/include_import/roles/role3/tasks/vartest.yml test/integration/targets/include_import/roles/role3/vars/main.yml test/integration/targets/include_import/roles/role3/vars/role3vars.yml test/integration/targets/include_import/roles/role_with_argspec/meta/argument_specs.yml test/integration/targets/include_import/roles/role_with_argspec/tasks/main.yml test/integration/targets/include_import/roles/role_with_deps/meta/main.yml test/integration/targets/include_import/roles/role_with_deps/tasks/main.yml test/integration/targets/include_import/run_once/include_me.yml test/integration/targets/include_import/run_once/playbook.yml test/integration/targets/include_import/tasks/debug_item.yml test/integration/targets/include_import/tasks/task_ansible_loop_index_var.yml test/integration/targets/include_import/tasks/tasks1.yml test/integration/targets/include_import/tasks/tasks2.yml test/integration/targets/include_import/tasks/tasks3.yml test/integration/targets/include_import/tasks/tasks4.yml test/integration/targets/include_import/tasks/tasks5.yml test/integration/targets/include_import/tasks/tasks6.yml test/integration/targets/include_import/tasks/test_allow_single_role_dup.yml test/integration/targets/include_import/tasks/test_dynamic_allow_dup.yml test/integration/targets/include_import/tasks/test_import_tasks.yml test/integration/targets/include_import/tasks/test_import_tasks_tags.yml test/integration/targets/include_import/tasks/test_include_dupe_loop.yml test/integration/targets/include_import/tasks/test_include_tasks.yml test/integration/targets/include_import/tasks/test_include_tasks_tags.yml test/integration/targets/include_import/tasks/test_recursion.yml test/integration/targets/include_import/tasks/test_templating_IncludeRole_FA.yml test/integration/targets/include_import/tasks/validate3.yml test/integration/targets/include_import/tasks/validate_tags.yml test/integration/targets/include_import/tasks/hello/.gitignore test/integration/targets/include_import/tasks/hello/keep test/integration/targets/include_import/tasks/nested/nested.yml test/integration/targets/include_import/undefined_var/include_tasks.yml test/integration/targets/include_import/undefined_var/include_that_defines_var.yml test/integration/targets/include_import/undefined_var/playbook.yml test/integration/targets/include_import/valid_include_keywords/include_me.yml test/integration/targets/include_import/valid_include_keywords/include_me_listen.yml test/integration/targets/include_import/valid_include_keywords/include_me_notify.yml test/integration/targets/include_import/valid_include_keywords/playbook.yml test/integration/targets/include_import_tasks_nested/aliases test/integration/targets/include_import_tasks_nested/tasks/main.yml test/integration/targets/include_import_tasks_nested/tasks/nested/nested_adjacent.yml test/integration/targets/include_import_tasks_nested/tasks/nested/nested_import.yml test/integration/targets/include_import_tasks_nested/tasks/nested/nested_include.yml test/integration/targets/include_parent_role_vars/aliases test/integration/targets/include_parent_role_vars/tasks/included_by_other_role.yml test/integration/targets/include_parent_role_vars/tasks/included_by_ourselves.yml test/integration/targets/include_parent_role_vars/tasks/main.yml test/integration/targets/include_vars/aliases test/integration/targets/include_vars/runme.sh test/integration/targets/include_vars/test_as_playbook.yml test/integration/targets/include_vars/test_as_role.yml test/integration/targets/include_vars-ad-hoc/aliases test/integration/targets/include_vars-ad-hoc/runme.sh test/integration/targets/include_vars-ad-hoc/vaultpass test/integration/targets/include_vars-ad-hoc/dir/encrypted.yml test/integration/targets/include_vars-ad-hoc/dir/inc.yml test/integration/targets/include_vars/defaults/main.yml test/integration/targets/include_vars/files/test_depth/sub1/sub11.yml test/integration/targets/include_vars/files/test_depth/sub1/sub12.yml test/integration/targets/include_vars/files/test_depth/sub1/sub11/config11.yml test/integration/targets/include_vars/files/test_depth/sub1/sub11/config112.yml test/integration/targets/include_vars/files/test_depth/sub2/sub21.yml test/integration/targets/include_vars/files/test_depth/sub2/sub21/config211.yml test/integration/targets/include_vars/files/test_depth/sub2/sub21/config212.yml test/integration/targets/include_vars/files/test_depth/sub3/config3.yml test/integration/targets/include_vars/tasks/main.yml test/integration/targets/include_vars/vars/no_auto_unsafe.yml test/integration/targets/include_vars/vars/all/all.yml test/integration/targets/include_vars/vars/environments/development/all.yml test/integration/targets/include_vars/vars/environments/development/services/webapp.yml test/integration/targets/include_vars/vars/services/service_vars.yml test/integration/targets/include_vars/vars/services/service_vars_fqcn.yml test/integration/targets/include_vars/vars/services/webapp.yml test/integration/targets/include_vars/vars/webapp/file_without_extension test/integration/targets/include_vars/vars2/hashes/hash1.yml test/integration/targets/include_vars/vars2/hashes/hash2.yml test/integration/targets/include_when_parent_is_dynamic/aliases test/integration/targets/include_when_parent_is_dynamic/playbook.yml test/integration/targets/include_when_parent_is_dynamic/runme.sh test/integration/targets/include_when_parent_is_dynamic/syntax_error.yml test/integration/targets/include_when_parent_is_dynamic/tasks.yml test/integration/targets/include_when_parent_is_static/aliases test/integration/targets/include_when_parent_is_static/playbook.yml test/integration/targets/include_when_parent_is_static/runme.sh test/integration/targets/include_when_parent_is_static/syntax_error.yml test/integration/targets/include_when_parent_is_static/tasks.yml test/integration/targets/includes/aliases test/integration/targets/includes/include_on_playbook_should_fail.yml test/integration/targets/includes/includes_loop_rescue.yml test/integration/targets/includes/inherit_notify.yml test/integration/targets/includes/runme.sh test/integration/targets/includes/test_include_free.yml test/integration/targets/includes/test_include_host_pinned.yml test/integration/targets/includes/test_includes.yml test/integration/targets/includes/test_includes2.yml test/integration/targets/includes/test_includes3.yml test/integration/targets/includes/test_includes4.yml test/integration/targets/includes/roles/test_includes/handlers/main.yml test/integration/targets/includes/roles/test_includes/handlers/more_handlers.yml test/integration/targets/includes/roles/test_includes/tasks/branch_toplevel.yml test/integration/targets/includes/roles/test_includes/tasks/empty.yml test/integration/targets/includes/roles/test_includes/tasks/included_task1.yml test/integration/targets/includes/roles/test_includes/tasks/leaf_sublevel.yml test/integration/targets/includes/roles/test_includes/tasks/main.yml test/integration/targets/includes/roles/test_includes/tasks/not_a_role_task.yml test/integration/targets/includes/roles/test_includes_free/tasks/inner.yml test/integration/targets/includes/roles/test_includes_free/tasks/inner_fqcn.yml test/integration/targets/includes/roles/test_includes_free/tasks/main.yml test/integration/targets/includes/roles/test_includes_host_pinned/tasks/inner.yml test/integration/targets/includes/roles/test_includes_host_pinned/tasks/main.yml test/integration/targets/includes/tasks/trigger_change.yml test/integration/targets/includes_race/aliases test/integration/targets/includes_race/inventory test/integration/targets/includes_race/runme.sh test/integration/targets/includes_race/test_includes_race.yml test/integration/targets/includes_race/roles/random_sleep/tasks/main.yml test/integration/targets/includes_race/roles/set_a_fact/tasks/fact1.yml test/integration/targets/includes_race/roles/set_a_fact/tasks/fact2.yml test/integration/targets/infra/aliases test/integration/targets/infra/inventory.local test/integration/targets/infra/runme.sh test/integration/targets/infra/test_test_infra.yml test/integration/targets/infra/library/test.py test/integration/targets/interpreter_discovery_python/aliases test/integration/targets/interpreter_discovery_python/bad-connection.yml test/integration/targets/interpreter_discovery_python/discovery.yml test/integration/targets/interpreter_discovery_python/runme.sh test/integration/targets/interpreter_discovery_python/library/test_echo_module.py test/integration/targets/interpreter_discovery_python/library/test_non_python_interpreter.py test/integration/targets/interpreter_discovery_python/tasks/config_templating.yml test/integration/targets/interpreter_discovery_python/tasks/main.yml test/integration/targets/interpreter_discovery_python_delegate_facts/aliases test/integration/targets/interpreter_discovery_python_delegate_facts/delegate_facts.yml test/integration/targets/interpreter_discovery_python_delegate_facts/inventory test/integration/targets/interpreter_discovery_python_delegate_facts/runme.sh test/integration/targets/inventory/aliases test/integration/targets/inventory/extra_vars_constructed.yml test/integration/targets/inventory/host_vars_constructed.yml test/integration/targets/inventory/inv_with_host_vars.yml test/integration/targets/inventory/inv_with_int.yml test/integration/targets/inventory/playbook.yml test/integration/targets/inventory/runme.sh test/integration/targets/inventory/strategy.yml test/integration/targets/inventory/test_empty.yml test/integration/targets/inventory-invalid-group/aliases test/integration/targets/inventory-invalid-group/inventory.ini test/integration/targets/inventory-invalid-group/runme.sh test/integration/targets/inventory-invalid-group/test.yml test/integration/targets/inventory/1/vars.yml test/integration/targets/inventory/1/2/inventory.yml test/integration/targets/inventory/1/2/3/extra_vars_relative.yml test/integration/targets/inventory/doc_fragments/fragment_with_expression.py test/integration/targets/inventory/inventory_plugins/constructed_with_hostvars.py test/integration/targets/inventory_advanced_host_list/aliases test/integration/targets/inventory_advanced_host_list/runme.sh test/integration/targets/inventory_advanced_host_list/test_advanced_host_list.yml test/integration/targets/inventory_cache/aliases test/integration/targets/inventory_cache/cache_host.yml test/integration/targets/inventory_cache/exercise_cache.yml test/integration/targets/inventory_cache/runme.sh test/integration/targets/inventory_cache/cache/.keep test/integration/targets/inventory_cache/plugins/inventory/cache_host.py test/integration/targets/inventory_cache/plugins/inventory/exercise_cache.py test/integration/targets/inventory_constructed/aliases test/integration/targets/inventory_constructed/constructed.yml test/integration/targets/inventory_constructed/keyed_group_default_value.yml test/integration/targets/inventory_constructed/keyed_group_list_default_value.yml test/integration/targets/inventory_constructed/keyed_group_str_default_value.yml test/integration/targets/inventory_constructed/keyed_group_trailing_separator.yml test/integration/targets/inventory_constructed/no_leading_separator_constructed.yml test/integration/targets/inventory_constructed/runme.sh test/integration/targets/inventory_constructed/static_inventory.yml test/integration/targets/inventory_constructed/tag_inventory.yml test/integration/targets/inventory_constructed/invs/1/one.yml test/integration/targets/inventory_constructed/invs/1/group_vars/stuff.yml test/integration/targets/inventory_constructed/invs/1/host_vars/testing.yml test/integration/targets/inventory_constructed/invs/2/constructed.yml test/integration/targets/inventory_generator/aliases test/integration/targets/inventory_generator/generator.yml test/integration/targets/inventory_generator/parent_without_name.yml test/integration/targets/inventory_generator/runme.sh test/integration/targets/inventory_generator/verify.yml test/integration/targets/inventory_ini/aliases test/integration/targets/inventory_ini/inventory.ini test/integration/targets/inventory_ini/runme.sh test/integration/targets/inventory_ini/test_ansible_become.yml test/integration/targets/inventory_ini/test_types.yml test/integration/targets/inventory_script/aliases test/integration/targets/inventory_script/bad_shebang test/integration/targets/inventory_script/script_inventory_fixture.py test/integration/targets/inventory_script/tasks/main.yml test/integration/targets/inventory_script/tasks/test_broken_inventory.yml test/integration/targets/inventory_script/tasks/test_valid_inventory.yml test/integration/targets/inventory_toml/aliases test/integration/targets/inventory_toml/inventory.toml test/integration/targets/inventory_toml/playbook.yml test/integration/targets/inventory_toml/runme.sh test/integration/targets/inventory_yaml/aliases test/integration/targets/inventory_yaml/empty.json test/integration/targets/inventory_yaml/runme.sh test/integration/targets/inventory_yaml/success.json test/integration/targets/inventory_yaml/test.yml test/integration/targets/inventory_yaml/test_int_hostname.yml test/integration/targets/iptables/aliases test/integration/targets/iptables/tasks/chain_management.yml test/integration/targets/iptables/tasks/main.yml test/integration/targets/iptables/vars/alpine.yml test/integration/targets/iptables/vars/centos.yml test/integration/targets/iptables/vars/default.yml test/integration/targets/iptables/vars/fedora.yml test/integration/targets/iptables/vars/redhat.yml test/integration/targets/iptables/vars/suse.yml test/integration/targets/jinja2_native_types/aliases test/integration/targets/jinja2_native_types/nested_undefined.yml test/integration/targets/jinja2_native_types/runme.sh test/integration/targets/jinja2_native_types/runtests.yml test/integration/targets/jinja2_native_types/test_bool.yml test/integration/targets/jinja2_native_types/test_casting.yml test/integration/targets/jinja2_native_types/test_concatentation.yml test/integration/targets/jinja2_native_types/test_hostvars.yml test/integration/targets/jinja2_native_types/test_none.yml test/integration/targets/jinja2_native_types/test_preserving_quotes.yml test/integration/targets/jinja2_native_types/test_template.yml test/integration/targets/jinja2_native_types/test_template_newlines.j2 test/integration/targets/jinja2_native_types/test_types.yml test/integration/targets/jinja2_native_types/test_vault.yml test/integration/targets/jinja2_native_types/test_vault_pass test/integration/targets/jinja_plugins/aliases test/integration/targets/jinja_plugins/playbook.yml test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/bad_collection_filter.py test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/bad_collection_filter2.py test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/filter/good_collection_filter.py test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/bad_collection_test.py test/integration/targets/jinja_plugins/collections/ansible_collections/foo/bar/plugins/test/good_collection_test.py test/integration/targets/jinja_plugins/filter_plugins/bad_filter.py test/integration/targets/jinja_plugins/filter_plugins/good_filter.py test/integration/targets/jinja_plugins/tasks/main.yml test/integration/targets/jinja_plugins/test_plugins/bad_test.py test/integration/targets/jinja_plugins/test_plugins/good_test.py test/integration/targets/json-serialization/aliases test/integration/targets/json-serialization/runme.sh test/integration/targets/json-serialization/test.yml test/integration/targets/json_cleanup/aliases test/integration/targets/json_cleanup/module_output_cleaning.yml test/integration/targets/json_cleanup/runme.sh test/integration/targets/json_cleanup/library/bad_json test/integration/targets/keyword_inheritance/aliases test/integration/targets/keyword_inheritance/dep_keyword_inheritance.yml test/integration/targets/keyword_inheritance/runme.sh test/integration/targets/keyword_inheritance/test.yml test/integration/targets/keyword_inheritance/roles/role-meta-inheritance/meta/main.yml test/integration/targets/keyword_inheritance/roles/whoami/tasks/main.yml test/integration/targets/known_hosts/aliases test/integration/targets/known_hosts/defaults/main.yml test/integration/targets/known_hosts/files/existing_known_hosts test/integration/targets/known_hosts/meta/main.yml test/integration/targets/known_hosts/tasks/main.yml test/integration/targets/limit_inventory/aliases test/integration/targets/limit_inventory/hosts.yml test/integration/targets/limit_inventory/runme.sh test/integration/targets/lineinfile/aliases test/integration/targets/lineinfile/files/firstmatch.txt test/integration/targets/lineinfile/files/test.conf test/integration/targets/lineinfile/files/test.txt test/integration/targets/lineinfile/files/test_58923.txt test/integration/targets/lineinfile/files/testempty.txt test/integration/targets/lineinfile/files/testmultiple.txt test/integration/targets/lineinfile/files/testnoeof.txt test/integration/targets/lineinfile/files/teststring.conf test/integration/targets/lineinfile/files/teststring.txt test/integration/targets/lineinfile/files/teststring_58923.txt test/integration/targets/lineinfile/meta/main.yml test/integration/targets/lineinfile/tasks/acls.yml test/integration/targets/lineinfile/tasks/main.yml test/integration/targets/lineinfile/tasks/test_string01.yml test/integration/targets/lineinfile/tasks/test_string02.yml test/integration/targets/lineinfile/vars/main.yml test/integration/targets/lookup-option-name/aliases test/integration/targets/lookup-option-name/lookup_plugins/non_terms_posargs.py test/integration/targets/lookup-option-name/tasks/main.yml test/integration/targets/lookup_config/aliases test/integration/targets/lookup_config/runme.sh test/integration/targets/lookup_config/runme.yml test/integration/targets/lookup_config/lookup_plugins/bogus.py test/integration/targets/lookup_config/tasks/main.yml test/integration/targets/lookup_csvfile/aliases test/integration/targets/lookup_csvfile/files/cool list of things.csv test/integration/targets/lookup_csvfile/files/crlf.csv test/integration/targets/lookup_csvfile/files/people.csv test/integration/targets/lookup_csvfile/files/tabs.csv test/integration/targets/lookup_csvfile/files/x1a.csv test/integration/targets/lookup_csvfile/tasks/main.yml test/integration/targets/lookup_dict/aliases test/integration/targets/lookup_dict/tasks/main.yml test/integration/targets/lookup_env/aliases test/integration/targets/lookup_env/runme.sh test/integration/targets/lookup_env/vars_not_set.yml test/integration/targets/lookup_env/vars_set.yml test/integration/targets/lookup_file/aliases test/integration/targets/lookup_file/tasks/main.yml test/integration/targets/lookup_fileglob/aliases test/integration/targets/lookup_fileglob/runme.sh test/integration/targets/lookup_fileglob/find_levels/play.yml test/integration/targets/lookup_fileglob/find_levels/play_adj.txt test/integration/targets/lookup_fileglob/find_levels/files/play_adj_subdir.txt test/integration/targets/lookup_fileglob/find_levels/files/somepath/play_adj_subsubdir.txt test/integration/targets/lookup_fileglob/find_levels/roles/get_file/files/in_role.txt test/integration/targets/lookup_fileglob/find_levels/roles/get_file/files/otherpath/in_role_subdir.txt test/integration/targets/lookup_fileglob/find_levels/roles/get_file/tasks/main.yml test/integration/targets/lookup_fileglob/issue72873/test.yml test/integration/targets/lookup_fileglob/non_existent/play.yml test/integration/targets/lookup_first_found/aliases test/integration/targets/lookup_first_found/action_plugins/debug_file_alias.py test/integration/targets/lookup_first_found/action_plugins/debug_template_alias.py test/integration/targets/lookup_first_found/action_plugins/debug_var_alias.py test/integration/targets/lookup_first_found/files/bar1 test/integration/targets/lookup_first_found/files/findme.txt test/integration/targets/lookup_first_found/files/foo1 test/integration/targets/lookup_first_found/files/vars file spaces.yml test/integration/targets/lookup_first_found/roles/a/tasks/main.yml test/integration/targets/lookup_first_found/roles/a/tasks/subdir/main.yml test/integration/targets/lookup_first_found/roles/a/tasks/subdir/relative test/integration/targets/lookup_first_found/tasks/main.yml test/integration/targets/lookup_first_found/templates/findme.txt test/integration/targets/lookup_first_found/vars/findme.txt test/integration/targets/lookup_first_found/vars/ishouldnotbefound.yml test/integration/targets/lookup_first_found/vars/itworks.yml test/integration/targets/lookup_indexed_items/aliases test/integration/targets/lookup_indexed_items/tasks/main.yml test/integration/targets/lookup_ini/aliases test/integration/targets/lookup_ini/duplicate.ini test/integration/targets/lookup_ini/duplicate_case_check.ini test/integration/targets/lookup_ini/interpolation.ini test/integration/targets/lookup_ini/inventory test/integration/targets/lookup_ini/lookup-8859-15.ini test/integration/targets/lookup_ini/lookup.ini test/integration/targets/lookup_ini/lookup.properties test/integration/targets/lookup_ini/lookup_case_check.properties test/integration/targets/lookup_ini/mysql.ini test/integration/targets/lookup_ini/nointerpolation.ini test/integration/targets/lookup_ini/runme.sh test/integration/targets/lookup_ini/test_allow_no_value.yml test/integration/targets/lookup_ini/test_case_sensitive.yml test/integration/targets/lookup_ini/test_errors.yml test/integration/targets/lookup_ini/test_ini.yml test/integration/targets/lookup_ini/test_interpolation.yml test/integration/targets/lookup_ini/test_lookup_properties.yml test/integration/targets/lookup_inventory_hostnames/aliases test/integration/targets/lookup_inventory_hostnames/inventory test/integration/targets/lookup_inventory_hostnames/main.yml test/integration/targets/lookup_inventory_hostnames/runme.sh test/integration/targets/lookup_items/aliases test/integration/targets/lookup_items/tasks/main.yml test/integration/targets/lookup_lines/aliases test/integration/targets/lookup_lines/tasks/main.yml test/integration/targets/lookup_list/aliases test/integration/targets/lookup_list/tasks/main.yml test/integration/targets/lookup_nested/aliases test/integration/targets/lookup_nested/tasks/main.yml test/integration/targets/lookup_password/aliases test/integration/targets/lookup_password/runme.sh test/integration/targets/lookup_password/runme.yml test/integration/targets/lookup_password/tasks/main.yml test/integration/targets/lookup_pipe/aliases test/integration/targets/lookup_pipe/tasks/main.yml test/integration/targets/lookup_random_choice/aliases test/integration/targets/lookup_random_choice/tasks/main.yml test/integration/targets/lookup_sequence/aliases test/integration/targets/lookup_sequence/tasks/main.yml test/integration/targets/lookup_subelements/aliases test/integration/targets/lookup_subelements/tasks/main.yml test/integration/targets/lookup_subelements/vars/main.yml test/integration/targets/lookup_template/aliases test/integration/targets/lookup_template/files/trim_blocks_false.expected test/integration/targets/lookup_template/files/trim_blocks_true.expected test/integration/targets/lookup_template/tasks/main.yml test/integration/targets/lookup_template/tasks/trim_blocks.yml test/integration/targets/lookup_template/templates/dict.j2 test/integration/targets/lookup_template/templates/hello.txt test/integration/targets/lookup_template/templates/hello_comment.txt test/integration/targets/lookup_template/templates/hello_string.txt test/integration/targets/lookup_template/templates/none.j2 test/integration/targets/lookup_template/templates/trim_blocks.j2 test/integration/targets/lookup_template/templates/world.txt test/integration/targets/lookup_together/aliases test/integration/targets/lookup_together/tasks/main.yml test/integration/targets/lookup_unvault/aliases test/integration/targets/lookup_unvault/runme.sh test/integration/targets/lookup_unvault/secret test/integration/targets/lookup_unvault/unvault.yml test/integration/targets/lookup_unvault/files/foot.txt test/integration/targets/lookup_unvault/files/foot.txt.vault test/integration/targets/lookup_url/aliases test/integration/targets/lookup_url/meta/main.yml test/integration/targets/lookup_url/tasks/ciphers.yml test/integration/targets/lookup_url/tasks/main.yml test/integration/targets/lookup_url/tasks/use_netrc.yml test/integration/targets/lookup_varnames/aliases test/integration/targets/lookup_varnames/tasks/main.yml test/integration/targets/lookup_vars/aliases test/integration/targets/lookup_vars/tasks/main.yml test/integration/targets/loop-connection/aliases test/integration/targets/loop-connection/main.yml test/integration/targets/loop-connection/runme.sh test/integration/targets/loop-connection/collections/ansible_collections/ns/name/meta/runtime.yml test/integration/targets/loop-connection/collections/ansible_collections/ns/name/plugins/connection/dummy.py test/integration/targets/loop-until/aliases test/integration/targets/loop-until/tasks/main.yml test/integration/targets/loop_control/aliases test/integration/targets/loop_control/break_when.yml test/integration/targets/loop_control/extended.yml test/integration/targets/loop_control/inner.yml test/integration/targets/loop_control/label.yml test/integration/targets/loop_control/runme.sh test/integration/targets/loops/aliases test/integration/targets/loops/files/data1.txt test/integration/targets/loops/files/data2.txt test/integration/targets/loops/tasks/index_var_tasks.yml test/integration/targets/loops/tasks/main.yml test/integration/targets/loops/tasks/templated_loop_var_tasks.yml test/integration/targets/loops/vars/main.yml test/integration/targets/meta_tasks/aliases test/integration/targets/meta_tasks/inventory.yml test/integration/targets/meta_tasks/inventory_new.yml test/integration/targets/meta_tasks/inventory_old.yml test/integration/targets/meta_tasks/inventory_refresh.yml test/integration/targets/meta_tasks/refresh.yml test/integration/targets/meta_tasks/refresh_preserve_dynamic.yml test/integration/targets/meta_tasks/runme.sh test/integration/targets/meta_tasks/test_end_batch.yml test/integration/targets/meta_tasks/test_end_host.yml test/integration/targets/meta_tasks/test_end_host_all.yml test/integration/targets/meta_tasks/test_end_host_all_fqcn.yml test/integration/targets/meta_tasks/test_end_host_fqcn.yml test/integration/targets/meta_tasks/test_end_host_rescue_rc.yml test/integration/targets/meta_tasks/test_end_play.yml test/integration/targets/meta_tasks/test_end_play_fqcn.yml test/integration/targets/meta_tasks/test_end_play_multiple_plays.yml test/integration/targets/meta_tasks/test_end_play_serial_one.yml test/integration/targets/missing-interpreter/aliases test/integration/targets/missing-interpreter/tasks/main.yml test/integration/targets/missing_required_lib/aliases test/integration/targets/missing_required_lib/runme.sh test/integration/targets/missing_required_lib/runme.yml test/integration/targets/missing_required_lib/library/missing_required_lib.py test/integration/targets/missing_required_lib/tasks/main.yml test/integration/targets/module-serialization-profiles/aliases test/integration/targets/module-serialization-profiles/library/echo_legacy.py test/integration/targets/module-serialization-profiles/library/echo_modern.py test/integration/targets/module-serialization-profiles/library/echo_unspecified.py test/integration/targets/module-serialization-profiles/tasks/main.yml test/integration/targets/module-serialization-profiles/vars/main.yml test/integration/targets/module_defaults/aliases test/integration/targets/module_defaults/runme.sh test/integration/targets/module_defaults/test_action_group_metadata.yml test/integration/targets/module_defaults/test_action_groups.yml test/integration/targets/module_defaults/test_defaults.yml test/integration/targets/module_defaults/test_templated_defaults.yml test/integration/targets/module_defaults/action_plugins/debug.py test/integration/targets/module_defaults/collections/ansible_collections/testns/othercoll/plugins/action/other_echoaction.py test/integration/targets/module_defaults/collections/ansible_collections/testns/othercoll/plugins/modules/other_echo1.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/meta/runtime.yml test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/action/echoaction.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/action/eos.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/action/ios.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/action/vyos.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/module_utils/echo_impl.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/echo1.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/echo2.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/eosfacts.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/ios_facts.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/metadata.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/module.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/ping.py test/integration/targets/module_defaults/collections/ansible_collections/testns/testcoll/plugins/modules/vyosfacts.py test/integration/targets/module_defaults/library/legacy_ping.py test/integration/targets/module_defaults/library/test_module_defaults.py test/integration/targets/module_defaults/tasks/main.yml test/integration/targets/module_defaults/templates/test_metadata_warning.yml.j2 test/integration/targets/module_no_log/aliases test/integration/targets/module_no_log/library/module_that_has_secret.py test/integration/targets/module_no_log/library/module_that_logs.py test/integration/targets/module_no_log/tasks/main.yml test/integration/targets/module_precedence/aliases test/integration/targets/module_precedence/modules_test.yml test/integration/targets/module_precedence/modules_test_envvar.yml test/integration/targets/module_precedence/modules_test_envvar_ext.yml test/integration/targets/module_precedence/modules_test_multiple_roles.yml test/integration/targets/module_precedence/modules_test_multiple_roles_reverse_order.yml test/integration/targets/module_precedence/modules_test_role.yml test/integration/targets/module_precedence/modules_test_role_ext.yml test/integration/targets/module_precedence/runme.sh test/integration/targets/module_precedence/lib_no_extension/ping test/integration/targets/module_precedence/lib_with_extension/a.ini test/integration/targets/module_precedence/lib_with_extension/a.py test/integration/targets/module_precedence/lib_with_extension/ping.ini test/integration/targets/module_precedence/lib_with_extension/ping.py test/integration/targets/module_precedence/multiple_roles/bar/library/ping.py test/integration/targets/module_precedence/multiple_roles/bar/tasks/main.yml test/integration/targets/module_precedence/multiple_roles/foo/library/ping.py test/integration/targets/module_precedence/multiple_roles/foo/tasks/main.yml test/integration/targets/module_precedence/roles_no_extension/foo/library/ping test/integration/targets/module_precedence/roles_no_extension/foo/tasks/main.yml test/integration/targets/module_precedence/roles_with_extension/foo/library/a.ini test/integration/targets/module_precedence/roles_with_extension/foo/library/a.py test/integration/targets/module_precedence/roles_with_extension/foo/library/ping.ini test/integration/targets/module_precedence/roles_with_extension/foo/library/ping.py test/integration/targets/module_precedence/roles_with_extension/foo/tasks/main.yml test/integration/targets/module_tracebacks/aliases test/integration/targets/module_tracebacks/inventory test/integration/targets/module_tracebacks/runme.sh test/integration/targets/module_tracebacks/traceback.yml test/integration/targets/module_tracebacks/library/ansibull.py test/integration/targets/module_utils/aliases test/integration/targets/module_utils/module_utils_basic_setcwd.yml test/integration/targets/module_utils/module_utils_common_dict_transformation.yml test/integration/targets/module_utils/module_utils_common_network.yml test/integration/targets/module_utils/module_utils_envvar.yml test/integration/targets/module_utils/module_utils_test.yml test/integration/targets/module_utils/module_utils_test_no_log.yml test/integration/targets/module_utils/module_utils_vvvvv.yml test/integration/targets/module_utils/runme.sh test/integration/targets/module_utils/callback/pure_json.py test/integration/targets/module_utils/collections/ansible_collections/testns/testcoll/plugins/module_utils/legit.py test/integration/targets/module_utils/library/test.py test/integration/targets/module_utils/library/test_alias_deprecation.py test/integration/targets/module_utils/library/test_cwd_missing.py test/integration/targets/module_utils/library/test_cwd_unreadable.py test/integration/targets/module_utils/library/test_datetime.py test/integration/targets/module_utils/library/test_env_override.py test/integration/targets/module_utils/library/test_failure.py test/integration/targets/module_utils/library/test_heuristic_log_sanitize.py test/integration/targets/module_utils/library/test_network.py test/integration/targets/module_utils/library/test_no_log.py test/integration/targets/module_utils/library/test_optional.py test/integration/targets/module_utils/library/test_override.py test/integration/targets/module_utils/library/test_recursive_diff.py test/integration/targets/module_utils/module_utils/__init__.py test/integration/targets/module_utils/module_utils/ansible_release.py test/integration/targets/module_utils/module_utils/foo0.py test/integration/targets/module_utils/module_utils/foo1.py test/integration/targets/module_utils/module_utils/foo2.py test/integration/targets/module_utils/module_utils/service.py test/integration/targets/module_utils/module_utils/a/__init__.py test/integration/targets/module_utils/module_utils/a/b/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/d/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/d/e/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/d/e/f/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/d/e/f/g/__init__.py test/integration/targets/module_utils/module_utils/a/b/c/d/e/f/g/h/__init__.py test/integration/targets/module_utils/module_utils/bar0/__init__.py test/integration/targets/module_utils/module_utils/bar0/foo3.py test/integration/targets/module_utils/module_utils/bar1/__init__.py test/integration/targets/module_utils/module_utils/bar2/__init__.py test/integration/targets/module_utils/module_utils/baz1/__init__.py test/integration/targets/module_utils/module_utils/baz1/one.py test/integration/targets/module_utils/module_utils/baz2/__init__.py test/integration/targets/module_utils/module_utils/baz2/one.py test/integration/targets/module_utils/module_utils/qux1/__init__.py test/integration/targets/module_utils/module_utils/qux1/quux.py test/integration/targets/module_utils/module_utils/qux2/__init__.py test/integration/targets/module_utils/module_utils/qux2/quux.py test/integration/targets/module_utils/module_utils/qux2/quuz.py test/integration/targets/module_utils/module_utils/spam1/__init__.py test/integration/targets/module_utils/module_utils/spam1/ham/__init__.py test/integration/targets/module_utils/module_utils/spam1/ham/eggs/__init__.py test/integration/targets/module_utils/module_utils/spam2/__init__.py test/integration/targets/module_utils/module_utils/spam2/ham/__init__.py test/integration/targets/module_utils/module_utils/spam2/ham/eggs/__init__.py test/integration/targets/module_utils/module_utils/spam3/__init__.py test/integration/targets/module_utils/module_utils/spam3/ham/__init__.py test/integration/targets/module_utils/module_utils/spam3/ham/bacon.py test/integration/targets/module_utils/module_utils/spam4/__init__.py test/integration/targets/module_utils/module_utils/spam4/ham/__init__.py test/integration/targets/module_utils/module_utils/spam4/ham/bacon.py test/integration/targets/module_utils/module_utils/spam5/__init__.py test/integration/targets/module_utils/module_utils/spam5/ham/__init__.py test/integration/targets/module_utils/module_utils/spam5/ham/bacon.py test/integration/targets/module_utils/module_utils/spam5/ham/eggs.py test/integration/targets/module_utils/module_utils/spam6/__init__.py test/integration/targets/module_utils/module_utils/spam6/ham/__init__.py test/integration/targets/module_utils/module_utils/spam7/__init__.py test/integration/targets/module_utils/module_utils/spam7/ham/__init__.py test/integration/targets/module_utils/module_utils/spam7/ham/bacon.py test/integration/targets/module_utils/module_utils/spam8/__init__.py test/integration/targets/module_utils/module_utils/spam8/ham/__init__.py test/integration/targets/module_utils/module_utils/spam8/ham/bacon.py test/integration/targets/module_utils/module_utils/sub/__init__.py test/integration/targets/module_utils/module_utils/sub/bam.py test/integration/targets/module_utils/module_utils/sub/bam/__init__.py test/integration/targets/module_utils/module_utils/sub/bam/bam.py test/integration/targets/module_utils/module_utils/yak/__init__.py test/integration/targets/module_utils/module_utils/yak/zebra/__init__.py test/integration/targets/module_utils/module_utils/yak/zebra/foo4.py test/integration/targets/module_utils/other_mu_dir/__init__.py test/integration/targets/module_utils/other_mu_dir/facts.py test/integration/targets/module_utils/other_mu_dir/json_utils.py test/integration/targets/module_utils/other_mu_dir/mork.py test/integration/targets/module_utils/other_mu_dir/a/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/d/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/d/e/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/d/e/f/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/d/e/f/g/__init__.py test/integration/targets/module_utils/other_mu_dir/a/b/c/d/e/f/g/h/__init__.py test/integration/targets/module_utils_Ansible.AccessToken/aliases test/integration/targets/module_utils_Ansible.AccessToken/library/ansible_access_token_tests.ps1 test/integration/targets/module_utils_Ansible.AccessToken/tasks/main.yml test/integration/targets/module_utils_Ansible.Basic/aliases test/integration/targets/module_utils_Ansible.Basic/library/ansible_basic_tests.ps1 test/integration/targets/module_utils_Ansible.Basic/tasks/main.yml test/integration/targets/module_utils_Ansible.Become/aliases test/integration/targets/module_utils_Ansible.Become/library/ansible_become_tests.ps1 test/integration/targets/module_utils_Ansible.Become/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/library/add_type_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.AddType/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.ArgvParser/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.ArgvParser/library/argv_parser_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.ArgvParser/meta/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.ArgvParser/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.Backup/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.Backup/library/backup_file_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.Backup/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.CamelConversion/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.CamelConversion/library/camel_conversion_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.CamelConversion/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.CommandUtil/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.CommandUtil/library/command_util_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.CommandUtil/meta/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.CommandUtil/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.FileUtil/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.FileUtil/library/file_util_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.FileUtil/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.Legacy/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.Legacy/library/testlist.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.Legacy/library/testpath.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.Legacy/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.LinkUtil/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.LinkUtil/library/symbolic_link_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.LinkUtil/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.PrivilegeUtil/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.PrivilegeUtil/library/privilege_util_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.PrivilegeUtil/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.SID/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.SID/library/sid_utils_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.SID/tasks/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.WebRequest/aliases test/integration/targets/module_utils_Ansible.ModuleUtils.WebRequest/library/web_request_test.ps1 test/integration/targets/module_utils_Ansible.ModuleUtils.WebRequest/meta/main.yml test/integration/targets/module_utils_Ansible.ModuleUtils.WebRequest/tasks/main.yml test/integration/targets/module_utils_Ansible.Privilege/aliases test/integration/targets/module_utils_Ansible.Privilege/library/ansible_privilege_tests.ps1 test/integration/targets/module_utils_Ansible.Privilege/tasks/main.yml test/integration/targets/module_utils_Ansible.Process/aliases test/integration/targets/module_utils_Ansible.Process/library/ansible_process_tests.ps1 test/integration/targets/module_utils_Ansible.Process/tasks/main.yml test/integration/targets/module_utils_Ansible.Service/aliases test/integration/targets/module_utils_Ansible.Service/library/ansible_service_tests.ps1 test/integration/targets/module_utils_Ansible.Service/tasks/main.yml test/integration/targets/module_utils_ansible_release/aliases test/integration/targets/module_utils_ansible_release/library/ansible_release.py test/integration/targets/module_utils_ansible_release/tasks/main.yml test/integration/targets/module_utils_common.respawn/aliases test/integration/targets/module_utils_common.respawn/library/respawnme.py test/integration/targets/module_utils_common.respawn/tasks/main.yml test/integration/targets/module_utils_distro/aliases test/integration/targets/module_utils_distro/runme.sh test/integration/targets/module_utils_distro/meta/main.yml test/integration/targets/module_utils_facts.system.selinux/aliases test/integration/targets/module_utils_facts.system.selinux/tasks/main.yml test/integration/targets/module_utils_facts.system.selinux/tasks/selinux.yml test/integration/targets/module_utils_urls/aliases test/integration/targets/module_utils_urls/library/test_peercert.py test/integration/targets/module_utils_urls/meta/main.yml test/integration/targets/module_utils_urls/tasks/main.yml test/integration/targets/mount_facts/aliases test/integration/targets/mount_facts/meta/main.yml test/integration/targets/mount_facts/tasks/main.yml test/integration/targets/no_log/aliases test/integration/targets/no_log/ansible_no_log_in_result.yml test/integration/targets/no_log/dynamic.yml test/integration/targets/no_log/no_log_config.yml test/integration/targets/no_log/no_log_local.yml test/integration/targets/no_log/no_log_suboptions.yml test/integration/targets/no_log/no_log_suboptions_invalid.yml test/integration/targets/no_log/runme.sh test/integration/targets/no_log/secretvars.yml test/integration/targets/no_log/action_plugins/action_sets_no_log.py test/integration/targets/no_log/library/module.py test/integration/targets/noexec/aliases test/integration/targets/noexec/inventory test/integration/targets/noexec/runme.sh test/integration/targets/noexec/test-noexec.yml test/integration/targets/old_style_modules_posix/aliases test/integration/targets/old_style_modules_posix/library/helloworld.sh test/integration/targets/old_style_modules_posix/meta/main.yml test/integration/targets/old_style_modules_posix/tasks/main.yml test/integration/targets/old_style_vars_plugins/aliases test/integration/targets/old_style_vars_plugins/runme.sh test/integration/targets/old_style_vars_plugins/deprecation_warning/v2_vars_plugin.py test/integration/targets/old_style_vars_plugins/roles/a/tasks/main.yml test/integration/targets/old_style_vars_plugins/roles/a/vars_plugins/auto_role_vars.py test/integration/targets/old_style_vars_plugins/vars_plugins/auto_enabled.py test/integration/targets/old_style_vars_plugins/vars_plugins/implicitly_auto_enabled.py test/integration/targets/old_style_vars_plugins/vars_plugins/require_enabled.py test/integration/targets/omit/48673.yml test/integration/targets/omit/75692.yml test/integration/targets/omit/C75692.yml test/integration/targets/omit/aliases test/integration/targets/omit/runme.sh test/integration/targets/order/aliases test/integration/targets/order/inventory test/integration/targets/order/order.yml test/integration/targets/order/runme.sh test/integration/targets/package/aliases test/integration/targets/package/meta/main.yml test/integration/targets/package/tasks/main.yml test/integration/targets/package_facts/aliases test/integration/targets/package_facts/runme.sh test/integration/targets/package_facts/runme.yml test/integration/targets/package_facts/test_warning_failed.yml test/integration/targets/package_facts/test_warning_unusable.yml test/integration/targets/package_facts/files/apk test/integration/targets/package_facts/tasks/main.yml test/integration/targets/packaging_cli-doc/aliases test/integration/targets/packaging_cli-doc/runme.sh test/integration/targets/packaging_cli-doc/template.j2 test/integration/targets/packaging_cli-doc/verify.py test/integration/targets/parsing/aliases test/integration/targets/parsing/good_parsing.yml test/integration/targets/parsing/parsing.yml test/integration/targets/parsing/runme.sh test/integration/targets/parsing/roles/test_good_parsing/tasks/main.yml test/integration/targets/parsing/roles/test_good_parsing/tasks/test_include.yml test/integration/targets/parsing/roles/test_good_parsing/tasks/test_include_conditional.yml test/integration/targets/parsing/roles/test_good_parsing/tasks/test_include_nested.yml test/integration/targets/parsing/roles/test_good_parsing/vars/main.yml test/integration/targets/path_lookups/aliases test/integration/targets/path_lookups/play.yml test/integration/targets/path_lookups/runme.sh test/integration/targets/path_lookups/testplay.yml test/integration/targets/path_lookups/roles/showfile/tasks/notmain.yml test/integration/targets/path_with_comma_in_inventory/aliases test/integration/targets/path_with_comma_in_inventory/playbook.yml test/integration/targets/path_with_comma_in_inventory/runme.sh test/integration/targets/path_with_comma_in_inventory/this,path,has,commas/hosts test/integration/targets/path_with_comma_in_inventory/this,path,has,commas/group_vars/all.yml test/integration/targets/pause/aliases test/integration/targets/pause/pause-1.yml test/integration/targets/pause/pause-2.yml test/integration/targets/pause/pause-3.yml test/integration/targets/pause/pause-4.yml test/integration/targets/pause/pause-5.yml test/integration/targets/pause/pause-6.yml test/integration/targets/pause/runme.sh test/integration/targets/pause/test-pause-background.yml test/integration/targets/pause/test-pause-no-tty.yml test/integration/targets/pause/test-pause.py test/integration/targets/pause/test-pause.yml test/integration/targets/ping/aliases test/integration/targets/ping/tasks/main.yml test/integration/targets/pip/aliases test/integration/targets/pip/files/setup.py test/integration/targets/pip/files/ansible_test_pip_chdir/__init__.py test/integration/targets/pip/files/sample-project/pyproject.toml test/integration/targets/pip/files/sample-project/src/sample_project/__init__.py test/integration/targets/pip/meta/main.yml test/integration/targets/pip/tasks/break_system_packages.yml test/integration/targets/pip/tasks/default_cleanup.yml test/integration/targets/pip/tasks/freebsd_cleanup.yml test/integration/targets/pip/tasks/main.yml test/integration/targets/pip/tasks/no_setuptools.yml test/integration/targets/pip/tasks/pip.yml test/integration/targets/pip/vars/main.yml test/integration/targets/pkg_resources/aliases test/integration/targets/pkg_resources/lookup_plugins/check_pkg_resources.py test/integration/targets/pkg_resources/tasks/main.yml test/integration/targets/play_iterator/aliases test/integration/targets/play_iterator/playbook.yml test/integration/targets/play_iterator/runme.sh test/integration/targets/playbook/aliases test/integration/targets/playbook/empty.yml test/integration/targets/playbook/empty_hosts.yml test/integration/targets/playbook/malformed_post_tasks.yml test/integration/targets/playbook/malformed_pre_tasks.yml test/integration/targets/playbook/malformed_roles.yml test/integration/targets/playbook/malformed_tasks.yml test/integration/targets/playbook/malformed_vars_prompt.yml test/integration/targets/playbook/old_style_role.yml test/integration/targets/playbook/remote_user_and_user.yml test/integration/targets/playbook/roles_null.yml test/integration/targets/playbook/runme.sh test/integration/targets/playbook/some_vars.yml test/integration/targets/playbook/timeout.yml test/integration/targets/playbook/types.yml test/integration/targets/playbook/user.yml test/integration/targets/playbook/vars_files_null.yml test/integration/targets/playbook/vars_files_string.yml test/integration/targets/playbook/vars_prompt_null.yml test/integration/targets/playbook_output_validator/aliases test/integration/targets/playbook_output_validator/filter.py test/integration/targets/plugin_config_for_inventory/aliases test/integration/targets/plugin_config_for_inventory/config_with_parameter.yml test/integration/targets/plugin_config_for_inventory/config_without_parameter.yml test/integration/targets/plugin_config_for_inventory/test_inventory.py test/integration/targets/plugin_config_for_inventory/cache_plugins/none.py test/integration/targets/plugin_config_for_inventory/tasks/main.yml test/integration/targets/plugin_filtering/aliases test/integration/targets/plugin_filtering/copy.yml test/integration/targets/plugin_filtering/filter_lookup.ini test/integration/targets/plugin_filtering/filter_lookup.yml test/integration/targets/plugin_filtering/filter_modules.ini test/integration/targets/plugin_filtering/filter_modules.yml test/integration/targets/plugin_filtering/filter_ping.ini test/integration/targets/plugin_filtering/filter_ping.yml test/integration/targets/plugin_filtering/filter_stat.ini test/integration/targets/plugin_filtering/filter_stat.yml test/integration/targets/plugin_filtering/lookup.yml test/integration/targets/plugin_filtering/no_filters.ini test/integration/targets/plugin_filtering/no_rejectlist_module.yml test/integration/targets/plugin_filtering/pause.yml test/integration/targets/plugin_filtering/ping.yml test/integration/targets/plugin_filtering/runme.sh test/integration/targets/plugin_filtering/stat.yml test/integration/targets/plugin_filtering/tempfile.yml test/integration/targets/plugin_loader/aliases test/integration/targets/plugin_loader/runme.sh test/integration/targets/plugin_loader/use_coll_name.yml test/integration/targets/plugin_loader/file_collision/play.yml test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/custom.py test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter1.yml test/integration/targets/plugin_loader/file_collision/roles/r1/filter_plugins/filter3.yml test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/custom.py test/integration/targets/plugin_loader/file_collision/roles/r2/filter_plugins/filter2.yml test/integration/targets/plugin_loader/normal/filters.yml test/integration/targets/plugin_loader/normal/self_referential.yml test/integration/targets/plugin_loader/normal/underscore.yml test/integration/targets/plugin_loader/normal/action_plugins/self_referential.py test/integration/targets/plugin_loader/normal/library/_underscore.py test/integration/targets/plugin_loader/override/filters.yml test/integration/targets/plugin_loader/override/filter_plugins/core.py test/integration/targets/plugin_namespace/aliases test/integration/targets/plugin_namespace/filter_plugins/test_filter.py test/integration/targets/plugin_namespace/lookup_plugins/lookup_name.py test/integration/targets/plugin_namespace/tasks/main.yml test/integration/targets/plugin_namespace/test_plugins/test_test.py test/integration/targets/preflight_encoding/aliases test/integration/targets/preflight_encoding/tasks/main.yml test/integration/targets/preflight_encoding/vars/main.yml test/integration/targets/prepare_http_tests/defaults/main.yml test/integration/targets/prepare_http_tests/files/openssl_legacy.cnf test/integration/targets/prepare_http_tests/handlers/main.yml test/integration/targets/prepare_http_tests/library/httptester_kinit.py test/integration/targets/prepare_http_tests/meta/main.yml test/integration/targets/prepare_http_tests/tasks/default.yml test/integration/targets/prepare_http_tests/tasks/kerberos.yml test/integration/targets/prepare_http_tests/tasks/main.yml test/integration/targets/prepare_http_tests/tasks/windows.yml test/integration/targets/prepare_http_tests/templates/krb5.conf.j2 test/integration/targets/prepare_http_tests/vars/Alpine.yml test/integration/targets/prepare_http_tests/vars/Debian.yml test/integration/targets/prepare_http_tests/vars/FreeBSD.yml test/integration/targets/prepare_http_tests/vars/RedHat-9.yml test/integration/targets/prepare_http_tests/vars/Suse.yml test/integration/targets/prepare_http_tests/vars/default.yml test/integration/targets/prepare_http_tests/vars/httptester.yml test/integration/targets/prepare_tests/tasks/main.yml test/integration/targets/protomatter/aliases test/integration/targets/protomatter/action_plugins/transform_factory.py test/integration/targets/protomatter/lookup_plugins/emit_deprecation_warning.py test/integration/targets/protomatter/lookup_plugins/synthetic_plugin_info.py test/integration/targets/protomatter/tasks/main.yml test/integration/targets/python_module_rlimit_nofile/aliases test/integration/targets/python_module_rlimit_nofile/tasks/main.yml test/integration/targets/pyyaml/aliases test/integration/targets/pyyaml/runme.sh test/integration/targets/raw/aliases test/integration/targets/raw/runme.sh test/integration/targets/raw/runme.yml test/integration/targets/raw/meta/main.yml test/integration/targets/raw/tasks/main.yml test/integration/targets/reboot/aliases test/integration/targets/reboot/handlers/main.yml test/integration/targets/reboot/tasks/check_reboot.yml test/integration/targets/reboot/tasks/get_boot_time.yml test/integration/targets/reboot/tasks/main.yml test/integration/targets/reboot/tasks/test_invalid_parameter.yml test/integration/targets/reboot/tasks/test_invalid_test_command.yml test/integration/targets/reboot/tasks/test_molly_guard.yml test/integration/targets/reboot/tasks/test_standard_scenarios.yml test/integration/targets/reboot/vars/main.yml test/integration/targets/register/aliases test/integration/targets/register/can_register.yml test/integration/targets/register/invalid.yml test/integration/targets/register/invalid_skipped.yml test/integration/targets/register/runme.sh test/integration/targets/rel_plugin_loading/aliases test/integration/targets/rel_plugin_loading/notyaml.yml test/integration/targets/rel_plugin_loading/runme.sh test/integration/targets/rel_plugin_loading/subdir/play.yml test/integration/targets/rel_plugin_loading/subdir/inventory_plugins/notyaml.py test/integration/targets/remote_tmp/aliases test/integration/targets/remote_tmp/playbook.yml test/integration/targets/remote_tmp/runme.sh test/integration/targets/replace/aliases test/integration/targets/replace/meta/main.yml test/integration/targets/replace/tasks/main.yml test/integration/targets/result_pickle_error/aliases test/integration/targets/result_pickle_error/runme.sh test/integration/targets/result_pickle_error/runme.yml test/integration/targets/result_pickle_error/action_plugins/result_pickle_error.py test/integration/targets/result_pickle_error/tasks/main.yml test/integration/targets/roles/47023.yml test/integration/targets/roles/75240.yml test/integration/targets/roles/aliases test/integration/targets/roles/allowed_dupes.yml test/integration/targets/roles/data_integrity.yml test/integration/targets/roles/dupe_inheritance.yml test/integration/targets/roles/end_role.yml test/integration/targets/roles/end_role_handler_error.yml test/integration/targets/roles/end_role_nested.yml test/integration/targets/roles/no_dupes.yml test/integration/targets/roles/no_outside.yml test/integration/targets/roles/no_outside_import.yml test/integration/targets/roles/privacy.yml test/integration/targets/roles/role_complete.yml test/integration/targets/roles/role_dep_chain.yml test/integration/targets/roles/runme.sh test/integration/targets/roles/test_subdirs.yml test/integration/targets/roles/vars_scope.yml test/integration/targets/roles/roles/47023_role1/defaults/main.yml test/integration/targets/roles/roles/47023_role1/tasks/main.yml test/integration/targets/roles/roles/47023_role1/vars/main.yml test/integration/targets/roles/roles/47023_role2/tasks/main.yml test/integration/targets/roles/roles/47023_role3/tasks/main.yml test/integration/targets/roles/roles/47023_role4/tasks/main.yml test/integration/targets/roles/roles/a/tasks/main.yml test/integration/targets/roles/roles/a/tasks/subdir/entrypoint.yml test/integration/targets/roles/roles/a/vars/main.yml test/integration/targets/roles/roles/b/meta/main.yml test/integration/targets/roles/roles/b/tasks/main.yml test/integration/targets/roles/roles/bottom/tasks/main.yml test/integration/targets/roles/roles/c/meta/main.yml test/integration/targets/roles/roles/c/tasks/main.yml test/integration/targets/roles/roles/data/defaults/main/00.yml test/integration/targets/roles/roles/data/defaults/main/01.yml test/integration/targets/roles/roles/data/tasks/main.yml test/integration/targets/roles/roles/end_role_inside/handlers/main.yml test/integration/targets/roles/roles/end_role_inside/tasks/main.yml test/integration/targets/roles/roles/end_role_inside/tasks/nested.yml test/integration/targets/roles/roles/end_role_inside_nested/tasks/import_tasks.yml test/integration/targets/roles/roles/end_role_inside_nested/tasks/include_tasks.yml test/integration/targets/roles/roles/end_role_inside_nested/tasks/main.yml test/integration/targets/roles/roles/error_handler/tasks/main.yml test/integration/targets/roles/roles/failed_when/tasks/main.yml test/integration/targets/roles/roles/imported_from_include/tasks/main.yml test/integration/targets/roles/roles/include_import_dep_chain/defaults/main.yml test/integration/targets/roles/roles/include_import_dep_chain/tasks/main.yml test/integration/targets/roles/roles/include_import_dep_chain/vars/main.yml test/integration/targets/roles/roles/middle/tasks/main.yml test/integration/targets/roles/roles/recover/tasks/main.yml test/integration/targets/roles/roles/set_var/tasks/main.yml test/integration/targets/roles/roles/test_connectivity/tasks/main.yml test/integration/targets/roles/roles/top/tasks/main.yml test/integration/targets/roles/roles/vars_scope/defaults/main.yml test/integration/targets/roles/roles/vars_scope/tasks/check_vars.yml test/integration/targets/roles/roles/vars_scope/tasks/main.yml test/integration/targets/roles/roles/vars_scope/vars/main.yml test/integration/targets/roles/tasks/check_vars.yml test/integration/targets/roles/tasks/dummy.yml test/integration/targets/roles/vars/play.yml test/integration/targets/roles/vars/privacy_vars.yml test/integration/targets/roles_arg_spec/aliases test/integration/targets/roles_arg_spec/runme.sh test/integration/targets/roles_arg_spec/test.yml test/integration/targets/roles_arg_spec/test_complex_role_fails.yml test/integration/targets/roles_arg_spec/test_play_level_role_fails.yml test/integration/targets/roles_arg_spec/test_tags.yml test/integration/targets/roles_arg_spec/collections/ansible_collections/foo/bar/MANIFEST.json test/integration/targets/roles_arg_spec/collections/ansible_collections/foo/bar/roles/blah/meta/argument_specs.yml test/integration/targets/roles_arg_spec/collections/ansible_collections/foo/bar/roles/blah/tasks/main.yml test/integration/targets/roles_arg_spec/roles/a/meta/argument_specs.yml test/integration/targets/roles_arg_spec/roles/a/meta/main.yml test/integration/targets/roles_arg_spec/roles/a/tasks/alternate.yml test/integration/targets/roles_arg_spec/roles/a/tasks/main.yml test/integration/targets/roles_arg_spec/roles/a/tasks/no_spec_entrypoint.yml test/integration/targets/roles_arg_spec/roles/b/meta/argument_specs.yaml test/integration/targets/roles_arg_spec/roles/b/tasks/main.yml test/integration/targets/roles_arg_spec/roles/c/meta/main.yml test/integration/targets/roles_arg_spec/roles/c/tasks/main.yml test/integration/targets/roles_arg_spec/roles/empty_argspec/meta/argument_specs.yml test/integration/targets/roles_arg_spec/roles/empty_argspec/tasks/main.yml test/integration/targets/roles_arg_spec/roles/empty_file/meta/argument_specs.yml test/integration/targets/roles_arg_spec/roles/empty_file/tasks/main.yml test/integration/targets/roles_arg_spec/roles/role_with_no_tasks/meta/argument_specs.yml test/integration/targets/roles_arg_spec/roles/test1/defaults/main.yml test/integration/targets/roles_arg_spec/roles/test1/meta/argument_specs.yml test/integration/targets/roles_arg_spec/roles/test1/tasks/main.yml test/integration/targets/roles_arg_spec/roles/test1/tasks/other.yml test/integration/targets/roles_arg_spec/roles/test1/tasks/test1_other.yml test/integration/targets/roles_arg_spec/roles/test1/vars/main.yml test/integration/targets/roles_arg_spec/roles/test1/vars/other.yml test/integration/targets/roles_var_inheritance/aliases test/integration/targets/roles_var_inheritance/play.yml test/integration/targets/roles_var_inheritance/runme.sh test/integration/targets/roles_var_inheritance/roles/A/meta/main.yml test/integration/targets/roles_var_inheritance/roles/B/meta/main.yml test/integration/targets/roles_var_inheritance/roles/child_nested_dep/vars/main.yml test/integration/targets/roles_var_inheritance/roles/common_dep/meta/main.yml test/integration/targets/roles_var_inheritance/roles/common_dep/vars/main.yml test/integration/targets/roles_var_inheritance/roles/nested_dep/meta/main.yml test/integration/targets/roles_var_inheritance/roles/nested_dep/tasks/main.yml test/integration/targets/rpm_key/aliases test/integration/targets/rpm_key/meta/main.yml test/integration/targets/rpm_key/tasks/main.yaml test/integration/targets/rpm_key/tasks/rpm_key.yaml test/integration/targets/rpm_key/vars/main.yml test/integration/targets/run_modules/aliases test/integration/targets/run_modules/args.json test/integration/targets/run_modules/run_raw_args.yml test/integration/targets/run_modules/runme.sh test/integration/targets/run_modules/library/test.py test/integration/targets/script/aliases test/integration/targets/script/files/create_afile.sh test/integration/targets/script/files/no_shebang.py test/integration/targets/script/files/remove_afile.sh test/integration/targets/script/files/test.sh test/integration/targets/script/files/test_with_args.sh test/integration/targets/script/files/space path/test.sh test/integration/targets/script/meta/main.yml test/integration/targets/script/tasks/main.yml test/integration/targets/service/aliases test/integration/targets/service/files/ansible-broken.upstart test/integration/targets/service/files/ansible.rc test/integration/targets/service/files/ansible.systemd test/integration/targets/service/files/ansible.sysv test/integration/targets/service/files/ansible.upstart test/integration/targets/service/files/ansible_test_service.py test/integration/targets/service/meta/main.yml test/integration/targets/service/tasks/main.yml test/integration/targets/service/tasks/rc_cleanup.yml test/integration/targets/service/tasks/rc_setup.yml test/integration/targets/service/tasks/systemd_cleanup.yml test/integration/targets/service/tasks/systemd_setup.yml test/integration/targets/service/tasks/sysv_cleanup.yml test/integration/targets/service/tasks/sysv_setup.yml test/integration/targets/service/tasks/tests.yml test/integration/targets/service/tasks/upstart_cleanup.yml test/integration/targets/service/tasks/upstart_setup.yml test/integration/targets/service/templates/main.yml test/integration/targets/service_facts/aliases test/integration/targets/service_facts/files/ansible.systemd test/integration/targets/service_facts/files/ansible_test_service.py test/integration/targets/service_facts/handlers/main.yml test/integration/targets/service_facts/tasks/main.yml test/integration/targets/service_facts/tasks/systemd_cleanup.yml test/integration/targets/service_facts/tasks/systemd_setup.yml test/integration/targets/service_facts/tasks/tests.yml test/integration/targets/set_fact/aliases test/integration/targets/set_fact/incremental.yml test/integration/targets/set_fact/inventory test/integration/targets/set_fact/nowarn_clean_facts.yml test/integration/targets/set_fact/runme.sh test/integration/targets/set_fact/set_fact.yml test/integration/targets/set_fact/set_fact_ansible_vars.yml test/integration/targets/set_fact/set_fact_auto_unsafe.yml test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml test/integration/targets/set_fact/set_fact_cached_1.yml test/integration/targets/set_fact/set_fact_cached_2.yml test/integration/targets/set_fact/set_fact_empty_str_key.yml test/integration/targets/set_fact/set_fact_no_cache.yml test/integration/targets/set_stats/aliases test/integration/targets/set_stats/runme.sh test/integration/targets/set_stats/test_aggregate.yml test/integration/targets/set_stats/test_simple.yml test/integration/targets/setup_become_user_pair/defaults/main.yml test/integration/targets/setup_become_user_pair/tasks/main.yml test/integration/targets/setup_cron/defaults/main.yml test/integration/targets/setup_cron/meta/main.yml test/integration/targets/setup_cron/tasks/main.yml test/integration/targets/setup_cron/vars/alpine.yml test/integration/targets/setup_cron/vars/debian.yml test/integration/targets/setup_cron/vars/default.yml test/integration/targets/setup_cron/vars/fedora.yml test/integration/targets/setup_cron/vars/freebsd.yml test/integration/targets/setup_cron/vars/redhat.yml test/integration/targets/setup_cron/vars/suse.yml test/integration/targets/setup_deb_repo/files/package_specs/stable/baz-1.0.0 test/integration/targets/setup_deb_repo/files/package_specs/stable/foo-1.0.0 test/integration/targets/setup_deb_repo/files/package_specs/stable/foo-1.0.1 test/integration/targets/setup_deb_repo/files/package_specs/stable/foobar-1.0.0 test/integration/targets/setup_deb_repo/files/package_specs/stable/foobar-1.0.1 test/integration/targets/setup_deb_repo/files/package_specs/testing/foo-2.0.0 test/integration/targets/setup_deb_repo/files/package_specs/testing/foo-2.0.1 test/integration/targets/setup_deb_repo/meta/main.yml test/integration/targets/setup_deb_repo/tasks/main.yml test/integration/targets/setup_gnutar/handlers/main.yml test/integration/targets/setup_gnutar/tasks/main.yml test/integration/targets/setup_nobody/handlers/main.yml test/integration/targets/setup_nobody/tasks/main.yml test/integration/targets/setup_paramiko/aliases test/integration/targets/setup_paramiko/constraints.txt test/integration/targets/setup_paramiko/install-Alpine-3-python-3.yml test/integration/targets/setup_paramiko/install-Darwin-python-3.yml test/integration/targets/setup_paramiko/install-FreeBSD-python-3.yml test/integration/targets/setup_paramiko/install-RedHat-10-python-3.yml test/integration/targets/setup_paramiko/install-RedHat-9-python-3.yml test/integration/targets/setup_paramiko/install-fail.yml test/integration/targets/setup_paramiko/install-python-3.yml test/integration/targets/setup_paramiko/install.yml test/integration/targets/setup_paramiko/inventory test/integration/targets/setup_paramiko/setup-remote-constraints.yml test/integration/targets/setup_paramiko/setup.sh test/integration/targets/setup_paramiko/uninstall-Alpine-3-python-3.yml test/integration/targets/setup_paramiko/uninstall-Darwin-python-3.yml test/integration/targets/setup_paramiko/uninstall-FreeBSD-python-3.yml test/integration/targets/setup_paramiko/uninstall-RedHat-10-python-3.yml test/integration/targets/setup_paramiko/uninstall-RedHat-9-python-3.yml test/integration/targets/setup_paramiko/uninstall-apt-python-3.yml test/integration/targets/setup_paramiko/uninstall-dnf.yml test/integration/targets/setup_paramiko/uninstall-dnf5.yml test/integration/targets/setup_paramiko/uninstall-fail.yml test/integration/targets/setup_paramiko/uninstall-yum.yml test/integration/targets/setup_paramiko/uninstall.yml test/integration/targets/setup_paramiko/library/detect_paramiko.py test/integration/targets/setup_passlib/tasks/main.yml test/integration/targets/setup_passlib_controller/runme.sh test/integration/targets/setup_pexpect/files/constraints.txt test/integration/targets/setup_pexpect/meta/main.yml test/integration/targets/setup_pexpect/tasks/main.yml test/integration/targets/setup_remote_constraints/aliases test/integration/targets/setup_remote_constraints/meta/main.yml test/integration/targets/setup_remote_constraints/tasks/main.yml test/integration/targets/setup_remote_tmp_dir/defaults/main.yml test/integration/targets/setup_remote_tmp_dir/handlers/main.yml test/integration/targets/setup_remote_tmp_dir/tasks/default-cleanup.yml test/integration/targets/setup_remote_tmp_dir/tasks/default.yml test/integration/targets/setup_remote_tmp_dir/tasks/main.yml test/integration/targets/setup_remote_tmp_dir/tasks/windows-cleanup.yml test/integration/targets/setup_remote_tmp_dir/tasks/windows.yml test/integration/targets/setup_rpm_repo/defaults/main.yml test/integration/targets/setup_rpm_repo/files/comps.xml test/integration/targets/setup_rpm_repo/handlers/main.yml test/integration/targets/setup_rpm_repo/library/create_repo.py test/integration/targets/setup_rpm_repo/meta/main.yml test/integration/targets/setup_rpm_repo/tasks/main.yml test/integration/targets/setup_test_user/defaults/main.yml test/integration/targets/setup_test_user/handlers/main.yml test/integration/targets/setup_test_user/tasks/default.yml test/integration/targets/setup_test_user/tasks/macosx.yml test/integration/targets/setup_test_user/tasks/main.yml test/integration/targets/setup_test_user/tasks/sudo_config.yml test/integration/targets/setup_win_printargv/files/PrintArgv.cs test/integration/targets/setup_win_printargv/meta/main.yml test/integration/targets/setup_win_printargv/tasks/main.yml test/integration/targets/shell/aliases test/integration/targets/shell/test-command-building-playbook.yml test/integration/targets/shell/action_plugins/test_shell.py test/integration/targets/shell/connection_plugins/test_connection_default.py test/integration/targets/shell/connection_plugins/test_connection_override.py test/integration/targets/shell/meta/main.yml test/integration/targets/shell/tasks/command-building.yml test/integration/targets/shell/tasks/main.yml test/integration/targets/slurp/aliases test/integration/targets/slurp/files/bar.bin test/integration/targets/slurp/meta/main.yml test/integration/targets/slurp/tasks/main.yml test/integration/targets/slurp/tasks/test_unreadable.yml test/integration/targets/special_vars/aliases test/integration/targets/special_vars/meta/main.yml test/integration/targets/special_vars/tasks/main.yml test/integration/targets/special_vars/templates/foo.j2 test/integration/targets/special_vars/vars/main.yml test/integration/targets/special_vars_hosts/aliases test/integration/targets/special_vars_hosts/inventory test/integration/targets/special_vars_hosts/playbook.yml test/integration/targets/special_vars_hosts/runme.sh test/integration/targets/split/aliases test/integration/targets/split/tasks/main.yml test/integration/targets/ssh_agent/aliases test/integration/targets/ssh_agent/auto.yml test/integration/targets/ssh_agent/test_key.yml test/integration/targets/ssh_agent/action_plugins/ssh_agent.py test/integration/targets/ssh_agent/action_plugins/ssh_keygen.py test/integration/targets/ssh_agent/fake_agents/ssh-agent-bad-shebang test/integration/targets/ssh_agent/fake_agents/ssh-agent-hangs test/integration/targets/ssh_agent/fake_agents/ssh-agent-incompatible test/integration/targets/ssh_agent/fake_agents/ssh-agent-truncated-early-exit test/integration/targets/ssh_agent/tasks/main.yml test/integration/targets/ssh_agent/tasks/tests.yml test/integration/targets/stat/aliases test/integration/targets/stat/files/foo.txt test/integration/targets/stat/meta/main.yml test/integration/targets/stat/tasks/main.yml test/integration/targets/strategy-external/aliases test/integration/targets/strategy-external/runme.sh test/integration/targets/strategy-external/ansible_collections/ns/col/plugins/strategy/external.py test/integration/targets/strategy_free/aliases test/integration/targets/strategy_free/inventory test/integration/targets/strategy_free/last_include_tasks.yml test/integration/targets/strategy_free/runme.sh test/integration/targets/strategy_free/test_last_include_in_always.yml test/integration/targets/strategy_host_pinned/aliases test/integration/targets/strategy_host_pinned/hosts test/integration/targets/strategy_host_pinned/playbook.yml test/integration/targets/strategy_host_pinned/runme.sh test/integration/targets/strategy_host_pinned/callback_plugins/callback_host_count.py test/integration/targets/strategy_linear/aliases test/integration/targets/strategy_linear/inventory test/integration/targets/strategy_linear/runme.sh test/integration/targets/strategy_linear/task_action_templating.yml test/integration/targets/strategy_linear/task_templated_run_once.yml test/integration/targets/strategy_linear/test_include_file_noop.yml test/integration/targets/strategy_linear/roles/role1/tasks/main.yml test/integration/targets/strategy_linear/roles/role1/tasks/tasks.yml test/integration/targets/strategy_linear/roles/role2/tasks/main.yml test/integration/targets/subversion/aliases test/integration/targets/subversion/runme.sh test/integration/targets/subversion/runme.yml test/integration/targets/subversion/roles/subversion/defaults/main.yml test/integration/targets/subversion/roles/subversion/files/create_repo.sh test/integration/targets/subversion/roles/subversion/tasks/cleanup.yml test/integration/targets/subversion/roles/subversion/tasks/main.yml test/integration/targets/subversion/roles/subversion/tasks/setup.yml test/integration/targets/subversion/roles/subversion/tasks/tests.yml test/integration/targets/subversion/roles/subversion/tasks/warnings.yml test/integration/targets/subversion/roles/subversion/templates/subversion.conf.j2 test/integration/targets/subversion/vars/Alpine.yml test/integration/targets/subversion/vars/Debian.yml test/integration/targets/subversion/vars/FreeBSD.yml test/integration/targets/subversion/vars/RedHat.yml test/integration/targets/support-callback_plugins/aliases test/integration/targets/support-callback_plugins/callback_plugins/callback_debug.py test/integration/targets/systemd/aliases test/integration/targets/systemd/defaults/main.yml test/integration/targets/systemd/handlers/main.yml test/integration/targets/systemd/meta/main.yml test/integration/targets/systemd/tasks/main.yml test/integration/targets/systemd/tasks/test_enabled_runtime.yml test/integration/targets/systemd/tasks/test_indirect_service.yml test/integration/targets/systemd/tasks/test_mask.yml test/integration/targets/systemd/tasks/test_systemd_version.yml test/integration/targets/systemd/tasks/test_unit_template.yml test/integration/targets/systemd/templates/baz.service test/integration/targets/systemd/templates/dummy.service test/integration/targets/systemd/templates/dummy.socket test/integration/targets/systemd/templates/mask_me.service test/integration/targets/systemd/templates/sleeper@.service test/integration/targets/systemd/vars/Debian.yml test/integration/targets/systemd/vars/default.yml test/integration/targets/tags/aliases test/integration/targets/tags/ansible_run_tags.yml test/integration/targets/tags/runme.sh test/integration/targets/tags/test_tags.yml test/integration/targets/tags/test_template_parent_tags.yml test/integration/targets/task-args/aliases test/integration/targets/task-args/action_plugins/echo.py test/integration/targets/task-args/action_plugins/echo_raw.py test/integration/targets/task-args/tasks/main.yml test/integration/targets/task-timeout/aliases test/integration/targets/task-timeout/tasks/main.yml test/integration/targets/task_ordering/aliases test/integration/targets/task_ordering/meta/main.yml test/integration/targets/task_ordering/tasks/main.yml test/integration/targets/task_ordering/tasks/taskorder-include.yml test/integration/targets/tasks/aliases test/integration/targets/tasks/playbook.yml test/integration/targets/tasks/runme.sh test/integration/targets/tasks/action_plugins/action_that_fails.py test/integration/targets/tempfile/aliases test/integration/targets/tempfile/meta/main.yml test/integration/targets/tempfile/tasks/main.yml test/integration/targets/template/6653.yml test/integration/targets/template/72262.yml test/integration/targets/template/72615.yml test/integration/targets/template/aliases test/integration/targets/template/ansible_managed.cfg test/integration/targets/template/ansible_managed.yml test/integration/targets/template/ansible_managed_templated.cfg test/integration/targets/template/arg_template_overrides.j2 test/integration/targets/template/badnull1.cfg test/integration/targets/template/badnull2.cfg test/integration/targets/template/badnull3.cfg test/integration/targets/template/corner_cases.yml test/integration/targets/template/custom_template.yml test/integration/targets/template/filter_plugins.yml test/integration/targets/template/in_template_overrides.j2 test/integration/targets/template/lazy_eval.yml test/integration/targets/template/runme.sh test/integration/targets/template/template.yml test/integration/targets/template/template_overrides.yml test/integration/targets/template/undefined_in_import-import.j2 test/integration/targets/template/undefined_in_import.j2 test/integration/targets/template/undefined_in_import.yml test/integration/targets/template/undefined_var_info.yml test/integration/targets/template/unsafe.yml test/integration/targets/template/unused_vars_include.yml test/integration/targets/template/custom_tasks/tasks/main.yml test/integration/targets/template/custom_tasks/templates/test test/integration/targets/template/files/custom_comment_string.expected test/integration/targets/template/files/encoding_1252_utf-8.expected test/integration/targets/template/files/encoding_1252_windows-1252.expected test/integration/targets/template/files/foo-py26.txt test/integration/targets/template/files/foo.dos.txt test/integration/targets/template/files/foo.txt test/integration/targets/template/files/foo.unix.txt test/integration/targets/template/files/import_as.expected test/integration/targets/template/files/import_as_with_context.expected test/integration/targets/template/files/import_with_context.expected test/integration/targets/template/files/lstrip_blocks_false.expected test/integration/targets/template/files/lstrip_blocks_true.expected test/integration/targets/template/files/override_colon_value.expected test/integration/targets/template/files/string_type_filters.expected test/integration/targets/template/files/trim_blocks_false.expected test/integration/targets/template/files/trim_blocks_true.expected test/integration/targets/template/meta/main.yml test/integration/targets/template/role_filter/filter_plugins/myplugin.py test/integration/targets/template/role_filter/tasks/main.yml test/integration/targets/template/tasks/backup_test.yml test/integration/targets/template/tasks/main.yml test/integration/targets/template/templates/%necho Onii-chan help Im stuck;exit 1%n.j2 test/integration/targets/template/templates/6653-include.j2 test/integration/targets/template/templates/6653.j2 test/integration/targets/template/templates/72262-included.j2 test/integration/targets/template/templates/72262-vars.j2 test/integration/targets/template/templates/72262.j2 test/integration/targets/template/templates/72615-macro-nested.j2 test/integration/targets/template/templates/72615-macro.j2 test/integration/targets/template/templates/72615.j2 test/integration/targets/template/templates/bar test/integration/targets/template/templates/café.j2 test/integration/targets/template/templates/completely{{ 1 % 0 }} safe template.j2 test/integration/targets/template/templates/custom_comment_string.j2 test/integration/targets/template/templates/empty_template.j2 test/integration/targets/template/templates/encoding_1252.j2 test/integration/targets/template/templates/foo.j2 test/integration/targets/template/templates/foo2.j2 test/integration/targets/template/templates/foo3.j2 test/integration/targets/template/templates/for_loop.j2 test/integration/targets/template/templates/for_loop_include.j2 test/integration/targets/template/templates/for_loop_include_nested.j2 test/integration/targets/template/templates/import_as.j2 test/integration/targets/template/templates/import_as_with_context.j2 test/integration/targets/template/templates/import_with_context.j2 test/integration/targets/template/templates/indirect_dict.j2 test/integration/targets/template/templates/json_macro.j2 test/integration/targets/template/templates/lstrip_blocks.j2 test/integration/targets/template/templates/macro_using_globals.j2 test/integration/targets/template/templates/none.j2 test/integration/targets/template/templates/override_colon_value.j2 test/integration/targets/template/templates/override_separator.j2 test/integration/targets/template/templates/parent.j2 test/integration/targets/template/templates/qux test/integration/targets/template/templates/short.j2 test/integration/targets/template/templates/subtemplate.j2 test/integration/targets/template/templates/template_destpath_test.j2 test/integration/targets/template/templates/template_import_macro_globals.j2 test/integration/targets/template/templates/trim_blocks.j2 test/integration/targets/template/templates/unused_vars_include.j2 test/integration/targets/template/templates/unused_vars_template.j2 test/integration/targets/template/vars/main.yml test/integration/targets/template_jinja2_non_native/46169.yml test/integration/targets/template_jinja2_non_native/aliases test/integration/targets/template_jinja2_non_native/macro_override.yml test/integration/targets/template_jinja2_non_native/runme.sh test/integration/targets/template_jinja2_non_native/templates/46169.json.j2 test/integration/targets/template_jinja2_non_native/templates/macro_override.j2 test/integration/targets/templating/aliases test/integration/targets/templating/filter_plugins/broken_filter.py test/integration/targets/templating/library/noisy.py test/integration/targets/templating/lookup_plugins/broken.py test/integration/targets/templating/tasks/main.yml test/integration/targets/templating/tasks/plugin_errors.yml test/integration/targets/templating/test_plugins/broken_test.py test/integration/targets/templating_lookup_args/aliases test/integration/targets/templating_lookup_args/runme.sh test/integration/targets/templating_lookup_args/test.yml test/integration/targets/templating_lookup_args/lookup_plugins/accept_args_markers.py test/integration/targets/templating_lookup_args/lookup_plugins/accept_no_markers.py test/integration/targets/templating_lookups/aliases test/integration/targets/templating_lookups/runme.sh test/integration/targets/templating_lookups/runme.yml test/integration/targets/templating_lookups/template_deepcopy/hosts test/integration/targets/templating_lookups/template_deepcopy/playbook.yml test/integration/targets/templating_lookups/template_deepcopy/template.in test/integration/targets/templating_lookups/template_lookup_vaulted/playbook.yml test/integration/targets/templating_lookups/template_lookup_vaulted/test_vault_pass test/integration/targets/templating_lookups/template_lookup_vaulted/templates/vaulted_hello.j2 test/integration/targets/templating_lookups/template_lookups/tasks/errors.yml test/integration/targets/templating_lookups/template_lookups/tasks/main.yml test/integration/targets/templating_lookups/template_lookups/vars/main.yml test/integration/targets/templating_settings/aliases test/integration/targets/templating_settings/dont_warn_register.yml test/integration/targets/templating_settings/runme.sh test/integration/targets/templating_settings/test_templating_settings.yml test/integration/targets/test_core/aliases test/integration/targets/test_core/inventory test/integration/targets/test_core/runme.sh test/integration/targets/test_core/runme.yml test/integration/targets/test_core/vault-password test/integration/targets/test_core/files/notvault test/integration/targets/test_core/files/vault1 test/integration/targets/test_core/files/vault2 test/integration/targets/test_core/tasks/main.yml test/integration/targets/test_files/aliases test/integration/targets/test_files/tasks/main.yml test/integration/targets/test_mathstuff/aliases test/integration/targets/test_mathstuff/tasks/main.yml test/integration/targets/test_uri/aliases test/integration/targets/test_uri/tasks/main.yml test/integration/targets/test_utils/aliases test/integration/targets/test_utils/scripts/timeout.py test/integration/targets/throttle/aliases test/integration/targets/throttle/inventory test/integration/targets/throttle/non_integer_throttle.yml test/integration/targets/throttle/runme.sh test/integration/targets/throttle/test_throttle.py test/integration/targets/throttle/test_throttle.yml test/integration/targets/throttle/undefined_throttle.yml test/integration/targets/throttle/group_vars/all.yml test/integration/targets/unarchive/aliases test/integration/targets/unarchive/runme.sh test/integration/targets/unarchive/runme.yml test/integration/targets/unarchive/test_relative_tmp_dir.yml test/integration/targets/unarchive/files/content_differs.tar.gz test/integration/targets/unarchive/files/content_differs_2.tar.gz test/integration/targets/unarchive/files/foo.txt test/integration/targets/unarchive/files/size_differs.tar.gz test/integration/targets/unarchive/files/size_differs_2.tar.gz test/integration/targets/unarchive/files/test-unarchive-nonascii-くらとみ.tar.gz test/integration/targets/unarchive/handlers/main.yml test/integration/targets/unarchive/meta/main.yml test/integration/targets/unarchive/tasks/main.yml test/integration/targets/unarchive/tasks/prepare_tests.yml test/integration/targets/unarchive/tasks/test_different_language_var.yml test/integration/targets/unarchive/tasks/test_download.yml test/integration/targets/unarchive/tasks/test_exclude.yml test/integration/targets/unarchive/tasks/test_include.yml test/integration/targets/unarchive/tasks/test_invalid_options.yml test/integration/targets/unarchive/tasks/test_missing_binaries.yml test/integration/targets/unarchive/tasks/test_missing_files.yml test/integration/targets/unarchive/tasks/test_mode.yml test/integration/targets/unarchive/tasks/test_non_ascii_filename.yml test/integration/targets/unarchive/tasks/test_owner_group.yml test/integration/targets/unarchive/tasks/test_ownership_top_folder.yml test/integration/targets/unarchive/tasks/test_parent_not_writeable.yml test/integration/targets/unarchive/tasks/test_quotable_characters.yml test/integration/targets/unarchive/tasks/test_relative_dest.yml test/integration/targets/unarchive/tasks/test_symlink.yml test/integration/targets/unarchive/tasks/test_tar.yml test/integration/targets/unarchive/tasks/test_tar_gz.yml test/integration/targets/unarchive/tasks/test_tar_gz_content_differs.yml test/integration/targets/unarchive/tasks/test_tar_gz_creates.yml test/integration/targets/unarchive/tasks/test_tar_gz_keep_newer.yml test/integration/targets/unarchive/tasks/test_tar_gz_owner_group.yml test/integration/targets/unarchive/tasks/test_tar_gz_size_differs.yml test/integration/targets/unarchive/tasks/test_tar_zst.yml test/integration/targets/unarchive/tasks/test_unprivileged_user.yml test/integration/targets/unarchive/tasks/test_zip.yml test/integration/targets/unarchive/vars/Darwin.yml test/integration/targets/unarchive/vars/FreeBSD.yml test/integration/targets/unarchive/vars/Linux.yml test/integration/targets/undefined/aliases test/integration/targets/undefined/tasks/main.yml test/integration/targets/unexpected_executor_exception/aliases test/integration/targets/unexpected_executor_exception/action_plugins/unexpected.py test/integration/targets/unexpected_executor_exception/tasks/main.yml test/integration/targets/unicode/aliases test/integration/targets/unicode/inventory test/integration/targets/unicode/runme.sh test/integration/targets/unicode/unicode-test-script test/integration/targets/unicode/unicode.yml test/integration/targets/unicode/křížek-ansible-project/ansible.cfg test/integration/targets/unsafe_writes/aliases test/integration/targets/unsafe_writes/basic.yml test/integration/targets/unsafe_writes/runme.sh test/integration/targets/until/aliases test/integration/targets/until/action_plugins/shell_no_failed.py test/integration/targets/until/tasks/main.yml test/integration/targets/unvault/aliases test/integration/targets/unvault/main.yml test/integration/targets/unvault/password test/integration/targets/unvault/runme.sh test/integration/targets/unvault/vault test/integration/targets/uri/aliases test/integration/targets/uri/files/README test/integration/targets/uri/files/fail0.json test/integration/targets/uri/files/fail1.json test/integration/targets/uri/files/fail10.json test/integration/targets/uri/files/fail11.json test/integration/targets/uri/files/fail12.json test/integration/targets/uri/files/fail13.json test/integration/targets/uri/files/fail14.json test/integration/targets/uri/files/fail15.json test/integration/targets/uri/files/fail16.json test/integration/targets/uri/files/fail17.json test/integration/targets/uri/files/fail18.json test/integration/targets/uri/files/fail19.json test/integration/targets/uri/files/fail2.json test/integration/targets/uri/files/fail20.json test/integration/targets/uri/files/fail21.json test/integration/targets/uri/files/fail22.json test/integration/targets/uri/files/fail23.json test/integration/targets/uri/files/fail24.json test/integration/targets/uri/files/fail25.json test/integration/targets/uri/files/fail26.json test/integration/targets/uri/files/fail27.json test/integration/targets/uri/files/fail28.json test/integration/targets/uri/files/fail29.json test/integration/targets/uri/files/fail3.json test/integration/targets/uri/files/fail30.json test/integration/targets/uri/files/fail4.json test/integration/targets/uri/files/fail5.json test/integration/targets/uri/files/fail6.json test/integration/targets/uri/files/fail7.json test/integration/targets/uri/files/fail8.json test/integration/targets/uri/files/fail9.json test/integration/targets/uri/files/formdata.txt test/integration/targets/uri/files/pass0.json test/integration/targets/uri/files/pass1.json test/integration/targets/uri/files/pass2.json test/integration/targets/uri/files/pass3.json test/integration/targets/uri/files/pass4.json test/integration/targets/uri/files/testserver.py test/integration/targets/uri/meta/main.yml test/integration/targets/uri/tasks/ciphers.yml test/integration/targets/uri/tasks/install-socat-and-test-unix-socket.yml test/integration/targets/uri/tasks/main.yml test/integration/targets/uri/tasks/redirect-all.yml test/integration/targets/uri/tasks/redirect-none.yml test/integration/targets/uri/tasks/redirect-safe.yml test/integration/targets/uri/tasks/redirect-urllib2.yml test/integration/targets/uri/tasks/return-content.yml test/integration/targets/uri/tasks/unexpected-failures.yml test/integration/targets/uri/tasks/unix-socket.yml test/integration/targets/uri/tasks/use_gssapi.yml test/integration/targets/uri/tasks/use_netrc.yml test/integration/targets/uri/templates/netrc.j2 test/integration/targets/user/aliases test/integration/targets/user/files/userlist.sh test/integration/targets/user/files/skel/.ssh/known_hosts test/integration/targets/user/meta/main.yml test/integration/targets/user/tasks/main.yml test/integration/targets/user/tasks/ssh_keygen.yml test/integration/targets/user/tasks/test_create_system_user.yml test/integration/targets/user/tasks/test_create_user.yml test/integration/targets/user/tasks/test_create_user_home.yml test/integration/targets/user/tasks/test_create_user_min_max.yml test/integration/targets/user/tasks/test_create_user_password.yml test/integration/targets/user/tasks/test_create_user_uid.yml test/integration/targets/user/tasks/test_expires.yml test/integration/targets/user/tasks/test_expires_min_max.yml test/integration/targets/user/tasks/test_expires_new_account.yml test/integration/targets/user/tasks/test_expires_new_account_epoch_negative.yml test/integration/targets/user/tasks/test_expires_no_shadow.yml test/integration/targets/user/tasks/test_expires_warn.yml test/integration/targets/user/tasks/test_inactive_new_account.yml test/integration/targets/user/tasks/test_local.yml test/integration/targets/user/tasks/test_local_expires.yml test/integration/targets/user/tasks/test_no_home_fallback.yml test/integration/targets/user/tasks/test_password_lock.yml test/integration/targets/user/tasks/test_password_lock_new_user.yml test/integration/targets/user/tasks/test_remove_user.yml test/integration/targets/user/tasks/test_ssh_key_passphrase.yml test/integration/targets/user/tasks/test_umask.yml test/integration/targets/user/vars/main.yml test/integration/targets/var_blending/aliases test/integration/targets/var_blending/inventory test/integration/targets/var_blending/runme.sh test/integration/targets/var_blending/test_var_blending.yml test/integration/targets/var_blending/test_vars.yml test/integration/targets/var_blending/vars_file.yml test/integration/targets/var_blending/group_vars/all test/integration/targets/var_blending/group_vars/local test/integration/targets/var_blending/host_vars/testhost test/integration/targets/var_blending/roles/test_var_blending/defaults/main.yml test/integration/targets/var_blending/roles/test_var_blending/files/foo.txt test/integration/targets/var_blending/roles/test_var_blending/tasks/main.yml test/integration/targets/var_blending/roles/test_var_blending/templates/foo.j2 test/integration/targets/var_blending/roles/test_var_blending/vars/main.yml test/integration/targets/var_blending/roles/test_var_blending/vars/more_vars.yml test/integration/targets/var_inheritance/aliases test/integration/targets/var_inheritance/tasks/main.yml test/integration/targets/var_precedence/aliases test/integration/targets/var_precedence/ansible-var-precedence-check.py test/integration/targets/var_precedence/inventory test/integration/targets/var_precedence/runme.sh test/integration/targets/var_precedence/test_var_precedence.yml test/integration/targets/var_precedence/host_vars/testhost test/integration/targets/var_precedence/roles/test_var_precedence/meta/main.yml test/integration/targets/var_precedence/roles/test_var_precedence/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_dep/defaults/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_dep/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_dep/vars/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_inven_override/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role1/defaults/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role1/meta/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role1/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role1/vars/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role2/defaults/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role2/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role2/vars/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role3/defaults/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role3/tasks/main.yml test/integration/targets/var_precedence/roles/test_var_precedence_role3/vars/main.yml test/integration/targets/var_precedence/vars/test_var_precedence.yml test/integration/targets/var_reserved/aliases test/integration/targets/var_reserved/tasks/block_vars.yml test/integration/targets/var_reserved/tasks/include_vars.yml test/integration/targets/var_reserved/tasks/main.yml test/integration/targets/var_reserved/tasks/play_vars.yml test/integration/targets/var_reserved/tasks/set_fact.yml test/integration/targets/var_reserved/tasks/task_vars.yml test/integration/targets/var_reserved/tasks/task_vars_used.yml test/integration/targets/var_reserved/vars/set_host_variable.yml test/integration/targets/var_templating/aliases test/integration/targets/var_templating/ansible_debug_template.j2 test/integration/targets/var_templating/runme.sh test/integration/targets/var_templating/task_vars_templating.yml test/integration/targets/var_templating/test_connection_vars.yml test/integration/targets/var_templating/undall.yml test/integration/targets/var_templating/undefined.yml test/integration/targets/var_templating/group_vars/all.yml test/integration/targets/var_templating/vars/connection.yml test/integration/targets/vars_files/aliases test/integration/targets/vars_files/inventory test/integration/targets/vars_files/runme.sh test/integration/targets/vars_files/runme.yml test/integration/targets/vars_files/validate.yml test/integration/targets/vars_files/vars/bar.yml test/integration/targets/vars_files/vars/common.yml test/integration/targets/vars_files/vars/defaults.yml test/integration/targets/wait_for/aliases test/integration/targets/wait_for/files/testserver.py test/integration/targets/wait_for/files/write_utf16.py test/integration/targets/wait_for/files/zombie.py test/integration/targets/wait_for/meta/main.yml test/integration/targets/wait_for/tasks/main.yml test/integration/targets/wait_for/vars/main.yml test/integration/targets/wait_for_connection/aliases test/integration/targets/wait_for_connection/tasks/main.yml test/integration/targets/want_json_modules_posix/aliases test/integration/targets/want_json_modules_posix/library/helloworld.py test/integration/targets/want_json_modules_posix/meta/main.yml test/integration/targets/want_json_modules_posix/tasks/main.yml test/integration/targets/win_app_control/aliases test/integration/targets/win_app_control/create_manifest.yml test/integration/targets/win_app_control/main.yml test/integration/targets/win_app_control/runme.sh test/integration/targets/win_app_control/setup.yml test/integration/targets/win_app_control/test_enabled.yml test/integration/targets/win_app_control/test_manifest.yml test/integration/targets/win_app_control/test_not_enabled.yml test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/module_utils/CSharpSigned.cs test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/module_utils/CSharpUnsigned.cs test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/module_utils/PwshSigned.psm1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/module_utils/PwshUnsigned.psm1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/inline_signed.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/inline_signed_not_trusted.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/scope.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/signed.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/signed_module_util.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/skipped.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/unsigned_csharp_util.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/unsigned_module_with_util.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/unsigned_pwsh_util.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/plugins/modules/unsupported.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/roles/app_control_script/files/signed.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/roles/app_control_script/files/unsigned.ps1 test/integration/targets/win_app_control/ansible_collections/ns/col/roles/app_control_script/tasks/main.yml test/integration/targets/win_app_control/ansible_collections/ns/invalid_manifest/meta/.keep test/integration/targets/win_app_control/ansible_collections/ns/invalid_manifest/plugins/modules/module.ps1 test/integration/targets/win_app_control/ansible_collections/ns/module_util_ref/plugins/modules/module.ps1 test/integration/targets/win_app_control/files/New-AnsiblePowerShellSignature.ps1 test/integration/targets/win_app_control/files/Set-ManifestSignature.ps1 test/integration/targets/win_app_control/templates/manifest_invalid_version.psd1 test/integration/targets/win_app_control/templates/manifest_no_hashtable.psd1 test/integration/targets/win_app_control/templates/manifest_no_version.psd1 test/integration/targets/win_app_control/templates/manifest_v1_invalid_hash_subkey.psd1 test/integration/targets/win_app_control/templates/manifest_v1_invalid_mode_subkey.psd1 test/integration/targets/win_app_control/templates/manifest_v1_no_hash_subkey.psd1 test/integration/targets/win_app_control/templates/manifest_v1_no_hashlist.psd1 test/integration/targets/win_app_control/templates/manifest_v1_no_mode_subkey.psd1 test/integration/targets/win_app_control/templates/manifest_v1_ok.psd1 test/integration/targets/win_app_control/templates/manifest_v1_unsafe_expression.psd1 test/integration/targets/win_async_wrapper/aliases test/integration/targets/win_async_wrapper/library/async_test.ps1 test/integration/targets/win_async_wrapper/tasks/main.yml test/integration/targets/win_become/aliases test/integration/targets/win_become/tasks/main.yml test/integration/targets/win_exec_wrapper/aliases test/integration/targets/win_exec_wrapper/action_plugins/test_rc_1.py test/integration/targets/win_exec_wrapper/library/test_all_options.ps1 test/integration/targets/win_exec_wrapper/library/test_exec_wrapper_scope.ps1 test/integration/targets/win_exec_wrapper/library/test_fail.ps1 test/integration/targets/win_exec_wrapper/library/test_invalid_requires.ps1 test/integration/targets/win_exec_wrapper/library/test_min_os_version.ps1 test/integration/targets/win_exec_wrapper/library/test_min_ps_version.ps1 test/integration/targets/win_exec_wrapper/library/test_no_utils.ps1 test/integration/targets/win_exec_wrapper/library/test_rc_1.ps1 test/integration/targets/win_exec_wrapper/module_utils/Ansible.ModuleUtils.ScopedUtil.psm1 test/integration/targets/win_exec_wrapper/tasks/main.yml test/integration/targets/win_fetch/aliases test/integration/targets/win_fetch/meta/main.yml test/integration/targets/win_fetch/tasks/main.yml test/integration/targets/win_module_utils/aliases test/integration/targets/win_module_utils/library/csharp_util.ps1 test/integration/targets/win_module_utils/library/legacy_only_new_way.ps1 test/integration/targets/win_module_utils/library/legacy_only_new_way_win_line_ending.ps1 test/integration/targets/win_module_utils/library/legacy_only_old_way.ps1 test/integration/targets/win_module_utils/library/legacy_only_old_way_win_line_ending.ps1 test/integration/targets/win_module_utils/library/recursive_requires.ps1 test/integration/targets/win_module_utils/library/uses_bogus_utils.ps1 test/integration/targets/win_module_utils/library/uses_local_utils.ps1 test/integration/targets/win_module_utils/module_utils/Ansible.ModuleUtils.Recursive1.psm1 test/integration/targets/win_module_utils/module_utils/Ansible.ModuleUtils.Recursive2.psm1 test/integration/targets/win_module_utils/module_utils/Ansible.ModuleUtils.Recursive3.psm1 test/integration/targets/win_module_utils/module_utils/Ansible.ModuleUtils.ValidTestModule.psm1 test/integration/targets/win_module_utils/module_utils/Ansible.Test.cs test/integration/targets/win_module_utils/tasks/main.yml test/integration/targets/win_raw/aliases test/integration/targets/win_raw/tasks/main.yml test/integration/targets/win_script/aliases test/integration/targets/win_script/defaults/main.yml test/integration/targets/win_script/files/fail.bat test/integration/targets/win_script/files/test_script.bat test/integration/targets/win_script/files/test_script.cmd test/integration/targets/win_script/files/test_script.ps1 test/integration/targets/win_script/files/test_script_bool.ps1 test/integration/targets/win_script/files/test_script_creates_file.ps1 test/integration/targets/win_script/files/test_script_removes_file.ps1 test/integration/targets/win_script/files/test_script_unicode.ps1 test/integration/targets/win_script/files/test_script_whoami.ps1 test/integration/targets/win_script/files/test_script_with_args.ps1 test/integration/targets/win_script/files/test_script_with_env.ps1 test/integration/targets/win_script/files/test_script_with_errors.ps1 test/integration/targets/win_script/files/test_script_with_native_stderr.ps1 test/integration/targets/win_script/files/test_script_with_splatting.ps1 test/integration/targets/win_script/files/space path/test_script.ps1 test/integration/targets/win_script/tasks/main.yml test/integration/targets/windows-minimal/aliases test/integration/targets/windows-minimal/library/test_no_exec_wrapper.ps1 test/integration/targets/windows-minimal/library/win_ping.ps1 test/integration/targets/windows-minimal/library/win_ping.py test/integration/targets/windows-minimal/library/win_ping_set_attr.ps1 test/integration/targets/windows-minimal/library/win_ping_strict_mode_error.ps1 test/integration/targets/windows-minimal/library/win_ping_syntax_error.ps1 test/integration/targets/windows-minimal/library/win_ping_throw.ps1 test/integration/targets/windows-minimal/library/win_ping_throw_string.ps1 test/integration/targets/windows-minimal/meta/main.yml test/integration/targets/windows-minimal/tasks/main.yml test/integration/targets/windows-paths/aliases test/integration/targets/windows-paths/tasks/main.yml test/integration/targets/yaml_parsing/aliases test/integration/targets/yaml_parsing/playbook.yml test/integration/targets/yaml_parsing/tasks/main.yml test/integration/targets/yaml_parsing/tasks/unsafe.yml test/integration/targets/yaml_parsing/vars/main.yml test/integration/targets/yum_repository/aliases test/integration/targets/yum_repository/defaults/main.yml test/integration/targets/yum_repository/handlers/main.yml test/integration/targets/yum_repository/meta/main.yml test/integration/targets/yum_repository/tasks/main.yml test/lib/ansible_test/__init__.py test/lib/ansible_test/_data/ansible.cfg test/lib/ansible_test/_data/coveragerc test/lib/ansible_test/_data/completion/docker.txt test/lib/ansible_test/_data/completion/network.txt test/lib/ansible_test/_data/completion/remote.txt test/lib/ansible_test/_data/completion/windows.txt test/lib/ansible_test/_data/playbooks/posix_coverage_setup.yml test/lib/ansible_test/_data/playbooks/posix_coverage_teardown.yml test/lib/ansible_test/_data/playbooks/posix_hosts_prepare.yml test/lib/ansible_test/_data/playbooks/posix_hosts_restore.yml test/lib/ansible_test/_data/playbooks/pypi_proxy_prepare.yml test/lib/ansible_test/_data/playbooks/pypi_proxy_restore.yml test/lib/ansible_test/_data/playbooks/windows_coverage_setup.yml test/lib/ansible_test/_data/playbooks/windows_coverage_teardown.yml test/lib/ansible_test/_data/playbooks/windows_hosts_prepare.ps1 test/lib/ansible_test/_data/playbooks/windows_hosts_prepare.yml test/lib/ansible_test/_data/playbooks/windows_hosts_restore.ps1 test/lib/ansible_test/_data/playbooks/windows_hosts_restore.yml test/lib/ansible_test/_data/pytest/config/default.ini test/lib/ansible_test/_data/pytest/config/legacy.ini test/lib/ansible_test/_data/requirements/ansible-test.txt test/lib/ansible_test/_data/requirements/ansible.txt test/lib/ansible_test/_data/requirements/constraints.txt test/lib/ansible_test/_data/requirements/sanity.ansible-doc.in test/lib/ansible_test/_data/requirements/sanity.ansible-doc.txt test/lib/ansible_test/_data/requirements/sanity.changelog.in test/lib/ansible_test/_data/requirements/sanity.changelog.txt test/lib/ansible_test/_data/requirements/sanity.import.in test/lib/ansible_test/_data/requirements/sanity.import.plugin.in test/lib/ansible_test/_data/requirements/sanity.import.plugin.txt test/lib/ansible_test/_data/requirements/sanity.import.txt test/lib/ansible_test/_data/requirements/sanity.integration-aliases.in test/lib/ansible_test/_data/requirements/sanity.integration-aliases.txt test/lib/ansible_test/_data/requirements/sanity.pep8.in test/lib/ansible_test/_data/requirements/sanity.pep8.txt test/lib/ansible_test/_data/requirements/sanity.pslint.ps1 test/lib/ansible_test/_data/requirements/sanity.pylint.in test/lib/ansible_test/_data/requirements/sanity.pylint.txt test/lib/ansible_test/_data/requirements/sanity.runtime-metadata.in test/lib/ansible_test/_data/requirements/sanity.runtime-metadata.txt test/lib/ansible_test/_data/requirements/sanity.validate-modules.in test/lib/ansible_test/_data/requirements/sanity.validate-modules.txt test/lib/ansible_test/_data/requirements/sanity.yamllint.in test/lib/ansible_test/_data/requirements/sanity.yamllint.txt test/lib/ansible_test/_data/requirements/units.txt test/lib/ansible_test/_data/requirements/windows-integration.txt test/lib/ansible_test/_internal/__init__.py test/lib/ansible_test/_internal/ansible_util.py test/lib/ansible_test/_internal/become.py test/lib/ansible_test/_internal/bootstrap.py test/lib/ansible_test/_internal/cache.py test/lib/ansible_test/_internal/cgroup.py test/lib/ansible_test/_internal/completion.py test/lib/ansible_test/_internal/config.py test/lib/ansible_test/_internal/connections.py test/lib/ansible_test/_internal/constants.py test/lib/ansible_test/_internal/containers.py test/lib/ansible_test/_internal/content_config.py test/lib/ansible_test/_internal/core_ci.py test/lib/ansible_test/_internal/coverage_util.py test/lib/ansible_test/_internal/data.py test/lib/ansible_test/_internal/delegation.py test/lib/ansible_test/_internal/diff.py test/lib/ansible_test/_internal/docker_util.py test/lib/ansible_test/_internal/encoding.py test/lib/ansible_test/_internal/executor.py test/lib/ansible_test/_internal/git.py test/lib/ansible_test/_internal/host_configs.py test/lib/ansible_test/_internal/host_profiles.py test/lib/ansible_test/_internal/http.py test/lib/ansible_test/_internal/init.py test/lib/ansible_test/_internal/inventory.py test/lib/ansible_test/_internal/io.py test/lib/ansible_test/_internal/junit_xml.py test/lib/ansible_test/_internal/locale_util.py test/lib/ansible_test/_internal/metadata.py test/lib/ansible_test/_internal/payload.py test/lib/ansible_test/_internal/provisioning.py test/lib/ansible_test/_internal/pypi_proxy.py test/lib/ansible_test/_internal/python_requirements.py test/lib/ansible_test/_internal/ssh.py test/lib/ansible_test/_internal/target.py test/lib/ansible_test/_internal/test.py test/lib/ansible_test/_internal/thread.py test/lib/ansible_test/_internal/timeout.py test/lib/ansible_test/_internal/util.py test/lib/ansible_test/_internal/util_common.py test/lib/ansible_test/_internal/venv.py test/lib/ansible_test/_internal/ci/__init__.py test/lib/ansible_test/_internal/ci/azp.py test/lib/ansible_test/_internal/ci/local.py test/lib/ansible_test/_internal/classification/__init__.py test/lib/ansible_test/_internal/classification/common.py test/lib/ansible_test/_internal/classification/csharp.py test/lib/ansible_test/_internal/classification/powershell.py test/lib/ansible_test/_internal/classification/python.py test/lib/ansible_test/_internal/cli/__init__.py test/lib/ansible_test/_internal/cli/actions.py test/lib/ansible_test/_internal/cli/compat.py test/lib/ansible_test/_internal/cli/completers.py test/lib/ansible_test/_internal/cli/converters.py test/lib/ansible_test/_internal/cli/environments.py test/lib/ansible_test/_internal/cli/epilog.py test/lib/ansible_test/_internal/cli/argparsing/__init__.py test/lib/ansible_test/_internal/cli/argparsing/actions.py test/lib/ansible_test/_internal/cli/argparsing/argcompletion.py test/lib/ansible_test/_internal/cli/argparsing/parsers.py test/lib/ansible_test/_internal/cli/commands/__init__.py test/lib/ansible_test/_internal/cli/commands/env.py test/lib/ansible_test/_internal/cli/commands/sanity.py test/lib/ansible_test/_internal/cli/commands/shell.py test/lib/ansible_test/_internal/cli/commands/units.py test/lib/ansible_test/_internal/cli/commands/coverage/__init__.py test/lib/ansible_test/_internal/cli/commands/coverage/combine.py test/lib/ansible_test/_internal/cli/commands/coverage/erase.py test/lib/ansible_test/_internal/cli/commands/coverage/html.py test/lib/ansible_test/_internal/cli/commands/coverage/report.py test/lib/ansible_test/_internal/cli/commands/coverage/xml.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/__init__.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py test/lib/ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py test/lib/ansible_test/_internal/cli/commands/integration/__init__.py test/lib/ansible_test/_internal/cli/commands/integration/network.py test/lib/ansible_test/_internal/cli/commands/integration/posix.py test/lib/ansible_test/_internal/cli/commands/integration/windows.py test/lib/ansible_test/_internal/cli/parsers/__init__.py test/lib/ansible_test/_internal/cli/parsers/base_argument_parsers.py test/lib/ansible_test/_internal/cli/parsers/helpers.py test/lib/ansible_test/_internal/cli/parsers/host_config_parsers.py test/lib/ansible_test/_internal/cli/parsers/key_value_parsers.py test/lib/ansible_test/_internal/cli/parsers/value_parsers.py test/lib/ansible_test/_internal/commands/__init__.py test/lib/ansible_test/_internal/commands/coverage/__init__.py test/lib/ansible_test/_internal/commands/coverage/combine.py test/lib/ansible_test/_internal/commands/coverage/erase.py test/lib/ansible_test/_internal/commands/coverage/html.py test/lib/ansible_test/_internal/commands/coverage/report.py test/lib/ansible_test/_internal/commands/coverage/xml.py test/lib/ansible_test/_internal/commands/coverage/analyze/__init__.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/__init__.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/combine.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/expand.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/filter.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/generate.py test/lib/ansible_test/_internal/commands/coverage/analyze/targets/missing.py test/lib/ansible_test/_internal/commands/env/__init__.py test/lib/ansible_test/_internal/commands/integration/__init__.py test/lib/ansible_test/_internal/commands/integration/coverage.py test/lib/ansible_test/_internal/commands/integration/filters.py test/lib/ansible_test/_internal/commands/integration/network.py test/lib/ansible_test/_internal/commands/integration/posix.py test/lib/ansible_test/_internal/commands/integration/windows.py test/lib/ansible_test/_internal/commands/integration/cloud/__init__.py test/lib/ansible_test/_internal/commands/integration/cloud/acme.py test/lib/ansible_test/_internal/commands/integration/cloud/aws.py test/lib/ansible_test/_internal/commands/integration/cloud/azure.py test/lib/ansible_test/_internal/commands/integration/cloud/cloudscale.py test/lib/ansible_test/_internal/commands/integration/cloud/cs.py test/lib/ansible_test/_internal/commands/integration/cloud/digitalocean.py test/lib/ansible_test/_internal/commands/integration/cloud/galaxy.py test/lib/ansible_test/_internal/commands/integration/cloud/gcp.py test/lib/ansible_test/_internal/commands/integration/cloud/hcloud.py test/lib/ansible_test/_internal/commands/integration/cloud/httptester.py test/lib/ansible_test/_internal/commands/integration/cloud/nios.py test/lib/ansible_test/_internal/commands/integration/cloud/opennebula.py test/lib/ansible_test/_internal/commands/integration/cloud/openshift.py test/lib/ansible_test/_internal/commands/integration/cloud/scaleway.py test/lib/ansible_test/_internal/commands/integration/cloud/vcenter.py test/lib/ansible_test/_internal/commands/integration/cloud/vultr.py test/lib/ansible_test/_internal/commands/sanity/__init__.py test/lib/ansible_test/_internal/commands/sanity/ansible_doc.py test/lib/ansible_test/_internal/commands/sanity/bin_symlinks.py test/lib/ansible_test/_internal/commands/sanity/compile.py test/lib/ansible_test/_internal/commands/sanity/ignores.py test/lib/ansible_test/_internal/commands/sanity/import.py test/lib/ansible_test/_internal/commands/sanity/integration_aliases.py test/lib/ansible_test/_internal/commands/sanity/pep8.py test/lib/ansible_test/_internal/commands/sanity/pslint.py test/lib/ansible_test/_internal/commands/sanity/pylint.py test/lib/ansible_test/_internal/commands/sanity/shellcheck.py test/lib/ansible_test/_internal/commands/sanity/validate_modules.py test/lib/ansible_test/_internal/commands/sanity/yamllint.py test/lib/ansible_test/_internal/commands/shell/__init__.py test/lib/ansible_test/_internal/commands/units/__init__.py test/lib/ansible_test/_internal/compat/__init__.py test/lib/ansible_test/_internal/compat/packaging.py test/lib/ansible_test/_internal/compat/yaml.py test/lib/ansible_test/_internal/dev/__init__.py test/lib/ansible_test/_internal/dev/container_probe.py test/lib/ansible_test/_internal/provider/__init__.py test/lib/ansible_test/_internal/provider/layout/__init__.py test/lib/ansible_test/_internal/provider/layout/ansible.py test/lib/ansible_test/_internal/provider/layout/collection.py test/lib/ansible_test/_internal/provider/layout/unsupported.py test/lib/ansible_test/_internal/provider/source/__init__.py test/lib/ansible_test/_internal/provider/source/git.py test/lib/ansible_test/_internal/provider/source/installed.py test/lib/ansible_test/_internal/provider/source/unsupported.py test/lib/ansible_test/_internal/provider/source/unversioned.py test/lib/ansible_test/_util/__init__.py test/lib/ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json test/lib/ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py test/lib/ansible_test/_util/controller/sanity/code-smell/changelog.json test/lib/ansible_test/_util/controller/sanity/code-smell/changelog.py test/lib/ansible_test/_util/controller/sanity/code-smell/empty-init.json test/lib/ansible_test/_util/controller/sanity/code-smell/empty-init.py test/lib/ansible_test/_util/controller/sanity/code-smell/line-endings.json test/lib/ansible_test/_util/controller/sanity/code-smell/line-endings.py test/lib/ansible_test/_util/controller/sanity/code-smell/no-assert.json test/lib/ansible_test/_util/controller/sanity/code-smell/no-assert.py test/lib/ansible_test/_util/controller/sanity/code-smell/no-get-exception.json test/lib/ansible_test/_util/controller/sanity/code-smell/no-get-exception.py test/lib/ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.json test/lib/ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py test/lib/ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.json test/lib/ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py test/lib/ansible_test/_util/controller/sanity/code-smell/replace-urlopen.json test/lib/ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.json test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py test/lib/ansible_test/_util/controller/sanity/code-smell/shebang.json test/lib/ansible_test/_util/controller/sanity/code-smell/shebang.py test/lib/ansible_test/_util/controller/sanity/code-smell/symlinks.json test/lib/ansible_test/_util/controller/sanity/code-smell/symlinks.py test/lib/ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.json test/lib/ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py test/lib/ansible_test/_util/controller/sanity/code-smell/use-compat-six.json test/lib/ansible_test/_util/controller/sanity/code-smell/use-compat-six.py test/lib/ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py test/lib/ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py test/lib/ansible_test/_util/controller/sanity/pep8/current-ignore.txt test/lib/ansible_test/_util/controller/sanity/pslint/pslint.ps1 test/lib/ansible_test/_util/controller/sanity/pslint/settings.psd1 test/lib/ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg test/lib/ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg test/lib/ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg test/lib/ansible_test/_util/controller/sanity/pylint/config/collection.cfg test/lib/ansible_test/_util/controller/sanity/pylint/config/default.cfg test/lib/ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py test/lib/ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py test/lib/ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py test/lib/ansible_test/_util/controller/sanity/pylint/plugins/string_format.py test/lib/ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py test/lib/ansible_test/_util/controller/sanity/shellcheck/exclude.txt test/lib/ansible_test/_util/controller/sanity/validate-modules/validate.py test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/__init__.py test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/ps_argspec.ps1 test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py test/lib/ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py test/lib/ansible_test/_util/controller/sanity/yamllint/yamllinter.py test/lib/ansible_test/_util/controller/sanity/yamllint/config/default.yml test/lib/ansible_test/_util/controller/sanity/yamllint/config/modules.yml test/lib/ansible_test/_util/controller/sanity/yamllint/config/plugins.yml test/lib/ansible_test/_util/controller/tools/collection_detail.py test/lib/ansible_test/_util/controller/tools/coverage_stub.ps1 test/lib/ansible_test/_util/controller/tools/yaml_to_json.py test/lib/ansible_test/_util/target/__init__.py test/lib/ansible_test/_util/target/cli/ansible_test_cli_stub.py test/lib/ansible_test/_util/target/common/constants.py test/lib/ansible_test/_util/target/injector/python.py test/lib/ansible_test/_util/target/injector/virtualenv.sh test/lib/ansible_test/_util/target/pytest/plugins/ansible_forked.py test/lib/ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py test/lib/ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py test/lib/ansible_test/_util/target/sanity/compile/compile.py test/lib/ansible_test/_util/target/sanity/import/importer.py test/lib/ansible_test/_util/target/setup/bootstrap.sh test/lib/ansible_test/_util/target/setup/check_systemd_cgroup_v1.sh test/lib/ansible_test/_util/target/setup/probe_cgroups.py test/lib/ansible_test/_util/target/setup/quiet_pip.py test/lib/ansible_test/_util/target/setup/requirements.py test/lib/ansible_test/_util/target/tools/virtualenvcheck.py test/lib/ansible_test/_util/target/tools/yamlcheck.py test/lib/ansible_test/config/cloud-config-aws.ini.template test/lib/ansible_test/config/cloud-config-azure.ini.template test/lib/ansible_test/config/cloud-config-cloudscale.ini.template test/lib/ansible_test/config/cloud-config-cs.ini.template test/lib/ansible_test/config/cloud-config-gcp.ini.template test/lib/ansible_test/config/cloud-config-hcloud.ini.template test/lib/ansible_test/config/cloud-config-opennebula.ini.template test/lib/ansible_test/config/cloud-config-openshift.kubeconfig.template test/lib/ansible_test/config/cloud-config-scaleway.ini.template test/lib/ansible_test/config/cloud-config-vcenter.ini.template test/lib/ansible_test/config/cloud-config-vultr.ini.template test/lib/ansible_test/config/config.yml test/lib/ansible_test/config/inventory.networking.template test/lib/ansible_test/config/inventory.winrm.template test/sanity/ignore.txt test/sanity/code-smell/ansible-requirements.json test/sanity/code-smell/ansible-requirements.py test/sanity/code-smell/black.json test/sanity/code-smell/black.py test/sanity/code-smell/black.requirements.in test/sanity/code-smell/black.requirements.txt test/sanity/code-smell/boilerplate.json test/sanity/code-smell/boilerplate.py test/sanity/code-smell/deprecated-config.json test/sanity/code-smell/deprecated-config.py test/sanity/code-smell/deprecated-config.requirements.in test/sanity/code-smell/deprecated-config.requirements.txt test/sanity/code-smell/mypy.json test/sanity/code-smell/mypy.py test/sanity/code-smell/mypy.requirements.in test/sanity/code-smell/mypy.requirements.txt test/sanity/code-smell/no-unwanted-characters.json test/sanity/code-smell/no-unwanted-characters.py test/sanity/code-smell/no-unwanted-files.json test/sanity/code-smell/no-unwanted-files.py test/sanity/code-smell/obsolete-files.json test/sanity/code-smell/obsolete-files.py test/sanity/code-smell/package-data.json test/sanity/code-smell/package-data.py test/sanity/code-smell/package-data.requirements.in test/sanity/code-smell/package-data.requirements.txt test/sanity/code-smell/pymarkdown.config.json test/sanity/code-smell/pymarkdown.json test/sanity/code-smell/pymarkdown.py test/sanity/code-smell/pymarkdown.requirements.in test/sanity/code-smell/pymarkdown.requirements.txt test/sanity/code-smell/release-names.json test/sanity/code-smell/release-names.py test/sanity/code-smell/required-and-default-attributes.json test/sanity/code-smell/required-and-default-attributes.py test/sanity/code-smell/skip.txt test/sanity/code-smell/test-constraints.json test/sanity/code-smell/test-constraints.py test/sanity/code-smell/update-bundled.json test/sanity/code-smell/update-bundled.py test/sanity/code-smell/update-bundled.requirements.in test/sanity/code-smell/update-bundled.requirements.txt test/sanity/code-smell/mypy/ansible-core.ini test/sanity/code-smell/mypy/ansible-test.ini test/sanity/code-smell/mypy/packaging.ini test/support/README.md test/support/integration/plugins/modules/pkgng.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/action/cli_config.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/action/net_get.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/action/net_put.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/action/network.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/connection/network_cli.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/connection/persistent.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/doc_fragments/connection_persistent.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/compat/ipaddress.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/config.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/netconf.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/network.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/parsing.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/utils.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/cfg/base.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/module_utils/network/common/facts/facts.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/modules/cli_config.py test/support/network-integration/collections/ansible_collections/ansible/netcommon/plugins/plugin_utils/connection_base.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/action/ios.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/cliconf/ios.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/doc_fragments/ios.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/module_utils/network/ios/ios.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_command.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/modules/ios_config.py test/support/network-integration/collections/ansible_collections/cisco/ios/plugins/terminal/ios.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/action/win_copy.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/action/win_reboot.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/module_utils/WebRequest.psm1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/async_status.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_acl.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_acl.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_copy.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_copy.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_file.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_file.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_ping.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_ping.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_shell.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_shell.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_stat.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_stat.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_uri.ps1 test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/modules/win_uri.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_quote.py test/support/windows-integration/collections/ansible_collections/ansible/windows/plugins/plugin_utils/_reboot.py test/support/windows-integration/plugins/action/win_copy.py test/support/windows-integration/plugins/action/win_reboot.py test/support/windows-integration/plugins/action/win_template.py test/support/windows-integration/plugins/become/runas.py test/support/windows-integration/plugins/module_utils/Ansible.Service.cs test/support/windows-integration/plugins/modules/async_status.ps1 test/support/windows-integration/plugins/modules/setup.ps1 test/support/windows-integration/plugins/modules/slurp.ps1 test/support/windows-integration/plugins/modules/win_acl.ps1 test/support/windows-integration/plugins/modules/win_acl.py test/support/windows-integration/plugins/modules/win_certificate_store.ps1 test/support/windows-integration/plugins/modules/win_certificate_store.py test/support/windows-integration/plugins/modules/win_command.ps1 test/support/windows-integration/plugins/modules/win_command.py test/support/windows-integration/plugins/modules/win_copy.ps1 test/support/windows-integration/plugins/modules/win_copy.py test/support/windows-integration/plugins/modules/win_file.ps1 test/support/windows-integration/plugins/modules/win_file.py test/support/windows-integration/plugins/modules/win_get_url.ps1 test/support/windows-integration/plugins/modules/win_get_url.py test/support/windows-integration/plugins/modules/win_lineinfile.ps1 test/support/windows-integration/plugins/modules/win_lineinfile.py test/support/windows-integration/plugins/modules/win_ping.ps1 test/support/windows-integration/plugins/modules/win_ping.py test/support/windows-integration/plugins/modules/win_reboot.py test/support/windows-integration/plugins/modules/win_regedit.ps1 test/support/windows-integration/plugins/modules/win_regedit.py test/support/windows-integration/plugins/modules/win_shell.ps1 test/support/windows-integration/plugins/modules/win_shell.py test/support/windows-integration/plugins/modules/win_stat.ps1 test/support/windows-integration/plugins/modules/win_stat.py test/support/windows-integration/plugins/modules/win_tempfile.ps1 test/support/windows-integration/plugins/modules/win_user.ps1 test/support/windows-integration/plugins/modules/win_user.py test/support/windows-integration/plugins/modules/win_user_right.ps1 test/support/windows-integration/plugins/modules/win_user_right.py test/support/windows-integration/plugins/modules/win_wait_for.ps1 test/support/windows-integration/plugins/modules/win_wait_for.py test/support/windows-integration/plugins/modules/win_whoami.ps1 test/support/windows-integration/plugins/modules/win_whoami.py test/units/__init__.py test/units/conftest.py test/units/controller_only_conftest.py test/units/requirements.txt test/units/test_context.py test/units/test_no_tty.py test/units/_internal/__init__.py test/units/_internal/test_event_formatting.py test/units/_internal/test_locking.py test/units/_internal/_datatag/__init__.py test/units/_internal/_datatag/test_tags.py test/units/_internal/_errors/test_alarm_timeout.py test/units/_internal/_errors/test_error_utils.py test/units/_internal/_errors/test_task_timeout.py test/units/_internal/_json/__init__.py test/units/_internal/_json/test_legacy_encoder.py test/units/_internal/templating/__init__.py test/units/_internal/templating/conftest.py test/units/_internal/templating/test_access.py test/units/_internal/templating/test_common_.py test/units/_internal/templating/test_datatag.py test/units/_internal/templating/test_jinja_bits.py test/units/_internal/templating/test_jinja_plugins.py test/units/_internal/templating/test_lazy_containers.py test/units/_internal/templating/test_templar.py test/units/_internal/templating/test_template_utilities.py test/units/_internal/templating/test_utils.py test/units/_internal/templating/fixtures/__init__.py test/units/_internal/templating/fixtures/valid_collection/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/filter/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/filter/correct.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/filter/get_filters_error.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/filter/load_error.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/lookup/__init__.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/lookup/also_also_valid.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/lookup/load_error.py test/units/_internal/templating/fixtures/valid_collection/ansible_collections/valid/also_valid/plugins/lookup/runtime_error.py test/units/_vendor/__init__.py test/units/_vendor/test_vendor.py test/units/ansible_test/__init__.py test/units/ansible_test/conftest.py test/units/ansible_test/test_diff.py test/units/ansible_test/_internal/__init__.py test/units/ansible_test/_internal/test_util.py test/units/ansible_test/ci/__init__.py test/units/ansible_test/ci/test_azp.py test/units/ansible_test/ci/util.py test/units/ansible_test/diff/add_binary_file.diff test/units/ansible_test/diff/add_text_file.diff test/units/ansible_test/diff/add_trailing_newline.diff test/units/ansible_test/diff/add_two_text_files.diff test/units/ansible_test/diff/context_no_trailing_newline.diff test/units/ansible_test/diff/multiple_context_lines.diff test/units/ansible_test/diff/parse_delete.diff test/units/ansible_test/diff/parse_rename.diff test/units/ansible_test/diff/remove_trailing_newline.diff test/units/cli/__init__.py test/units/cli/test_adhoc.py test/units/cli/test_cli.py test/units/cli/test_console.py test/units/cli/test_doc.py test/units/cli/test_galaxy.py test/units/cli/test_playbook.py test/units/cli/test_vault.py test/units/cli/arguments/test_option_helpers.py test/units/cli/galaxy/test_collection_extract_tar.py test/units/cli/galaxy/test_display_collection.py test/units/cli/galaxy/test_display_header.py test/units/cli/galaxy/test_display_role.py test/units/cli/galaxy/test_execute_list.py test/units/cli/galaxy/test_execute_list_collection.py test/units/cli/galaxy/test_get_collection_widths.py test/units/cli/test_data/collection_skeleton/README.md test/units/cli/test_data/collection_skeleton/galaxy.yml.j2 test/units/cli/test_data/collection_skeleton/docs/My Collection.md test/units/cli/test_data/collection_skeleton/playbooks/main.yml test/units/cli/test_data/collection_skeleton/playbooks/templates/test.conf.j2 test/units/cli/test_data/collection_skeleton/playbooks/templates/subfolder/test.conf.j2 test/units/cli/test_data/collection_skeleton/plugins/action/.git_keep test/units/cli/test_data/collection_skeleton/plugins/filter/.git_keep test/units/cli/test_data/collection_skeleton/plugins/inventory/.git_keep test/units/cli/test_data/collection_skeleton/plugins/lookup/.git_keep test/units/cli/test_data/collection_skeleton/plugins/module_utils/.git_keep test/units/cli/test_data/collection_skeleton/plugins/modules/.git_keep test/units/cli/test_data/collection_skeleton/roles/common/tasks/main.yml.j2 test/units/cli/test_data/collection_skeleton/roles/common/templates/test.conf.j2 test/units/cli/test_data/collection_skeleton/roles/common/templates/subfolder/test.conf.j2 test/units/cli/test_data/role_skeleton/README.md test/units/cli/test_data/role_skeleton/inventory test/units/cli/test_data/role_skeleton/defaults/main.yml.j2 test/units/cli/test_data/role_skeleton/files/.git_keep test/units/cli/test_data/role_skeleton/handlers/main.yml.j2 test/units/cli/test_data/role_skeleton/meta/main.yml.j2 test/units/cli/test_data/role_skeleton/tasks/main.yml.j2 test/units/cli/test_data/role_skeleton/templates/.git_keep test/units/cli/test_data/role_skeleton/templates/test.conf.j2 test/units/cli/test_data/role_skeleton/templates/subfolder/test.conf.j2 test/units/cli/test_data/role_skeleton/templates_extra/templates.txt.j2 test/units/cli/test_data/role_skeleton/tests/test.yml.j2 test/units/cli/test_data/role_skeleton/vars/main.yml.j2 test/units/config/__init__.py test/units/config/test.cfg test/units/config/test.yml test/units/config/test2.cfg test/units/config/test3.cfg test/units/config/test_manager.py test/units/config/manager/__init__.py test/units/config/manager/test_find_ini_config_file.py test/units/errors/__init__.py test/units/errors/test_errors.py test/units/errors/test_handler.py test/units/errors/test_utils.py test/units/errors/fixtures/inputs/empty_file.txt test/units/errors/fixtures/inputs/file_with_tabs.txt test/units/errors/fixtures/inputs/long_file.txt test/units/errors/fixtures/inputs/one_line_file.txt test/units/errors/fixtures/inputs/short_file.txt test/units/errors/fixtures/inputs/short_file_missing_trailing_newline.txt test/units/errors/fixtures/outputs/empty_file_unavailable.txt test/units/errors/fixtures/outputs/file_with_tabs_replaced_left_marker.txt test/units/errors/fixtures/outputs/long_file_last_column_right_marker.txt test/units/errors/fixtures/outputs/nonexistent.txt test/units/errors/fixtures/outputs/short_file_last_column_right_marker.txt test/units/errors/fixtures/outputs/short_file_left_marker.txt test/units/errors/fixtures/outputs/short_file_long_line_truncated_past_target.txt test/units/errors/fixtures/outputs/short_file_missing_trailing_newline_left_marker.txt test/units/errors/fixtures/outputs/short_file_no_column.txt test/units/errors/fixtures/outputs/short_file_no_column_overflowed.txt test/units/errors/fixtures/outputs/short_file_no_context_left_marker.txt test/units/errors/fixtures/outputs/short_file_no_line.txt test/units/errors/fixtures/outputs/short_file_overflowed_col.txt test/units/errors/fixtures/outputs/short_file_overflowed_line.txt test/units/errors/fixtures/outputs/short_file_truncated_target.txt test/units/errors/fixtures/outputs/short_file_truncated_target_last_displayed_char.txt test/units/errors/fixtures/outputs/short_file_underflowed_col.txt test/units/errors/fixtures/outputs/short_file_underflowed_line.txt test/units/executor/__init__.py test/units/executor/test_play_iterator.py test/units/executor/test_playbook_executor.py test/units/executor/test_task_executor.py test/units/executor/test_task_result.py test/units/executor/module_common/conftest.py test/units/executor/module_common/test_module_common.py test/units/executor/module_common/test_recursive_finder.py test/units/galaxy/__init__.py test/units/galaxy/test_api.py test/units/galaxy/test_collection.py test/units/galaxy/test_collection_dataclasses.py test/units/galaxy/test_collection_install.py test/units/galaxy/test_role_install.py test/units/galaxy/test_role_requirements.py test/units/galaxy/test_token.py test/units/galaxy/test_user_agent.py test/units/inventory/__init__.py test/units/inventory/test_data.py test/units/inventory/test_group.py test/units/inventory/test_host.py test/units/inventory_test_data/group_vars/noparse/all.yml~ test/units/inventory_test_data/group_vars/noparse/file.txt test/units/inventory_test_data/group_vars/parse/all.yml test/units/mock/__init__.py test/units/mock/custom_types.py test/units/mock/error_helper.py test/units/mock/loader.py test/units/mock/module.py test/units/mock/path.py test/units/mock/vault_helper.py test/units/mock/yaml_helper.py test/units/module_utils/__init__.py test/units/module_utils/conftest.py test/units/module_utils/test_api.py test/units/module_utils/test_connection.py test/units/module_utils/test_distro.py test/units/module_utils/test_text.py test/units/module_utils/_internal/__init__.py test/units/module_utils/_internal/test_deprecator.py test/units/module_utils/_internal/_concurrent/__init__.py test/units/module_utils/_internal/_concurrent/test_daemon_threading.py test/units/module_utils/_internal/_concurrent/test_futures.py test/units/module_utils/_internal/_patches/__init__.py test/units/module_utils/_internal/_patches/test_dataclass_annotation_patch.py test/units/module_utils/_internal/_patches/test_patches.py test/units/module_utils/_internal/_patches/test_socket_patch.py test/units/module_utils/_internal/_patches/test_sys_intern_patch.py test/units/module_utils/basic/__init__.py test/units/module_utils/basic/test__log_invocation.py test/units/module_utils/basic/test__symbolic_mode_to_octal.py test/units/module_utils/basic/test_argument_spec.py test/units/module_utils/basic/test_atomic_move.py test/units/module_utils/basic/test_command_nonexisting.py test/units/module_utils/basic/test_dict_converters.py test/units/module_utils/basic/test_exit_json.py test/units/module_utils/basic/test_filesystem.py test/units/module_utils/basic/test_get_available_hash_algorithms.py test/units/module_utils/basic/test_get_file_attributes.py test/units/module_utils/basic/test_get_module_path.py test/units/module_utils/basic/test_heuristic_log_sanitize.py test/units/module_utils/basic/test_imports.py test/units/module_utils/basic/test_log.py test/units/module_utils/basic/test_no_log.py test/units/module_utils/basic/test_platform_distribution.py test/units/module_utils/basic/test_run_command.py test/units/module_utils/basic/test_safe_eval.py test/units/module_utils/basic/test_sanitize_keys.py test/units/module_utils/basic/test_selinux.py test/units/module_utils/basic/test_set_cwd.py test/units/module_utils/basic/test_set_mode_if_different.py test/units/module_utils/basic/test_tmpdir.py test/units/module_utils/common/__init__.py test/units/module_utils/common/test_collections.py test/units/module_utils/common/test_dict_transformations.py test/units/module_utils/common/test_json.py test/units/module_utils/common/test_locale.py test/units/module_utils/common/test_network.py test/units/module_utils/common/test_sys_info.py test/units/module_utils/common/test_utils.py test/units/module_utils/common/test_yaml.py test/units/module_utils/common/arg_spec/__init__.py test/units/module_utils/common/arg_spec/test_aliases.py test/units/module_utils/common/arg_spec/test_module_validate.py test/units/module_utils/common/arg_spec/test_sub_spec.py test/units/module_utils/common/arg_spec/test_validate_invalid.py test/units/module_utils/common/arg_spec/test_validate_valid.py test/units/module_utils/common/parameters/test_check_arguments.py test/units/module_utils/common/parameters/test_handle_aliases.py test/units/module_utils/common/parameters/test_list_deprecations.py test/units/module_utils/common/parameters/test_list_no_log_values.py test/units/module_utils/common/process/test_get_bin_path.py test/units/module_utils/common/text/converters/test_container_to_bytes.py test/units/module_utils/common/text/converters/test_container_to_text.py test/units/module_utils/common/text/converters/test_jsonify.py test/units/module_utils/common/text/converters/test_to_str.py test/units/module_utils/common/text/formatters/test_bytes_to_human.py test/units/module_utils/common/text/formatters/test_human_to_bytes.py test/units/module_utils/common/text/formatters/test_lenient_lowercase.py test/units/module_utils/common/validation/test_check_missing_parameters.py test/units/module_utils/common/validation/test_check_mutually_exclusive.py test/units/module_utils/common/validation/test_check_required_arguments.py test/units/module_utils/common/validation/test_check_required_by.py test/units/module_utils/common/validation/test_check_required_if.py test/units/module_utils/common/validation/test_check_required_one_of.py test/units/module_utils/common/validation/test_check_required_together.py test/units/module_utils/common/validation/test_check_type_bits.py test/units/module_utils/common/validation/test_check_type_bool.py test/units/module_utils/common/validation/test_check_type_bytes.py test/units/module_utils/common/validation/test_check_type_dict.py test/units/module_utils/common/validation/test_check_type_float.py test/units/module_utils/common/validation/test_check_type_int.py test/units/module_utils/common/validation/test_check_type_jsonarg.py test/units/module_utils/common/validation/test_check_type_list.py test/units/module_utils/common/validation/test_check_type_path.py test/units/module_utils/common/validation/test_check_type_raw.py test/units/module_utils/common/validation/test_check_type_str.py test/units/module_utils/common/validation/test_count_terms.py test/units/module_utils/common/warnings/test_deprecate.py test/units/module_utils/common/warnings/test_error_as_warning.py test/units/module_utils/common/warnings/test_warn.py test/units/module_utils/compat/__init__.py test/units/module_utils/compat/test_datetime.py test/units/module_utils/datatag/__init__.py test/units/module_utils/datatag/test_datatag.py test/units/module_utils/facts/__init__.py test/units/module_utils/facts/base.py test/units/module_utils/facts/test_ansible_collector.py test/units/module_utils/facts/test_collector.py test/units/module_utils/facts/test_collectors.py test/units/module_utils/facts/test_date_time.py test/units/module_utils/facts/test_facts.py test/units/module_utils/facts/test_sysctl.py test/units/module_utils/facts/test_timeout.py test/units/module_utils/facts/test_utils.py test/units/module_utils/facts/fixtures/findmount_output.txt test/units/module_utils/facts/fixtures/cpuinfo/aarch64-4cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/arm64-4cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/armv6-rev7-1cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/armv7-rev3-8cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/armv7-rev4-4cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/ppc64-power7-rhel7-8cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/ppc64le-power8-24cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/s390x-z13-2cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/s390x-z14-64cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/sparc-t5-debian-ldom-24vcpu test/units/module_utils/facts/fixtures/cpuinfo/x86_64-2cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/x86_64-4cpu-cpuinfo test/units/module_utils/facts/fixtures/cpuinfo/x86_64-8cpu-cpuinfo test/units/module_utils/facts/fixtures/distribution_files/ClearLinux test/units/module_utils/facts/fixtures/distribution_files/CoreOS test/units/module_utils/facts/fixtures/distribution_files/LinuxMint test/units/module_utils/facts/fixtures/distribution_files/Slackware test/units/module_utils/facts/fixtures/distribution_files/SlackwareCurrent test/units/module_utils/facts/hardware/__init__.py test/units/module_utils/facts/hardware/aix_data.py test/units/module_utils/facts/hardware/linux_data.py test/units/module_utils/facts/hardware/test_aix_processor.py test/units/module_utils/facts/hardware/test_darwin_facts.py test/units/module_utils/facts/hardware/test_linux.py test/units/module_utils/facts/hardware/test_linux_get_cpu_info.py test/units/module_utils/facts/hardware/test_sunos_get_uptime_facts.py test/units/module_utils/facts/hardware/fixtures/sysctl_darwin_intel.txt test/units/module_utils/facts/hardware/fixtures/sysctl_darwin_silicon.txt test/units/module_utils/facts/hardware/fixtures/vm_stat_darwin_intel.txt test/units/module_utils/facts/hardware/fixtures/vm_stat_darwin_silicon.txt test/units/module_utils/facts/hardware/freebsd/test_get_device_facts.py test/units/module_utils/facts/hardware/freebsd/fixtures/devices test/units/module_utils/facts/hardware/freebsd/fixtures/expected_devices test/units/module_utils/facts/hardware/linux/test_get_sysinfo_facts.py test/units/module_utils/facts/hardware/linux/fixtures/sysinfo test/units/module_utils/facts/network/__init__.py test/units/module_utils/facts/network/test_fc_wwn.py test/units/module_utils/facts/network/test_generic_bsd.py test/units/module_utils/facts/network/test_iscsi_get_initiator.py test/units/module_utils/facts/network/test_locally_reachable_ips.py test/units/module_utils/facts/other/__init__.py test/units/module_utils/facts/other/test_facter.py test/units/module_utils/facts/other/test_ohai.py test/units/module_utils/facts/system/__init__.py test/units/module_utils/facts/system/test_cmdline.py test/units/module_utils/facts/system/test_fips.py test/units/module_utils/facts/system/test_lsb.py test/units/module_utils/facts/system/test_pkg_mgr.py test/units/module_utils/facts/system/test_user.py test/units/module_utils/facts/system/distribution/__init__.py test/units/module_utils/facts/system/distribution/conftest.py test/units/module_utils/facts/system/distribution/test_distribution_files.py test/units/module_utils/facts/system/distribution/test_distribution_sles4sap.py test/units/module_utils/facts/system/distribution/test_distribution_version.py test/units/module_utils/facts/system/distribution/test_parse_distribution_file_ClearLinux.py test/units/module_utils/facts/system/distribution/test_parse_distribution_file_Slackware.py test/units/module_utils/facts/system/distribution/fixtures/almalinux_8_3_beta.json test/units/module_utils/facts/system/distribution/fixtures/alp-dolomite.json test/units/module_utils/facts/system/distribution/fixtures/amazon_linux_2.json test/units/module_utils/facts/system/distribution/fixtures/amazon_linux_2016.03.json test/units/module_utils/facts/system/distribution/fixtures/amazon_linux_2018.03.json test/units/module_utils/facts/system/distribution/fixtures/amazon_linux_2_karoo.json test/units/module_utils/facts/system/distribution/fixtures/amazon_linux_release_2.json test/units/module_utils/facts/system/distribution/fixtures/arch_linux_na.json test/units/module_utils/facts/system/distribution/fixtures/arch_linux_no_arch-release_na.json test/units/module_utils/facts/system/distribution/fixtures/archlinux_rolling.json test/units/module_utils/facts/system/distribution/fixtures/centos_6.7.json test/units/module_utils/facts/system/distribution/fixtures/centos_8_1.json test/units/module_utils/facts/system/distribution/fixtures/centos_stream_8.json test/units/module_utils/facts/system/distribution/fixtures/clearlinux_26580.json test/units/module_utils/facts/system/distribution/fixtures/clearlinux_28120.json test/units/module_utils/facts/system/distribution/fixtures/core_os_1911.5.0.json test/units/module_utils/facts/system/distribution/fixtures/core_os_976.0.0.json test/units/module_utils/facts/system/distribution/fixtures/cumulus_linux_2.5.4.json test/units/module_utils/facts/system/distribution/fixtures/cumulus_linux_3.7.3.json test/units/module_utils/facts/system/distribution/fixtures/debian_10.json test/units/module_utils/facts/system/distribution/fixtures/debian_7.9.json test/units/module_utils/facts/system/distribution/fixtures/debian_stretch_sid.json test/units/module_utils/facts/system/distribution/fixtures/deepin_20.4.json test/units/module_utils/facts/system/distribution/fixtures/devuan.json test/units/module_utils/facts/system/distribution/fixtures/dragonfly_5.2.2.json test/units/module_utils/facts/system/distribution/fixtures/dragonfly_5.6.2.json test/units/module_utils/facts/system/distribution/fixtures/eurolinux_8.5.json test/units/module_utils/facts/system/distribution/fixtures/fedora_22.json test/units/module_utils/facts/system/distribution/fixtures/fedora_25.json test/units/module_utils/facts/system/distribution/fixtures/fedora_31.json test/units/module_utils/facts/system/distribution/fixtures/flatcar_3139.2.0.json test/units/module_utils/facts/system/distribution/fixtures/kali_2019.1.json test/units/module_utils/facts/system/distribution/fixtures/kde_neon_16.04.json test/units/module_utils/facts/system/distribution/fixtures/kylin_linux_advanced_server_v10.json test/units/module_utils/facts/system/distribution/fixtures/linux_mint_18.2.json test/units/module_utils/facts/system/distribution/fixtures/linux_mint_19.1.json test/units/module_utils/facts/system/distribution/fixtures/lmde_6.json test/units/module_utils/facts/system/distribution/fixtures/miracle_linux_9.json test/units/module_utils/facts/system/distribution/fixtures/netbsd_8.2.json test/units/module_utils/facts/system/distribution/fixtures/nexenta_3.json test/units/module_utils/facts/system/distribution/fixtures/nexenta_4.json test/units/module_utils/facts/system/distribution/fixtures/omnios.json test/units/module_utils/facts/system/distribution/fixtures/openeuler_20.03.json test/units/module_utils/facts/system/distribution/fixtures/openindiana.json test/units/module_utils/facts/system/distribution/fixtures/opensuse-microos-20241205.json test/units/module_utils/facts/system/distribution/fixtures/opensuse_13.2.json test/units/module_utils/facts/system/distribution/fixtures/opensuse_leap_15.0.json test/units/module_utils/facts/system/distribution/fixtures/opensuse_leap_15.1.json test/units/module_utils/facts/system/distribution/fixtures/opensuse_leap_42.1.json test/units/module_utils/facts/system/distribution/fixtures/opensuse_tumbleweed_20160917.json test/units/module_utils/facts/system/distribution/fixtures/osmc.json test/units/module_utils/facts/system/distribution/fixtures/pardus_19.1.json test/units/module_utils/facts/system/distribution/fixtures/parrot_4.8.json test/units/module_utils/facts/system/distribution/fixtures/pop_os_20.04.json test/units/module_utils/facts/system/distribution/fixtures/redhat_6.7.json test/units/module_utils/facts/system/distribution/fixtures/redhat_7.2.json test/units/module_utils/facts/system/distribution/fixtures/redhat_7.7.json test/units/module_utils/facts/system/distribution/fixtures/rockylinux_8_3.json test/units/module_utils/facts/system/distribution/fixtures/sl-micro.json test/units/module_utils/facts/system/distribution/fixtures/sles_11.3.json test/units/module_utils/facts/system/distribution/fixtures/sles_11.4.json test/units/module_utils/facts/system/distribution/fixtures/sles_12_sp0.json test/units/module_utils/facts/system/distribution/fixtures/sles_12_sp1.json test/units/module_utils/facts/system/distribution/fixtures/sles_15_6.json test/units/module_utils/facts/system/distribution/fixtures/sles_16_0.json test/units/module_utils/facts/system/distribution/fixtures/sles_sap_15_6.json test/units/module_utils/facts/system/distribution/fixtures/sles_sap_16_0.json test/units/module_utils/facts/system/distribution/fixtures/smartos_global_zone.json test/units/module_utils/facts/system/distribution/fixtures/smartos_zone.json test/units/module_utils/facts/system/distribution/fixtures/smgl_na.json test/units/module_utils/facts/system/distribution/fixtures/solaris_10.json test/units/module_utils/facts/system/distribution/fixtures/solaris_11.3.json test/units/module_utils/facts/system/distribution/fixtures/solaris_11.4.json test/units/module_utils/facts/system/distribution/fixtures/solaris_11.json test/units/module_utils/facts/system/distribution/fixtures/steamos_2.0.json test/units/module_utils/facts/system/distribution/fixtures/tencentos_3_1.json test/units/module_utils/facts/system/distribution/fixtures/truenas_12.0rc1.json test/units/module_utils/facts/system/distribution/fixtures/ubuntu_10.04_guess.json test/units/module_utils/facts/system/distribution/fixtures/ubuntu_12.04.json test/units/module_utils/facts/system/distribution/fixtures/ubuntu_14.04.json test/units/module_utils/facts/system/distribution/fixtures/ubuntu_16.04.json test/units/module_utils/facts/system/distribution/fixtures/ubuntu_18.04.json test/units/module_utils/facts/system/distribution/fixtures/uos_20.json test/units/module_utils/facts/system/distribution/fixtures/virtuozzo_7.3.json test/units/module_utils/facts/virtual/__init__.py test/units/module_utils/facts/virtual/test_hpux.py test/units/module_utils/facts/virtual/test_linux.py test/units/module_utils/facts/virtual/test_sunos.py test/units/module_utils/facts/virtual/test_sysctl.py test/units/module_utils/json_utils/__init__.py test/units/module_utils/json_utils/test_filter_non_json_lines.py test/units/module_utils/parsing/test_convert_bool.py test/units/module_utils/urls/__init__.py test/units/module_utils/urls/test_RedirectHandlerFactory.py test/units/module_utils/urls/test_Request.py test/units/module_utils/urls/test_channel_binding.py test/units/module_utils/urls/test_fetch_file.py test/units/module_utils/urls/test_fetch_url.py test/units/module_utils/urls/test_generic_urlparse.py test/units/module_utils/urls/test_gzip.py test/units/module_utils/urls/test_prepare_multipart.py test/units/module_utils/urls/test_split.py test/units/module_utils/urls/test_urls.py test/units/module_utils/urls/fixtures/client.key test/units/module_utils/urls/fixtures/client.pem test/units/module_utils/urls/fixtures/client.txt test/units/module_utils/urls/fixtures/multipart.txt test/units/module_utils/urls/fixtures/netrc test/units/module_utils/urls/fixtures/cbt/ecdsa_sha256.pem test/units/module_utils/urls/fixtures/cbt/ecdsa_sha512.pem test/units/module_utils/urls/fixtures/cbt/rsa-pss_sha256.pem test/units/module_utils/urls/fixtures/cbt/rsa-pss_sha512.pem test/units/module_utils/urls/fixtures/cbt/rsa_md5.pem test/units/module_utils/urls/fixtures/cbt/rsa_sha.pem test/units/module_utils/urls/fixtures/cbt/rsa_sha1.pem test/units/module_utils/urls/fixtures/cbt/rsa_sha256.pem test/units/module_utils/urls/fixtures/cbt/rsa_sha384.pem test/units/module_utils/urls/fixtures/cbt/rsa_sha512.pem test/units/modules/__init__.py test/units/modules/conftest.py test/units/modules/mount_facts_data.py test/units/modules/test_apt.py test/units/modules/test_apt_key.py test/units/modules/test_async_wrapper.py test/units/modules/test_copy.py test/units/modules/test_debconf.py test/units/modules/test_get_url.py test/units/modules/test_hostname.py test/units/modules/test_iptables.py test/units/modules/test_known_hosts.py test/units/modules/test_mount_facts.py test/units/modules/test_pip.py test/units/modules/test_service.py test/units/modules/test_service_facts.py test/units/modules/test_systemd.py test/units/modules/test_unarchive.py test/units/modules/test_uri.py test/units/modules/utils.py test/units/parsing/__init__.py test/units/parsing/test_ajson.py test/units/parsing/test_dataloader.py test/units/parsing/test_mod_args.py test/units/parsing/test_splitter.py test/units/parsing/test_unquote.py test/units/parsing/fixtures/ajson.json test/units/parsing/fixtures/vault.yml test/units/parsing/utils/__init__.py test/units/parsing/utils/test_addresses.py test/units/parsing/utils/test_yaml.py test/units/parsing/vault/__init__.py test/units/parsing/vault/test_vault.py test/units/parsing/vault/test_vault_editor.py test/units/parsing/yaml/__init__.py test/units/parsing/yaml/test_dumper.py test/units/parsing/yaml/test_errors.py test/units/parsing/yaml/test_loader.py test/units/parsing/yaml/test_objects.py test/units/parsing/yaml/test_vault.py test/units/playbook/__init__.py test/units/playbook/test_attribute.py test/units/playbook/test_base.py test/units/playbook/test_block.py test/units/playbook/test_collectionsearch.py test/units/playbook/test_helpers.py test/units/playbook/test_included_file.py test/units/playbook/test_play.py test/units/playbook/test_play_context.py test/units/playbook/test_playbook.py test/units/playbook/test_taggable.py test/units/playbook/test_task.py test/units/playbook/role/__init__.py test/units/playbook/role/test_include_role.py test/units/playbook/role/test_role.py test/units/plugins/__init__.py test/units/plugins/test_plugins.py test/units/plugins/action/__init__.py test/units/plugins/action/test_action.py test/units/plugins/action/test_gather_facts.py test/units/plugins/action/test_raw.py test/units/plugins/action/test_reboot.py test/units/plugins/become/__init__.py test/units/plugins/become/conftest.py test/units/plugins/become/test_su.py test/units/plugins/become/test_sudo.py test/units/plugins/cache/__init__.py test/units/plugins/cache/test_cache.py test/units/plugins/callback/__init__.py test/units/plugins/callback/test_callback.py test/units/plugins/connection/__init__.py test/units/plugins/connection/test_connection.py test/units/plugins/connection/test_local.py test/units/plugins/connection/test_paramiko_ssh.py test/units/plugins/connection/test_psrp.py test/units/plugins/connection/test_ssh.py test/units/plugins/connection/test_winrm.py test/units/plugins/filter/__init__.py test/units/plugins/filter/test_core.py test/units/plugins/filter/test_mathstuff.py test/units/plugins/inventory/__init__.py test/units/plugins/inventory/test_constructed.py test/units/plugins/inventory/test_inventory.py test/units/plugins/loader_fixtures/__init__.py test/units/plugins/loader_fixtures/import_fixture.py test/units/plugins/lookup/__init__.py test/units/plugins/lookup/test_env.py test/units/plugins/lookup/test_ini.py test/units/plugins/lookup/test_password.py test/units/plugins/lookup/test_url.py test/units/plugins/shell/__init__.py test/units/plugins/shell/test_cmd.py test/units/plugins/shell/test_powershell.py test/units/plugins/strategy/__init__.py test/units/plugins/strategy/test_linear.py test/units/plugins/test/__init__.py test/units/plugins/test/dummy_vault.txt test/units/plugins/test/test_all.py test/units/plugins/test/test_core.py test/units/regex/test_invalid_var_names.py test/units/template/__init__.py test/units/template/test_template.py test/units/test_utils/__init__.py test/units/test_utils/controller/__init__.py test/units/test_utils/controller/display.py test/units/utils/__init__.py test/units/utils/conftest.py test/units/utils/test_cleanup_tmp_file.py test/units/utils/test_context_objects.py test/units/utils/test_datatag.py test/units/utils/test_display.py test/units/utils/test_encrypt.py test/units/utils/test_errors.py test/units/utils/test_helpers.py test/units/utils/test_isidentifier.py test/units/utils/test_json.py test/units/utils/test_listify.py test/units/utils/test_plugin_docs.py test/units/utils/test_serialization.py test/units/utils/test_serialization_profiles.py test/units/utils/test_shlex.py test/units/utils/test_vars.py test/units/utils/test_version.py test/units/utils/collection_loader/__init__.py test/units/utils/collection_loader/test_collection_loader.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/ansible/builtin/plugins/modules/shouldnotload.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/meta/runtime.yml test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/action/my_action.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/module_utils/__init__.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/module_utils/my_other_util.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/module_utils/my_util.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/modules/__init__.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/plugins/modules/amodule.py test/units/utils/collection_loader/fixtures/collections/ansible_collections/testns/testcoll/roles/some_role/.gitkeep test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/__init__.py test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/ansible/__init__.py test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/testns/__init__.py test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/testns/testcoll/__init__.py test/units/utils/collection_loader/fixtures/collections_masked/ansible_collections/testns/testcoll2/__init__.py test/units/utils/collection_loader/fixtures/playbook_path/collections/ansible_collections/ansible/playbook_adj_other/.gitkeep test/units/utils/collection_loader/fixtures/playbook_path/collections/ansible_collections/freshns/playbook_adj_other/.gitkeep test/units/utils/collection_loader/fixtures/playbook_path/collections/ansible_collections/testns/playbook_adj_other/.gitkeep test/units/utils/display/test_broken_cowsay.py test/units/utils/display/test_curses.py test/units/utils/display/test_display.py test/units/utils/display/test_logger.py test/units/utils/display/test_warning.py test/units/utils/expected_serialization_profiles/cache_persistence.txt test/units/utils/expected_serialization_profiles/fallback_to_str.txt test/units/utils/expected_serialization_profiles/inventory_legacy.txt test/units/utils/expected_serialization_profiles/legacy.txt test/units/utils/expected_serialization_profiles/module_legacy_c2m.txt test/units/utils/expected_serialization_profiles/module_legacy_m2c.txt test/units/utils/expected_serialization_profiles/module_modern_c2m.txt test/units/utils/expected_serialization_profiles/module_modern_m2c.txt test/units/utils/expected_serialization_profiles/tagless.txt test/units/vars/__init__.py test/units/vars/test_module_response_deepcopy.py test/units/vars/test_variable_manager.pyansible_core-2.19.0b5/ansible_core.egg-info/dependency_links.txt0000644000000000000000000000000115017704211023400 0ustar00rootroot ansible_core-2.19.0b5/ansible_core.egg-info/entry_points.txt0000644000000000000000000000070315017704211022630 0ustar00rootroot[console_scripts] ansible = ansible.cli.adhoc:main ansible-config = ansible.cli.config:main ansible-console = ansible.cli.console:main ansible-doc = ansible.cli.doc:main ansible-galaxy = ansible.cli.galaxy:main ansible-inventory = ansible.cli.inventory:main ansible-playbook = ansible.cli.playbook:main ansible-pull = ansible.cli.pull:main ansible-test = ansible_test._util.target.cli.ansible_test_cli_stub:main ansible-vault = ansible.cli.vault:main ansible_core-2.19.0b5/ansible_core.egg-info/requires.txt0000644000000000000000000000011215017704211021724 0ustar00rootrootjinja2>=3.1.0 PyYAML>=5.1 cryptography packaging resolvelib<2.0.0,>=0.5.3 ansible_core-2.19.0b5/ansible_core.egg-info/top_level.txt0000644000000000000000000000002515017704211022061 0ustar00rootrootansible ansible_test ansible_core-2.19.0b5/changelogs/0000755000000000000000000000000015017704211015325 5ustar00rootrootansible_core-2.19.0b5/changelogs/CHANGELOG-v2.19.rst0000644000000000000000000014637015017704211020136 0ustar00rootroot================================================================== ansible-core 2.19 "What Is and What Should Never Be" Release Notes ================================================================== .. contents:: Topics v2.19.0b5 ========= Release Summary --------------- | Release Date: 2025-06-03 | `Porting Guide `__ Minor Changes ------------- - Improved SUSE distribution detection in distribution.py by parsing VARIANT_ID from /etc/os-release for identifying SLES_SAP and SL-Micro. Falls back to /etc/products.d/baseproduct symlink for older systems. - Remove unnecessary shebang from the ``hostname`` module. - Use ``importlib.metadata.version()`` to detect Jinja version as jinja2.__version__ is deprecated and will be removed in Jinja 3.3. - ansible-doc - Return dynamic stub when reporting on Jinja filters and tests not explicitly documented in Ansible - ansible-doc - Skip listing the internal ``ansible._protomatter`` plugins unless explicitly requested - ansible-test - Add RHEL 10.0 as a remote platform for testing. - apt_repository - remove Python 2 support - csvfile lookup - remove Python 2 compat - display - Add ``help_text`` and ``obj`` to ``Display.error_as_warning``. - display - Replace Windows newlines (``\r\n``) in display output with Unix newlines (``\n``). This ensures proper display of strings sourced from Windows hosts in environments which treat ``\r`` as ``\n``, such as Azure Pipelines. - facts - add "Linode" for Linux VM in virtual facts - module_utils - Add ``AnsibleModule.error_as_warning``. - module_utils - Add ``ansible.module_utils.common.warnings.error_as_warning``. - module_utils - Add optional ``help_text`` argument to ``AnsibleModule.warn``. - ssh agent - Added ``SSH_AGENT_EXECUTABLE`` config to allow override of ssh-agent. - ssh connection plugin - Added ``verbosity`` config to decouple SSH debug output verbosity from Ansible verbosity. Previously, the Ansible verbosity value was always applied to the SSH client command-line, leading to excessively verbose output. Set the ``ANSIBLE_SSH_VERBOSITY`` envvar or ``ansible_ssh_verbosity`` Ansible variable to a positive integer to increase SSH client verbosity. - task timeout - Specifying a timeout greater than 100,000,000 now results in an error. - templating - Added ``_ANSIBLE_TEMPLAR_SANDBOX_MODE=allow_unsafe_attributes`` environment variable to disable Jinja template attribute sandbox. (https://github.com/ansible/ansible/issues/85202) - windows - Added support for ``#AnsibleRequires -Wrapper`` to request a PowerShell module be run through the execution wrapper scripts without any module utils specified. - windows - Added support for running signed modules and scripts with a Windows host protected by Windows App Control/WDAC. This is a tech preview and the interface may be subject to change. - windows - Script modules will preserve UTF-8 encoding when executing the script. Deprecated Features ------------------- - The ``ShellModule.checksum`` method is now deprecated and will be removed in ansible-core 2.23. Use ``ActionBase._execute_remote_stat()`` instead. - The ``ansible.module_utils.common.collections.count()`` function is deprecated and will be removed in ansible-core 2.23. Use ``collections.Counter()`` from the Python standard library instead. - ``ansible.compat.importlib_resources`` is deprecated and will be removed in ansible-core 2.23. Use ``importlib.resources`` from the Python standard library instead. Bugfixes -------- - Core Jinja test plugins - Builtin test plugins now always return ``bool`` to avoid spurious deprecation warnings for some malformed inputs. - ansible-test - Disabled the ``bad-super-call`` pylint rule due to false positives. - ansible-test - Fix incorrect handling of options with optional args (e.g. ``--color``), when followed by other options which are omitted during arg filtering (e.g. ``--docker``). Previously it was possible for non-option arguments to be incorrectly omitted in these cases. (https://github.com/ansible/ansible/issues/85173) - ansible-test - Improve type inference for pylint deprecated checks to accommodate some type annotations. - async_status module - The ``started`` and ``finished`` return values are now ``True`` or ``False`` instead of ``1`` or ``0``. - constructed inventory - Use the ``default_value`` or ``trailing_separator`` in a ``keyed_groups`` entry if the expression result of ``key`` is ``None`` and not just an empty string. - dnf5 - handle all libdnf5 specific exceptions (https://github.com/ansible/ansible/issues/84634) - error handling - Error details and tracebacks from connection and built-in action exceptions are preserved. Previously, much of the detail was lost or mixed into the error message. - from_yaml_all filter - `None` and empty string inputs now always return an empty list. Previously, `None` was returned in Jinja native mode and empty list in classic mode. - local connection plugin - The command-line used to create subprocesses is now always ``str`` to avoid issues with debuggers and profilers. - ssh agent - Fixed several potential startup hangs for badly-behaved or overloaded ssh agents. - task timeout - Specifying a negative task timeout now results in an error. v2.19.0b4 ========= Release Summary --------------- | Release Date: 2025-05-12 | `Porting Guide `__ Minor Changes ------------- - facts - add "CloudStack KVM Hypervisor" for Linux VM in virtual facts (https://github.com/ansible/ansible/issues/85089). - modules - use ``AnsibleModule.warn`` instead of passing ``warnings`` to ``exit_json`` or ``fail_json`` which is deprecated. Bugfixes -------- - ansible-test - Updated the ``pylint`` sanity test to skip some deprecation validation checks when all arguments are dynamic. - config - Preserve or apply Origin tag to values returned by config. - config - Prevented fatal errors when ``MODULE_IGNORE_EXTS`` configuration was set. - config - Templating failures on config defaults now issue a warning. Previously, failures silently returned an unrendered and untrusted template to the caller. - config - ``ensure_type`` correctly propagates trust and other tags on returned values. - config - ``ensure_type`` now converts mappings to ``dict`` when requested, instead of returning the mapping. - config - ``ensure_type`` now converts sequences to ``list`` when requested, instead of returning the sequence. - config - ``ensure_type`` now correctly errors when ``pathlist`` or ``pathspec`` types encounter non-string list items. - config - ``ensure_type`` now reports an error when ``bytes`` are provided for any known ``value_type``. Previously, the behavior was undefined, but often resulted in an unhandled exception or incorrect return type. - config - ``ensure_type`` with expected type ``int`` now properly converts ``True`` and ``False`` values to ``int``. Previously, these values were silently returned unmodified. - convert_bool.boolean API conversion function - Unhashable values passed to ``boolean`` behave like other non-boolean convertible values, returning False or raising ``TypeError`` depending on the value of ``strict``. Previously, unhashable values always raised ``ValueError`` due to an invalid set membership check. - dnf5 - when ``bugfix`` and/or ``security`` is specified, skip packages that do not have any such updates, even for new versions of libdnf5 where this functionality changed and it is considered failure - plugin loader - Apply template trust to strings loaded from plugin configuration definitions and doc fragments. - template action - Template files where the entire file's output renders as ``None`` are no longer emitted as the string "None", but instead render to an empty file as in previous releases. v2.19.0b3 ========= Release Summary --------------- | Release Date: 2025-05-06 | `Porting Guide `__ Minor Changes ------------- - ansible-config will now show internal, but not test configuration entries. This allows for debugging but still denoting the configurations as internal use only (_ prefix). - ansible-test - Improved ``pylint`` checks for Ansible-specific deprecation functions. - ansible-test - Use the ``-t`` option to set the stop timeout when stopping a container. This avoids use of the ``--time`` option which was deprecated in Docker v28.0. - collection metadata - The collection loader now parses scalar values from ``meta/runtime.yml`` as strings. This avoids issues caused by unquoted values such as versions or dates being parsed as types other than strings. - deprecation warnings - Deprecation warning APIs automatically capture the identity of the deprecating plugin. The ``collection_name`` argument is only required to correctly attribute deprecations that occur in module_utils or other non-plugin code. - deprecation warnings - Improved deprecation messages to more clearly indicate the affected content, including plugin name when available. - deprecations - Collection name strings not of the form ``ns.coll`` passed to deprecation API functions will result in an error. - deprecations - Removed support for specifying deprecation dates as a ``datetime.date``, which was included in an earlier 2.19 pre-release. - deprecations - Some argument names to ``deprecate_value`` for consistency with existing APIs. An earlier 2.19 pre-release included a ``removal_`` prefix on the ``date`` and ``version`` arguments. - modules - The ``AnsibleModule.deprecate`` function no longer sends deprecation messages to the target host's logging system. Deprecated Features ------------------- - Passing a ``warnings` or ``deprecations`` key to ``exit_json`` or ``fail_json`` is deprecated. Use ``AnsibleModule.warn`` or ``AnsibleModule.deprecate`` instead. - plugins - Accessing plugins with ``_``-prefixed filenames without the ``_`` prefix is deprecated. Bugfixes -------- - Ansible will now ensure predictable permissions on remote artifacts, until now it only ensured executable and relied on system masks for the rest. - dnf5 - avoid generating excessive transaction entries in the dnf5 history (https://github.com/ansible/ansible/issues/85046) v2.19.0b2 ========= Release Summary --------------- | Release Date: 2025-04-24 | `Porting Guide `__ Minor Changes ------------- - comment filter - Improve the error message shown when an invalid ``style`` argument is provided. Bugfixes -------- - Remove use of `required` parameter in `get_bin_path` which has been deprecated. - ansible-doc - fix indentation for first line of descriptions of suboptions and sub-return values (https://github.com/ansible/ansible/pull/84690). - ansible-doc - fix line wrapping for first line of description of options and return values (https://github.com/ansible/ansible/pull/84690). v2.19.0b1 ========= Release Summary --------------- | Release Date: 2025-04-14 | `Porting Guide `__ Major Changes ------------- - Jinja plugins - Jinja builtin filter and test plugins are now accessible via their fully-qualified names ``ansible.builtin.{name}``. - Task Execution / Forks - Forks no longer inherit stdio from the parent ``ansible-playbook`` process. ``stdout``, ``stderr``, and ``stdin`` within a worker are detached from the terminal, and non-functional. All needs to access stdio from a fork for controller side plugins requires use of ``Display``. - ansible-test - Packages beneath ``module_utils`` can now contain ``__init__.py`` files. - variables - The type system underlying Ansible's variable storage has been significantly overhauled and formalized. Attempts to store unsupported Python object types in variables now more consistently yields early warnings or errors. - variables - To support new Ansible features, many variable objects are now represented by subclasses of their respective native Python types. In most cases, they behave indistinguishably from their original types, but some Python libraries do not handle builtin object subclasses properly. Custom plugins that interact with such libraries may require changes to convert and pass the native types. Minor Changes ------------- - Added a -vvvvv log message indicating when a host fails to produce output within the timeout period. - AnsibleModule.uri - Add option ``multipart_encoding`` for ``form-multipart`` files in body to change default base64 encoding for files - INVENTORY_IGNORE_EXTS config, removed ``ini`` from the default list, inventory scripts using a corresponding .ini configuration are rare now and inventory.ini files are more common. Those that need to ignore the ini files for inventory scripts can still add it to configuration. - Jinja plugins - Plugins can declare support for undefined values. - Jinja2 version 3.1.0 or later is now required on the controller. - Move ``follow_redirects`` parameter to module_utils so external modules can reuse it. - PlayIterator - do not return tasks from already executed roles so specific strategy plugins do not have to do the filtering of such tasks themselves - SSH Escalation-related -vvv log messages now include the associated host information. - Windows - Add support for Windows Server 2025 to Ansible and as an ``ansible-test`` remote target - https://github.com/ansible/ansible/issues/84229 - Windows - refactor the async implementation to better handle errors during bootstrapping and avoid WMI when possible. - ``ansible-galaxy collection install`` — the collection dependency resolver now prints out conflicts it hits during dependency resolution when it's taking too long and it ends up backtracking a lot. It also displays suggestions on how to help it compute the result more quickly. - ansible, ansible-console, ansible-pull - add --flush-cache option (https://github.com/ansible/ansible/issues/83749). - ansible-galaxy - Add support for Keycloak service accounts - ansible-galaxy - support ``resolvelib >= 0.5.3, < 2.0.0`` (https://github.com/ansible/ansible/issues/84217). - ansible-test - Added a macOS 15.3 remote VM, replacing 14.3. - ansible-test - Automatically retry HTTP GET/PUT/DELETE requests on exceptions. - ansible-test - Default to Python 3.13 in the ``base`` and ``default`` containers. - ansible-test - Disable the ``deprecated-`` prefixed ``pylint`` rules as their results vary by Python version. - ansible-test - Disable the ``pep8`` sanity test rules ``E701`` and ``E704`` to improve compatibility with ``black``. - ansible-test - Improve container runtime probe error handling. When unexpected probe output is encountered, an error with more useful debugging information is provided. - ansible-test - Replace container Alpine 3.20 with 3.21. - ansible-test - Replace container Fedora 40 with 41. - ansible-test - Replace remote Alpine 3.20 with 3.21. - ansible-test - Replace remote Fedora 40 with 41. - ansible-test - Replace remote FreeBSD 13.3 with 13.5. - ansible-test - Replace remote FreeBSD 14.1 with 14.2. - ansible-test - Replace remote RHEL 9.4 with 9.5. - ansible-test - Show a more user-friendly error message when a ``runme.sh`` script is not executable. - ansible-test - The ``yamllint`` sanity test now enforces string values for the ``!vault`` tag. - ansible-test - Update ``nios-test-container`` to version 7.0.0. - ansible-test - Update ``pylint`` sanity test to use version 3.3.1. - ansible-test - Update distro containers to remove unnecessary pakages (apache2, subversion, ruby). - ansible-test - Update sanity test requirements to latest available versions. - ansible-test - Update the HTTP test container. - ansible-test - Update the PyPI test container. - ansible-test - Update the ``base`` and ``default`` containers. - ansible-test - Update the utility container. - ansible-test - Use Python's ``urllib`` instead of ``curl`` for HTTP requests. - ansible-test - When detection of the current container network fails, a warning is now issued and execution continues. This simplifies usage in cases where the current container cannot be inspected, such as when running in GitHub Codespaces. - ansible-test acme test container - bump `version to 2.3.0 `__ to include newer versions of Pebble, dependencies, and runtimes. This adds support for ACME profiles, ``dns-account-01`` support, and some smaller improvements (https://github.com/ansible/ansible/pull/84547). - apt_key module - add notes to docs and errors to point at the CLI tool deprecation by Debian and alternatives - apt_repository module - add notes to errors to point at the CLI tool deprecation by Debian and alternatives - become plugins get new property 'pipelining' to show support or lack there of for the feature. - callback plugins - add has_option() to CallbackBase to match other functions overloaded from AnsiblePlugin - callback plugins - fix get_options() for CallbackBase - copy - fix sanity test failures (https://github.com/ansible/ansible/pull/83643). - copy - parameter ``local_follow`` was incorrectly documented as having default value ``True`` (https://github.com/ansible/ansible/pull/83643). - cron - Provide additional error information while writing cron file (https://github.com/ansible/ansible/issues/83223). - csvfile - let the config system do the typecasting (https://github.com/ansible/ansible/pull/82263). - display - Deduplication of warning and error messages considers the full content of the message (including source and traceback contexts, if enabled). This may result in fewer messages being omitted. - distribution - Added openSUSE MicroOS to Suse OS family (#84685). - dnf5, apt - add ``auto_install_module_deps`` option (https://github.com/ansible/ansible/issues/84206) - docs - add collection name in message from which the module is being deprecated (https://github.com/ansible/ansible/issues/84116). - env lookup - The error message generated for a missing environment variable when ``default`` is an undefined value (e.g. ``undef('something')``) will contain the hint from that undefined value, except when the undefined value is the default of ``undef()`` with no arguments. Previously, any existing undefined hint would be ignored. - file - enable file module to disable diff_mode (https://github.com/ansible/ansible/issues/80817). - file - make code more readable and simple. - filter - add support for URL-safe encoding and decoding in b64encode and b64decode (https://github.com/ansible/ansible/issues/84147). - find - add a checksum_algorithm parameter to specify which type of checksum the module will return - from_json filter - The filter accepts a ``profile`` argument, which defaults to ``tagless``. - handlers - Templated handler names with syntax errors, or that resolve to ``omit`` are now skipped like handlers with undefined variables in their name. - improved error message for yaml parsing errors in plugin documentation - local connection plugin - A new ``become_strip_preamble`` config option (default True) was added; disable to preserve diagnostic ``become`` output in task results. - local connection plugin - A new ``become_success_timeout`` operation-wide timeout config (default 10s) was added for ``become``. - local connection plugin - When a ``become`` plugin's ``prompt`` value is a non-string after the ``check_password_prompt`` callback has completed, no prompt stripping will occur on stderr. - lookup_template - add an option to trim blocks while templating (https://github.com/ansible/ansible/issues/75962). - module - set ipv4 and ipv6 rules simultaneously in iptables module (https://github.com/ansible/ansible/issues/84404). - module_utils - Add ``NoReturn`` type annotations to functions which never return. - modules - PowerShell modules can now receive ``datetime.date``, ``datetime.time`` and ``datetime.datetime`` values as ISO 8601 strings. - modules - PowerShell modules can now receive strings sourced from inline vault-encrypted strings. - modules - Unhandled exceptions during Python module execution are now returned as structured data from the target. This allows the new traceback handling to be applied to exceptions raised on targets. - pipelining logic has mostly moved to connection plugins so they can decide/override settings. - plugin error handling - When raising exceptions in an exception handler, be sure to use ``raise ... from`` as appropriate. This supersedes the use of the ``AnsibleError`` arg ``orig_exc`` to represent the cause. Specifying ``orig_exc`` as the cause is still permitted. Failure to use ``raise ... from`` when ``orig_exc`` is set will result in a warning. Additionally, if the two cause exceptions do not match, a warning will be issued. - removed harcoding of su plugin as it now works with pipelining. - runtime-metadata sanity test - improve validation of ``action_groups`` (https://github.com/ansible/ansible/pull/83965). - service_facts module got freebsd support added. - ssh connection plugin - Support ``SSH_ASKPASS`` mechanism to provide passwords, making it the default, but still offering an explicit choice to use ``sshpass`` (https://github.com/ansible/ansible/pull/83936) - ssh connection plugin now overrides pipelining when a tty is requested. - ssh-agent - ``ansible``, ``ansible-playbook`` and ``ansible-console`` are capable of spawning or reusing an ssh-agent, allowing plugins to interact with the ssh-agent. Additionally a pure python ssh-agent client has been added, enabling easy interaction with the agent. The ssh connection plugin contains new functionality via ``ansible_ssh_private_key`` and ``ansible_ssh_private_key_passphrase``, for loading an SSH private key into the agent from a variable. - templating - Access to an undefined variable from inside a lookup, filter, or test (which raises MarkerError) no longer ends processing of the current template. The triggering undefined value is returned as the result of the offending plugin invocation, and the template continues to execute. - templating - Embedding ``range()`` values in containers such as lists will result in an error on use. Previously the value would be converted to a string representing the range parameters, such as ``range(0, 3)``. - templating - Handling of omitted values is now a first-class feature of the template engine, and is usable in all Ansible Jinja template contexts. Any template that resolves to ``omit`` is automatically removed from its parent container during templating. - templating - Template evaluation is lazier than in previous versions. Template expressions which resolve only portions of a data structure no longer result in the entire structure being templated. - templating - Templating errors now provide more information about both the location and context of the error, especially for deeply-nested and/or indirected templating scenarios. - templating - Unified ``omit`` behavior now requires that plugins calling ``Templar.template()`` handle cases where the entire template result is omitted, by catching the ``AnsibleValueOmittedError`` that is raised. Previously, this condition caused a randomly-generated string marker to appear in the template result. - templating - Variables of type ``set`` and ``tuple`` are now converted to ``list`` when exiting the final pass of templating. - to_json / to_nice_json filters - The filters accept a ``profile`` argument, which defaults to ``tagless``. - troubleshooting - Tracebacks can be collected and displayed for most errors, warnings, and deprecation warnings (including those generated by modules). Tracebacks are no longer enabled with ``-vvv``; the behavior is directly configurable via the ``DISPLAY_TRACEBACK`` config option. Module tracebacks passed to ``fail_json`` via the ``exception`` kwarg will not be included in the task result unless error tracebacks are configured. - undef jinja function - The ``undef`` jinja function now raises an error if a non-string hint is given. Attempting to use an undefined hint also results in an error, ensuring incorrect use of the function can be distinguished from the function's normal behavior. - validate-modules sanity test - make sure that ``module`` and ``plugin`` ``seealso`` entries use FQCNs (https://github.com/ansible/ansible/pull/84325). - vault - improved vault filter documentation by adding missing example content for dump_template_data.j2, refining examples for clarity, and ensuring variable consistency (https://github.com/ansible/ansible/issues/83583). - warnings - All warnings (including deprecation warnings) issued during a task's execution are now accessible via the ``warnings`` and ``deprecations`` keys on the task result. - when the ``dict`` lookup is given a non-dict argument, show the value of the argument and its type in the error message. - windows - add hard minimum limit for PowerShell to 5.1. Ansible dropped support for older versions of PowerShell in the 2.16 release but this reqirement is now enforced at runtime. - windows - refactor windows exec runner to improve efficiency and add better error reporting on failures. - winrm - Remove need for pexpect on macOS hosts when using ``kinit`` to retrieve the Kerberos TGT. By default the code will now only use the builtin ``subprocess`` library which should handle issues with select and a high fd count and also simplify the code. Breaking Changes / Porting Guide -------------------------------- - Support for the ``toml`` library has been removed from TOML inventory parsing and dumping. Use ``tomli`` for parsing on Python 3.10. Python 3.11 and later have built-in support for parsing. Use ``tomli-w`` to support outputting inventory in TOML format. - assert - The ``quiet`` argument must be a commonly-accepted boolean value. Previously, unrecognized values were silently treated as False. - conditionals - Conditional expressions that result in non-boolean values are now an error by default. Such results often indicate unintentional use of templates where they are not supported, resulting in a conditional that is always true. When this option is enabled, conditional expressions which are a literal ``None`` or empty string will evaluate as true, for backwards compatibility. The error can be temporarily changed to a deprecation warning by enabling the ``ALLOW_BROKEN_CONDITIONALS`` config option. - first_found lookup - When specifying ``files`` or ``paths`` as a templated list containing undefined values, the undefined list elements will be discarded with a warning. Previously, the entire list would be discarded without any warning. - internals - The ``AnsibleLoader`` and ``AnsibleDumper`` classes for working with YAML are now factory functions and cannot be extended. - internals - The ``ansible.utils.native_jinja`` Python module has been removed. - inventory - Invalid variable names provided by inventories result in an inventory parse failure. This behavior is now consistent with other variable name usages throughout Ansible. - lookup plugins - Lookup plugins called as `with_(lookup)` will no longer have the `_subdir` attribute set. - lookup plugins - ``terms`` will always be passed to ``run`` as the first positional arg, where previously it was sometimes passed as a keyword arg when using ``with_`` syntax. - loops - Omit placeholders no longer leak between loop item templating and task templating. Previously, ``omit`` placeholders could remain embedded in loop items after templating and be used as an ``omit`` for task templating. Now, values resolving to ``omit`` are dropped immediately when loop items are templated. To turn missing values into an ``omit`` for task templating, use ``| default(omit)``. This solution is backward-compatible with previous versions of ansible-core. - modules - Ansible modules using ``sys.excepthook`` must use a standard ``try/except`` instead. - plugins - Any plugin that sources or creates templates must properly tag them as trusted. - plugins - Custom Jinja plugins that accept undefined top-level arguments must opt in to receiving them. - plugins - Custom Jinja plugins that use ``environment.getitem`` to retrieve undefined values will now trigger a ``MarkerError`` exception. This exception must be handled to allow the plugin to return a ``Marker``, or the plugin must opt-in to accepting ``Marker`` values. - public API - The ``ansible.vars.fact_cache.FactCache`` wrapper has been removed. - serialization of ``omit`` sentinel - Serialization of variables containing ``omit`` sentinels (e.g., by the ``to_json`` and ``to_yaml`` filters or ``ansible-inventory``) will fail if the variable has not completed templating. Previously, serialization succeeded with placeholder strings emitted in the serialized output. - set_fact - The string values "yes", "no", "true" and "false" were previously converted (ignoring case) to boolean values when not using Jinja2 native mode. Since Jinja2 native mode is always used, this conversion no longer occurs. When boolean values are required, native boolean syntax should be used where variables are defined, such as in YAML. When native boolean syntax is not an option, the ``bool`` filter can be used to parse string values into booleans. - template lookup - The ``convert_data`` option is deprecated and no longer has any effect. Use the ``from_json`` filter on the lookup result instead. - templating - Access to ``_`` prefixed attributes and methods, and methods with known side effects, is no longer permitted. In cases where a matching mapping key is present, the associated value will be returned instead of an error. This increases template environment isolation and ensures more consistent behavior between the ``.`` and ``[]`` operators. - templating - Conditionals and lookups which use embedded inline templates in Jinja string constants now display a warning. These templates should be converted to their expression equivalent. - templating - Many Jinja plugins (filters, lookups, tests) and methods previously silently ignored undefined inputs, which often masked subtle errors. Passing an undefined argument to a Jinja plugin or method that does not declare undefined support now results in an undefined value. - templating - Templates are always rendered in Jinja2 native mode. As a result, non-string values are no longer automatically converted to strings. - templating - Templates resulting in ``None`` are no longer automatically converted to an empty string. - templating - Templates with embedded inline templates that were not contained within a Jinja string constant now result in an error, as support for multi-pass templating was removed for security reasons. In most cases, such templates can be easily rewritten to avoid the use of embedded inline templates. - templating - The ``allow_unsafe_lookups`` option no longer has any effect. Lookup plugins are responsible for tagging strings containing templates to allow evaluation as a template. - templating - The result of the ``range()`` global function cannot be returned from a template- it should always be passed to a filter (e.g., ``random``). Previously, range objects returned from an intermediate template were always converted to a list, which is inconsistent with inline consumption of range objects. - templating - ``#jinja2:`` overrides in templates with invalid override names or types are now templating errors. Deprecated Features ------------------- - CLI - The ``--inventory-file`` option alias is deprecated. Use the ``-i`` or ``--inventory`` option instead. - Stategy Plugins - Use of strategy plugins not provided in ``ansible.builtin`` are deprecated and do not carry any backwards compatibility guarantees going forward. A future release will remove the ability to use external strategy plugins. No alternative for third party strategy plugins is currently planned. - ``ansible.module_utils.compat.datetime`` - The datetime compatibility shims are now deprecated. They are scheduled to be removed in ``ansible-core`` v2.21. This includes ``UTC``, ``utcfromtimestamp()`` and ``utcnow`` importable from said module (https://github.com/ansible/ansible/pull/81874). - bool filter - Support for coercing unrecognized input values (including None) has been deprecated. Consult the filter documentation for acceptable values, or consider use of the ``truthy`` and ``falsy`` tests. - cache plugins - The `ansible.plugins.cache.base` Python module is deprecated. Use `ansible.plugins.cache` instead. - callback plugins - The `v2_on_any` callback method is deprecated. Use specific callback methods instead. - callback plugins - The v1 callback API (callback methods not prefixed with `v2_`) is deprecated. Use `v2_` prefixed methods instead. - conditionals - Conditionals using Jinja templating delimiters (e.g., ``{{``, ``{%``) should be rewritten as expressions without delimiters, unless the entire conditional value is a single template that resolves to a trusted string expression. This is useful for dynamic indirection of conditional expressions, but is limited to trusted literal string expressions. - config - The ``ACTION_WARNINGS`` config has no effect. It previously disabled command warnings, which have since been removed. - config - The ``DEFAULT_JINJA2_NATIVE`` option has no effect. Jinja2 native mode is now the default and only option. - config - The ``DEFAULT_NULL_REPRESENTATION`` option has no effect. Null values are no longer automatically converted to another value during templating of single variable references. - display - The ``Display.get_deprecation_message`` method has been deprecated. Call ``Display.deprecated`` to display a deprecation message, or call it with ``removed=True`` to raise an ``AnsibleError``. - file loading - Loading text files with ``DataLoader`` containing data that cannot be decoded under the expected encoding is deprecated. In most cases the encoding must be UTF-8, although some plugins allow choosing a different encoding. Previously, invalid data was silently wrapped in Unicode surrogate escape sequences, often resulting in later errors or other data corruption. - first_found lookup - Splitting of file paths on ``,;:`` is deprecated. Pass a list of paths instead. The ``split`` method on strings can be used to split variables into a list as needed. - interpreter discovery - The ``auto_legacy`` and ``auto_legacy_silent`` options for ``INTERPRETER_PYTHON`` are deprecated. Use ``auto`` or ``auto_silent`` options instead, as they have the same effect. - oneline callback - The ``oneline`` callback and its associated ad-hoc CLI args (``-o``, ``--one-line``) are deprecated. - paramiko - The paramiko connection plugin has been deprecated with planned removal in 2.21. - playbook variables - The ``play_hosts`` variable has been deprecated, use ``ansible_play_batch`` instead. - plugin error handling - The ``AnsibleError`` constructor arg ``suppress_extended_error`` is deprecated. Using ``suppress_extended_error=True`` has the same effect as ``show_content=False``. - template lookup - The jinja2_native option is no longer used in the Ansible Core code base. Jinja2 native mode is now the default and only option. - templating - Support for enabling Jinja2 extensions (not plugins) has been deprecated. - templating - The ``ansible_managed`` variable available for certain templating scenarios, such as the ``template`` action and ``template`` lookup has been deprecated. Define and use a custom variable instead of relying on ``ansible_managed``. - templating - The ``disable_lookups`` option has no effect, since plugins must be updated to apply trust before any templating can be performed. - to_yaml/to_nice_yaml filters - Implicit YAML dumping of vaulted value ciphertext is deprecated. Set `dump_vault_tags` to explicitly specify the desired behavior. - tree callback - The ``tree`` callback and its associated ad-hoc CLI args (``-t``, ``--tree``) are deprecated. Removed Features (previously deprecated) ---------------------------------------- - Remove deprecated plural form of collection path (https://github.com/ansible/ansible/pull/84156). - Removed deprecated STRING_CONVERSION_ACTION (https://github.com/ansible/ansible/issues/84220). - encrypt - passing unsupported passlib hashtype now raises AnsibleFilterError. - manager - remove deprecated include_delegate_to parameter from get_vars API. - modules - Modules returning non-UTF8 strings now result in an error. The ``MODULE_STRICT_UTF8_RESPONSE`` setting can be used to disable this check. - removed deprecated pycompat24 and compat.importlib. - selector - remove deprecated compat.selector related files (https://github.com/ansible/ansible/pull/84155). - windows - removed common module functions ``ConvertFrom-AnsibleJson``, ``Format-AnsibleException`` from Windows modules as they are not used and add uneeded complexity to the code. Security Fixes -------------- - include_vars action - Ensure that result masking is correctly requested when vault-encrypted files are read. (CVE-2024-8775) - task result processing - Ensure that action-sourced result masking (``_ansible_no_log=True``) is preserved. (CVE-2024-8775) - templating - Ansible's template engine no longer processes Jinja templates in strings unless they are marked as coming from a trusted source. Untrusted strings containing Jinja template markers are ignored with a warning. Examples of trusted sources include playbooks, vars files, and many inventory sources. Examples of untrusted sources include module results and facts. Plugins which have not been updated to preserve trust while manipulating strings may inadvertently cause them to lose their trusted status. - templating - Changes to conditional expression handling removed numerous instances of insecure multi-pass templating (which could result in execution of untrusted template expressions). - user action won't allow ssh-keygen, chown and chmod to run on existing ssh public key file, avoiding traversal on existing symlinks (CVE-2024-9902). Bugfixes -------- - Ansible will now also warn when reserved keywords are set via a module (set_fact, include_vars, etc). - Ansible.Basic - Fix ``required_if`` check when the option value to check is unset or set to null. - Correctly return ``False`` when using the ``filter`` and ``test`` Jinja tests on plugin names which are not filters or tests, respectively. (resolves issue https://github.com/ansible/ansible/issues/82084) - Do not run implicit ``flush_handlers`` meta tasks when the whole play is excluded from the run due to tags specified. - Errors now preserve stacked error messages even when YAML is involved. - Fix a display.debug statement with the wrong param in _get_diff_data() method - Fix disabling SSL verification when installing collections and roles from git repositories. If ``--ignore-certs`` isn't provided, the value for the ``GALAXY_IGNORE_CERTS`` configuration option will be used (https://github.com/ansible/ansible/issues/83326). - Fix ipv6 pattern bug in lib/ansible/parsing/utils/addresses.py (https://github.com/ansible/ansible/issues/84237) - Fix returning 'unreachable' for the overall task result. This prevents false positives when a looped task has unignored unreachable items (https://github.com/ansible/ansible/issues/84019). - Implicit ``meta: flush_handlers`` tasks now have a parent block to prevent potential tracebacks when calling methods like ``get_play()`` on them internally. - Improve performance on large inventories by reducing the number of implicit meta tasks. - Jinja plugins - Errors raised will always be derived from ``AnsibleTemplatePluginError``. - Optimize the way tasks from within ``include_tasks``/``include_role`` are inserted into the play. - Time out waiting on become is an unreachable error (https://github.com/ansible/ansible/issues/84468) - Use consistent multiprocessing context for action write locks - Use the requested error message in the ansible.module_utils.facts.timeout timeout function instead of hardcoding one. - Windows - add support for running on system where WDAC is in audit mode with ``Dynamic Code Security`` enabled. - YAML parsing - The `!unsafe` tag no longer coerces non-string scalars to strings. - ``ansible-galaxy`` — the collection dependency resolver now treats version specifiers starting with ``!=`` as unpinned. - ``package``/``dnf`` action plugins - provide the reason behind the failure to gather the ``ansible_pkg_mgr`` fact to identify the package backend - action plugins - Action plugins that raise unhandled exceptions no longer terminate playbook loops. Previously, exceptions raised by an action plugin caused abnormal loop termination and loss of loop iteration results. - ansible-config - format galaxy server configs while dumping in JSON format (https://github.com/ansible/ansible/issues/84840). - ansible-doc - If none of the files in files exists, path will be undefined and a direct reference will throw an UnboundLocalError (https://github.com/ansible/ansible/pull/84464). - ansible-galaxy - Small adjustments to URL building for ``download_url`` and relative redirects. - ansible-pull change detection will now work independently of callback or result format settings. - ansible-test - Enable the ``sys.unraisablehook`` work-around for the ``pylint`` sanity test on Python 3.11. Previously the work-around was only enabled for Python 3.12 and later. However, the same issue has been discovered on Python 3.11. - ansible-test - Ensure CA certificates are installed on managed FreeBSD instances. - ansible-test - Fix support for PowerShell module_util imports with the ``-Optional`` flag. - ansible-test - Fix support for detecting PowerShell modules importing module utils with the newer ``#AnsibleRequires`` format. - ansible-test - Fix traceback that occurs after an interactive command fails. - ansible-test - Fix up coverage reporting to properly translate the temporary path of integration test modules to the expected static test module path. - ansible-test - Fixed traceback when handling certain YAML errors in the ``yamllint`` sanity test. - ansible-test - Managed macOS instances now use the ``sudo_chdir`` option for the ``sudo`` become plugin to avoid permission errors when dropping privileges. - ansible-vault will now correctly handle `--prompt`, previously it would issue an error about stdin if no 2nd argument was passed - ansible_uptime_second - added ansible_uptime_seconds fact support for AIX (https://github.com/ansible/ansible/pull/84321). - apt_key module - prevent tests from running when apt-key was removed - base.yml - deprecated libvirt_lxc_noseclabel config. - build - Pin ``wheel`` in ``pyproject.toml`` to ensure compatibility with supported ``setuptools`` versions. - config - various fixes to config lookup plugin (https://github.com/ansible/ansible/pull/84398). - copy - refactor copy module for simplicity. - copy action now prevents user from setting internal options. - debconf - set empty password values (https://github.com/ansible/ansible/issues/83214). - debug - hide loop vars in debug var display (https://github.com/ansible/ansible/issues/65856). - default callback - Error context is now shown for failing tasks that use the ``debug`` action. - display - The ``Display.deprecated`` method once again properly handles the ``removed=True`` argument (https://github.com/ansible/ansible/issues/82358). - distro - add support for Linux Mint Debian Edition (LMDE) (https://github.com/ansible/ansible/issues/84934). - distro - detect Debian as os_family for LMDE 6 (https://github.com/ansible/ansible/issues/84934). - dnf5 - Handle forwarded exceptions from dnf5-5.2.13 where a generic ``RuntimeError`` was previously raised - dnf5 - fix ``is_installed`` check for packages that are not installed but listed as provided by an installed package (https://github.com/ansible/ansible/issues/84578) - dnf5 - fix installing a package using ``state=latest`` when a binary of the same name as the package is already installed (https://github.com/ansible/ansible/issues/84259) - dnf5 - fix traceback when ``enable_plugins``/``disable_plugins`` is used on ``python3-libdnf5`` versions that do not support this functionality - dnf5 - libdnf5 - use ``conf.pkg_gpgcheck`` instead of deprecated ``conf.gpgcheck`` which is used only as a fallback - dnf5 - matching on a binary can be achieved only by specifying a full path (https://github.com/ansible/ansible/issues/84334) - facts - gather pagesize and calculate respective values depending upon architecture (https://github.com/ansible/ansible/issues/84773). - facts - skip if distribution file path is directory, instead of raising error (https://github.com/ansible/ansible/issues/84006). - find - skip ENOENT error code while recursively enumerating files. find module will now be tolerant to race conditions that remove files or directories from the target it is currently inspecting. (https://github.com/ansible/ansible/issues/84873). - first_found lookup - Corrected return value documentation to reflect None (not empty string) for no files found. - gather_facts action now defaults to `ansible.legacy.setup` if `smart` was set, no network OS was found and no other alias for `setup` was present. - gather_facts action will now issues errors and warnings as appropriate if a network OS is detected but no facts modules are defined for it. - gather_facts action, will now add setup when 'smart' appears with other modules in the FACTS_MODULES setting (#84750). - get_url - add support for BSD-style checksum digest file (https://github.com/ansible/ansible/issues/84476). - get_url - fix honoring ``filename`` from the ``content-disposition`` header even when the type is ``inline`` (https://github.com/ansible/ansible/issues/83690) - host_group_vars - fixed defining the 'key' variable if the get_vars method is called with cache=False (https://github.com/ansible/ansible/issues/84384) - include_vars - fix including previously undefined hash variables with hash_behaviour merge (https://github.com/ansible/ansible/issues/84295). - iptables - Allows the wait parameter to be used with iptables chain creation (https://github.com/ansible/ansible/issues/84490) - linear strategy - fix executing ``end_role`` meta tasks for each host, instead of handling these as implicit run_once tasks (https://github.com/ansible/ansible/issues/84660). - local connection plugin - Become timeout errors now include all received data. Previously, the most recently-received data was discarded. - local connection plugin - Ensure ``become`` success validation always occurs, even when an active plugin does not set ``prompt``. - local connection plugin - Fixed cases where the internal ``BECOME-SUCCESS`` message appeared in task output. - local connection plugin - Fixed hang or spurious failure when data arrived concurrently on stdout and stderr during a successful ``become`` operation validation. - local connection plugin - Fixed hang when a become plugin expects a prompt but a password was not provided. - local connection plugin - Fixed hang when an active become plugin incorrectly signals lack of prompt. - local connection plugin - Fixed hang when an internal become read timeout expired before the password prompt was written. - local connection plugin - Fixed hang when only one of stdout or stderr was closed by the ``become_exe`` subprocess. - local connection plugin - Fixed long timeout/hang for ``become`` plugins that repeat their prompt on failure (e.g., ``sudo``, some ``su`` implementations). - local connection plugin - Fixed silent ignore of ``become`` failures and loss of task output when data arrived concurrently on stdout and stderr during ``become`` operation validation. - local connection plugin - Fixed task output header truncation when post-become data arrived before ``become`` operation validation had completed. - lookup plugins - The ``terms`` arg to the ``run`` method is now always a list. Previously, there were cases where a non-list could be received. - module arg templating - When using a templated raw task arg and a templated ``args`` keyword, args are now merged. Previously use of templated raw task args silently ignored all values from the templated ``args`` keyword. - module defaults - Module defaults are no longer templated unless they are used by a task that does not override them. Previously, all module defaults for all modules were templated for every task. - module respawn - limit to supported Python versions - package_facts module when using 'auto' will return the first package manager found that provides an output, instead of just the first one, as this can be foreign and not have any packages. - psrp - Improve stderr parsing when running raw commands that emit error records or stderr lines. - regex_search filter - Corrected return value documentation to reflect None (not empty string) for no match. - respawn - use copy of env variables to update existing PYTHONPATH value (https://github.com/ansible/ansible/issues/84954). - runas become - Fix up become logic to still get the SYSTEM token with the most privileges when running as SYSTEM. - sequence lookup - sequence query/lookups without positional arguments now return a valid list if their kwargs comprise a valid sequence expression (https://github.com/ansible/ansible/issues/82921). - service_facts - skip lines which does not contain service names in openrc output (https://github.com/ansible/ansible/issues/84512). - ssh - Improve the logic for parsing CLIXML data in stderr when working with Windows host. This fixes issues when the raw stderr contains invalid UTF-8 byte sequences and improves embedded CLIXML sequences. - ssh - Raise exception when sshpass returns error code (https://github.com/ansible/ansible/issues/58133). - ssh - connection options were incorrectly templated during ``reset_connection`` tasks (https://github.com/ansible/ansible/pull/84238). - stability - Fixed silent process failure on unhandled IOError/OSError under ``linear`` strategy. - su become plugin - Ensure generated regex from ``prompt_l10n`` config values is properly escaped. - su become plugin - Ensure that password prompts are correctly detected in the presence of leading output. Previously, this case resulted in a timeout or hang. - su become plugin - Ensure that trailing colon is expected on all ``prompt_l10n`` config values. - sudo become plugin - The `sudo_chdir` config option allows the current directory to be set to the specified value before executing sudo to avoid permission errors when dropping privileges. - sunos - remove hard coding of virtinfo command in facts gathering code (https://github.com/ansible/ansible/pull/84357). - to_yaml/to_nice_yaml filters - Eliminated possibility of keyword arg collisions with internally-set defaults. - unarchive - Clamp timestamps from beyond y2038 to representible values when unpacking zip files on platforms that use 32-bit time_t (e.g. Debian i386). - uri - Form location correctly when the server returns a relative redirect (https://github.com/ansible/ansible/issues/84540) - uri - Handle HTTP exceptions raised while reading the content (https://github.com/ansible/ansible/issues/83794). - uri - mark ``url`` as required (https://github.com/ansible/ansible/pull/83642). - user - Create Buildroot subclass as alias to Busybox (https://github.com/ansible/ansible/issues/83665). - user - Set timeout for passphrase interaction. - user - Update prompt for SSH key passphrase (https://github.com/ansible/ansible/issues/84484). - user - Use higher precedence HOME_MODE as UMASK for path provided (https://github.com/ansible/ansible/pull/84482). - user action will now require O(force) to overwrite the public part of an ssh key when generating ssh keys, as was already the case for the private part. - user module now avoids changing ownership of files symlinked in provided home dir skeleton - vars lookup - The ``default`` substitution only applies when trying to look up a variable which is not defined. If the variable is defined, but templates to an undefined value, the ``default`` substitution will not apply. Use the ``default`` filter to coerce those values instead. - wait_for_connection - a warning was displayed if any hosts used a local connection (https://github.com/ansible/ansible/issues/84419) ansible_core-2.19.0b5/changelogs/changelog.yaml0000644000000000000000000017546215017704211020157 0ustar00rootrootancestor: 2.18.0 releases: 2.19.0b1: changes: breaking_changes: - Support for the ``toml`` library has been removed from TOML inventory parsing and dumping. Use ``tomli`` for parsing on Python 3.10. Python 3.11 and later have built-in support for parsing. Use ``tomli-w`` to support outputting inventory in TOML format. - assert - The ``quiet`` argument must be a commonly-accepted boolean value. Previously, unrecognized values were silently treated as False. - conditionals - Conditional expressions that result in non-boolean values are now an error by default. Such results often indicate unintentional use of templates where they are not supported, resulting in a conditional that is always true. When this option is enabled, conditional expressions which are a literal ``None`` or empty string will evaluate as true, for backwards compatibility. The error can be temporarily changed to a deprecation warning by enabling the ``ALLOW_BROKEN_CONDITIONALS`` config option. - first_found lookup - When specifying ``files`` or ``paths`` as a templated list containing undefined values, the undefined list elements will be discarded with a warning. Previously, the entire list would be discarded without any warning. - internals - The ``AnsibleLoader`` and ``AnsibleDumper`` classes for working with YAML are now factory functions and cannot be extended. - internals - The ``ansible.utils.native_jinja`` Python module has been removed. - inventory - Invalid variable names provided by inventories result in an inventory parse failure. This behavior is now consistent with other variable name usages throughout Ansible. - lookup plugins - Lookup plugins called as `with_(lookup)` will no longer have the `_subdir` attribute set. - lookup plugins - ``terms`` will always be passed to ``run`` as the first positional arg, where previously it was sometimes passed as a keyword arg when using ``with_`` syntax. - loops - Omit placeholders no longer leak between loop item templating and task templating. Previously, ``omit`` placeholders could remain embedded in loop items after templating and be used as an ``omit`` for task templating. Now, values resolving to ``omit`` are dropped immediately when loop items are templated. To turn missing values into an ``omit`` for task templating, use ``| default(omit)``. This solution is backward-compatible with previous versions of ansible-core. - modules - Ansible modules using ``sys.excepthook`` must use a standard ``try/except`` instead. - plugins - Any plugin that sources or creates templates must properly tag them as trusted. - plugins - Custom Jinja plugins that accept undefined top-level arguments must opt in to receiving them. - plugins - Custom Jinja plugins that use ``environment.getitem`` to retrieve undefined values will now trigger a ``MarkerError`` exception. This exception must be handled to allow the plugin to return a ``Marker``, or the plugin must opt-in to accepting ``Marker`` values. - public API - The ``ansible.vars.fact_cache.FactCache`` wrapper has been removed. - serialization of ``omit`` sentinel - Serialization of variables containing ``omit`` sentinels (e.g., by the ``to_json`` and ``to_yaml`` filters or ``ansible-inventory``) will fail if the variable has not completed templating. Previously, serialization succeeded with placeholder strings emitted in the serialized output. - set_fact - The string values "yes", "no", "true" and "false" were previously converted (ignoring case) to boolean values when not using Jinja2 native mode. Since Jinja2 native mode is always used, this conversion no longer occurs. When boolean values are required, native boolean syntax should be used where variables are defined, such as in YAML. When native boolean syntax is not an option, the ``bool`` filter can be used to parse string values into booleans. - template lookup - The ``convert_data`` option is deprecated and no longer has any effect. Use the ``from_json`` filter on the lookup result instead. - templating - Access to ``_`` prefixed attributes and methods, and methods with known side effects, is no longer permitted. In cases where a matching mapping key is present, the associated value will be returned instead of an error. This increases template environment isolation and ensures more consistent behavior between the ``.`` and ``[]`` operators. - templating - Conditionals and lookups which use embedded inline templates in Jinja string constants now display a warning. These templates should be converted to their expression equivalent. - templating - Many Jinja plugins (filters, lookups, tests) and methods previously silently ignored undefined inputs, which often masked subtle errors. Passing an undefined argument to a Jinja plugin or method that does not declare undefined support now results in an undefined value. - templating - Templates are always rendered in Jinja2 native mode. As a result, non-string values are no longer automatically converted to strings. - templating - Templates resulting in ``None`` are no longer automatically converted to an empty string. - templating - Templates with embedded inline templates that were not contained within a Jinja string constant now result in an error, as support for multi-pass templating was removed for security reasons. In most cases, such templates can be easily rewritten to avoid the use of embedded inline templates. - templating - The ``allow_unsafe_lookups`` option no longer has any effect. Lookup plugins are responsible for tagging strings containing templates to allow evaluation as a template. - templating - The result of the ``range()`` global function cannot be returned from a template- it should always be passed to a filter (e.g., ``random``). Previously, range objects returned from an intermediate template were always converted to a list, which is inconsistent with inline consumption of range objects. - templating - ``#jinja2:`` overrides in templates with invalid override names or types are now templating errors. bugfixes: - Ansible will now also warn when reserved keywords are set via a module (set_fact, include_vars, etc). - Ansible.Basic - Fix ``required_if`` check when the option value to check is unset or set to null. - Correctly return ``False`` when using the ``filter`` and ``test`` Jinja tests on plugin names which are not filters or tests, respectively. (resolves issue https://github.com/ansible/ansible/issues/82084) - Do not run implicit ``flush_handlers`` meta tasks when the whole play is excluded from the run due to tags specified. - Errors now preserve stacked error messages even when YAML is involved. - Fix a display.debug statement with the wrong param in _get_diff_data() method - Fix disabling SSL verification when installing collections and roles from git repositories. If ``--ignore-certs`` isn't provided, the value for the ``GALAXY_IGNORE_CERTS`` configuration option will be used (https://github.com/ansible/ansible/issues/83326). - Fix ipv6 pattern bug in lib/ansible/parsing/utils/addresses.py (https://github.com/ansible/ansible/issues/84237) - Fix returning 'unreachable' for the overall task result. This prevents false positives when a looped task has unignored unreachable items (https://github.com/ansible/ansible/issues/84019). - 'Implicit ``meta: flush_handlers`` tasks now have a parent block to prevent potential tracebacks when calling methods like ``get_play()`` on them internally.' - Improve performance on large inventories by reducing the number of implicit meta tasks. - Jinja plugins - Errors raised will always be derived from ``AnsibleTemplatePluginError``. - Optimize the way tasks from within ``include_tasks``/``include_role`` are inserted into the play. - Time out waiting on become is an unreachable error (https://github.com/ansible/ansible/issues/84468) - Use consistent multiprocessing context for action write locks - Use the requested error message in the ansible.module_utils.facts.timeout timeout function instead of hardcoding one. - Windows - add support for running on system where WDAC is in audit mode with ``Dynamic Code Security`` enabled. - YAML parsing - The `!unsafe` tag no longer coerces non-string scalars to strings. - "``ansible-galaxy`` \u2014 the collection dependency resolver now treats version specifiers starting with ``!=`` as unpinned." - '``package``/``dnf`` action plugins - provide the reason behind the failure to gather the ``ansible_pkg_mgr`` fact to identify the package backend' - action plugins - Action plugins that raise unhandled exceptions no longer terminate playbook loops. Previously, exceptions raised by an action plugin caused abnormal loop termination and loss of loop iteration results. - ansible-config - format galaxy server configs while dumping in JSON format (https://github.com/ansible/ansible/issues/84840). - ansible-doc - If none of the files in files exists, path will be undefined and a direct reference will throw an UnboundLocalError (https://github.com/ansible/ansible/pull/84464). - ansible-galaxy - Small adjustments to URL building for ``download_url`` and relative redirects. - ansible-pull change detection will now work independently of callback or result format settings. - ansible-test - Enable the ``sys.unraisablehook`` work-around for the ``pylint`` sanity test on Python 3.11. Previously the work-around was only enabled for Python 3.12 and later. However, the same issue has been discovered on Python 3.11. - ansible-test - Ensure CA certificates are installed on managed FreeBSD instances. - ansible-test - Fix support for PowerShell module_util imports with the ``-Optional`` flag. - ansible-test - Fix support for detecting PowerShell modules importing module utils with the newer ``#AnsibleRequires`` format. - ansible-test - Fix traceback that occurs after an interactive command fails. - ansible-test - Fix up coverage reporting to properly translate the temporary path of integration test modules to the expected static test module path. - ansible-test - Fixed traceback when handling certain YAML errors in the ``yamllint`` sanity test. - ansible-test - Managed macOS instances now use the ``sudo_chdir`` option for the ``sudo`` become plugin to avoid permission errors when dropping privileges. - ansible-vault will now correctly handle `--prompt`, previously it would issue an error about stdin if no 2nd argument was passed - ansible_uptime_second - added ansible_uptime_seconds fact support for AIX (https://github.com/ansible/ansible/pull/84321). - apt_key module - prevent tests from running when apt-key was removed - base.yml - deprecated libvirt_lxc_noseclabel config. - build - Pin ``wheel`` in ``pyproject.toml`` to ensure compatibility with supported ``setuptools`` versions. - config - various fixes to config lookup plugin (https://github.com/ansible/ansible/pull/84398). - copy - refactor copy module for simplicity. - copy action now prevents user from setting internal options. - debconf - set empty password values (https://github.com/ansible/ansible/issues/83214). - debug - hide loop vars in debug var display (https://github.com/ansible/ansible/issues/65856). - default callback - Error context is now shown for failing tasks that use the ``debug`` action. - display - The ``Display.deprecated`` method once again properly handles the ``removed=True`` argument (https://github.com/ansible/ansible/issues/82358). - distro - add support for Linux Mint Debian Edition (LMDE) (https://github.com/ansible/ansible/issues/84934). - distro - detect Debian as os_family for LMDE 6 (https://github.com/ansible/ansible/issues/84934). - dnf5 - Handle forwarded exceptions from dnf5-5.2.13 where a generic ``RuntimeError`` was previously raised - dnf5 - fix ``is_installed`` check for packages that are not installed but listed as provided by an installed package (https://github.com/ansible/ansible/issues/84578) - dnf5 - fix installing a package using ``state=latest`` when a binary of the same name as the package is already installed (https://github.com/ansible/ansible/issues/84259) - dnf5 - fix traceback when ``enable_plugins``/``disable_plugins`` is used on ``python3-libdnf5`` versions that do not support this functionality - dnf5 - libdnf5 - use ``conf.pkg_gpgcheck`` instead of deprecated ``conf.gpgcheck`` which is used only as a fallback - dnf5 - matching on a binary can be achieved only by specifying a full path (https://github.com/ansible/ansible/issues/84334) - facts - gather pagesize and calculate respective values depending upon architecture (https://github.com/ansible/ansible/issues/84773). - facts - skip if distribution file path is directory, instead of raising error (https://github.com/ansible/ansible/issues/84006). - find - skip ENOENT error code while recursively enumerating files. find module will now be tolerant to race conditions that remove files or directories from the target it is currently inspecting. (https://github.com/ansible/ansible/issues/84873). - first_found lookup - Corrected return value documentation to reflect None (not empty string) for no files found. - gather_facts action now defaults to `ansible.legacy.setup` if `smart` was set, no network OS was found and no other alias for `setup` was present. - gather_facts action will now issues errors and warnings as appropriate if a network OS is detected but no facts modules are defined for it. - gather_facts action, will now add setup when 'smart' appears with other modules in the FACTS_MODULES setting (#84750). - get_url - add support for BSD-style checksum digest file (https://github.com/ansible/ansible/issues/84476). - get_url - fix honoring ``filename`` from the ``content-disposition`` header even when the type is ``inline`` (https://github.com/ansible/ansible/issues/83690) - host_group_vars - fixed defining the 'key' variable if the get_vars method is called with cache=False (https://github.com/ansible/ansible/issues/84384) - include_vars - fix including previously undefined hash variables with hash_behaviour merge (https://github.com/ansible/ansible/issues/84295). - iptables - Allows the wait parameter to be used with iptables chain creation (https://github.com/ansible/ansible/issues/84490) - linear strategy - fix executing ``end_role`` meta tasks for each host, instead of handling these as implicit run_once tasks (https://github.com/ansible/ansible/issues/84660). - local connection plugin - Become timeout errors now include all received data. Previously, the most recently-received data was discarded. - local connection plugin - Ensure ``become`` success validation always occurs, even when an active plugin does not set ``prompt``. - local connection plugin - Fixed cases where the internal ``BECOME-SUCCESS`` message appeared in task output. - local connection plugin - Fixed hang or spurious failure when data arrived concurrently on stdout and stderr during a successful ``become`` operation validation. - local connection plugin - Fixed hang when a become plugin expects a prompt but a password was not provided. - local connection plugin - Fixed hang when an active become plugin incorrectly signals lack of prompt. - local connection plugin - Fixed hang when an internal become read timeout expired before the password prompt was written. - local connection plugin - Fixed hang when only one of stdout or stderr was closed by the ``become_exe`` subprocess. - local connection plugin - Fixed long timeout/hang for ``become`` plugins that repeat their prompt on failure (e.g., ``sudo``, some ``su`` implementations). - local connection plugin - Fixed silent ignore of ``become`` failures and loss of task output when data arrived concurrently on stdout and stderr during ``become`` operation validation. - local connection plugin - Fixed task output header truncation when post-become data arrived before ``become`` operation validation had completed. - lookup plugins - The ``terms`` arg to the ``run`` method is now always a list. Previously, there were cases where a non-list could be received. - module arg templating - When using a templated raw task arg and a templated ``args`` keyword, args are now merged. Previously use of templated raw task args silently ignored all values from the templated ``args`` keyword. - module defaults - Module defaults are no longer templated unless they are used by a task that does not override them. Previously, all module defaults for all modules were templated for every task. - module respawn - limit to supported Python versions - package_facts module when using 'auto' will return the first package manager found that provides an output, instead of just the first one, as this can be foreign and not have any packages. - psrp - Improve stderr parsing when running raw commands that emit error records or stderr lines. - regex_search filter - Corrected return value documentation to reflect None (not empty string) for no match. - respawn - use copy of env variables to update existing PYTHONPATH value (https://github.com/ansible/ansible/issues/84954). - runas become - Fix up become logic to still get the SYSTEM token with the most privileges when running as SYSTEM. - sequence lookup - sequence query/lookups without positional arguments now return a valid list if their kwargs comprise a valid sequence expression (https://github.com/ansible/ansible/issues/82921). - service_facts - skip lines which does not contain service names in openrc output (https://github.com/ansible/ansible/issues/84512). - ssh - Improve the logic for parsing CLIXML data in stderr when working with Windows host. This fixes issues when the raw stderr contains invalid UTF-8 byte sequences and improves embedded CLIXML sequences. - ssh - Raise exception when sshpass returns error code (https://github.com/ansible/ansible/issues/58133). - ssh - connection options were incorrectly templated during ``reset_connection`` tasks (https://github.com/ansible/ansible/pull/84238). - stability - Fixed silent process failure on unhandled IOError/OSError under ``linear`` strategy. - su become plugin - Ensure generated regex from ``prompt_l10n`` config values is properly escaped. - su become plugin - Ensure that password prompts are correctly detected in the presence of leading output. Previously, this case resulted in a timeout or hang. - su become plugin - Ensure that trailing colon is expected on all ``prompt_l10n`` config values. - sudo become plugin - The `sudo_chdir` config option allows the current directory to be set to the specified value before executing sudo to avoid permission errors when dropping privileges. - sunos - remove hard coding of virtinfo command in facts gathering code (https://github.com/ansible/ansible/pull/84357). - to_yaml/to_nice_yaml filters - Eliminated possibility of keyword arg collisions with internally-set defaults. - unarchive - Clamp timestamps from beyond y2038 to representible values when unpacking zip files on platforms that use 32-bit time_t (e.g. Debian i386). - uri - Form location correctly when the server returns a relative redirect (https://github.com/ansible/ansible/issues/84540) - uri - Handle HTTP exceptions raised while reading the content (https://github.com/ansible/ansible/issues/83794). - uri - mark ``url`` as required (https://github.com/ansible/ansible/pull/83642). - user - Create Buildroot subclass as alias to Busybox (https://github.com/ansible/ansible/issues/83665). - user - Set timeout for passphrase interaction. - user - Update prompt for SSH key passphrase (https://github.com/ansible/ansible/issues/84484). - user - Use higher precedence HOME_MODE as UMASK for path provided (https://github.com/ansible/ansible/pull/84482). - user action will now require O(force) to overwrite the public part of an ssh key when generating ssh keys, as was already the case for the private part. - user module now avoids changing ownership of files symlinked in provided home dir skeleton - vars lookup - The ``default`` substitution only applies when trying to look up a variable which is not defined. If the variable is defined, but templates to an undefined value, the ``default`` substitution will not apply. Use the ``default`` filter to coerce those values instead. - wait_for_connection - a warning was displayed if any hosts used a local connection (https://github.com/ansible/ansible/issues/84419) deprecated_features: - CLI - The ``--inventory-file`` option alias is deprecated. Use the ``-i`` or ``--inventory`` option instead. - Stategy Plugins - Use of strategy plugins not provided in ``ansible.builtin`` are deprecated and do not carry any backwards compatibility guarantees going forward. A future release will remove the ability to use external strategy plugins. No alternative for third party strategy plugins is currently planned. - '``ansible.module_utils.compat.datetime`` - The datetime compatibility shims are now deprecated. They are scheduled to be removed in ``ansible-core`` v2.21. This includes ``UTC``, ``utcfromtimestamp()`` and ``utcnow`` importable from said module (https://github.com/ansible/ansible/pull/81874).' - bool filter - Support for coercing unrecognized input values (including None) has been deprecated. Consult the filter documentation for acceptable values, or consider use of the ``truthy`` and ``falsy`` tests. - cache plugins - The `ansible.plugins.cache.base` Python module is deprecated. Use `ansible.plugins.cache` instead. - callback plugins - The `v2_on_any` callback method is deprecated. Use specific callback methods instead. - callback plugins - The v1 callback API (callback methods not prefixed with `v2_`) is deprecated. Use `v2_` prefixed methods instead. - conditionals - Conditionals using Jinja templating delimiters (e.g., ``{{``, ``{%``) should be rewritten as expressions without delimiters, unless the entire conditional value is a single template that resolves to a trusted string expression. This is useful for dynamic indirection of conditional expressions, but is limited to trusted literal string expressions. - config - The ``ACTION_WARNINGS`` config has no effect. It previously disabled command warnings, which have since been removed. - config - The ``DEFAULT_JINJA2_NATIVE`` option has no effect. Jinja2 native mode is now the default and only option. - config - The ``DEFAULT_NULL_REPRESENTATION`` option has no effect. Null values are no longer automatically converted to another value during templating of single variable references. - display - The ``Display.get_deprecation_message`` method has been deprecated. Call ``Display.deprecated`` to display a deprecation message, or call it with ``removed=True`` to raise an ``AnsibleError``. - file loading - Loading text files with ``DataLoader`` containing data that cannot be decoded under the expected encoding is deprecated. In most cases the encoding must be UTF-8, although some plugins allow choosing a different encoding. Previously, invalid data was silently wrapped in Unicode surrogate escape sequences, often resulting in later errors or other data corruption. - first_found lookup - Splitting of file paths on ``,;:`` is deprecated. Pass a list of paths instead. The ``split`` method on strings can be used to split variables into a list as needed. - interpreter discovery - The ``auto_legacy`` and ``auto_legacy_silent`` options for ``INTERPRETER_PYTHON`` are deprecated. Use ``auto`` or ``auto_silent`` options instead, as they have the same effect. - oneline callback - The ``oneline`` callback and its associated ad-hoc CLI args (``-o``, ``--one-line``) are deprecated. - paramiko - The paramiko connection plugin has been deprecated with planned removal in 2.21. - playbook variables - The ``play_hosts`` variable has been deprecated, use ``ansible_play_batch`` instead. - plugin error handling - The ``AnsibleError`` constructor arg ``suppress_extended_error`` is deprecated. Using ``suppress_extended_error=True`` has the same effect as ``show_content=False``. - template lookup - The jinja2_native option is no longer used in the Ansible Core code base. Jinja2 native mode is now the default and only option. - templating - Support for enabling Jinja2 extensions (not plugins) has been deprecated. - templating - The ``ansible_managed`` variable available for certain templating scenarios, such as the ``template`` action and ``template`` lookup has been deprecated. Define and use a custom variable instead of relying on ``ansible_managed``. - templating - The ``disable_lookups`` option has no effect, since plugins must be updated to apply trust before any templating can be performed. - to_yaml/to_nice_yaml filters - Implicit YAML dumping of vaulted value ciphertext is deprecated. Set `dump_vault_tags` to explicitly specify the desired behavior. - tree callback - The ``tree`` callback and its associated ad-hoc CLI args (``-t``, ``--tree``) are deprecated. major_changes: - Jinja plugins - Jinja builtin filter and test plugins are now accessible via their fully-qualified names ``ansible.builtin.{name}``. - Task Execution / Forks - Forks no longer inherit stdio from the parent ``ansible-playbook`` process. ``stdout``, ``stderr``, and ``stdin`` within a worker are detached from the terminal, and non-functional. All needs to access stdio from a fork for controller side plugins requires use of ``Display``. - ansible-test - Packages beneath ``module_utils`` can now contain ``__init__.py`` files. - variables - The type system underlying Ansible's variable storage has been significantly overhauled and formalized. Attempts to store unsupported Python object types in variables now more consistently yields early warnings or errors. - variables - To support new Ansible features, many variable objects are now represented by subclasses of their respective native Python types. In most cases, they behave indistinguishably from their original types, but some Python libraries do not handle builtin object subclasses properly. Custom plugins that interact with such libraries may require changes to convert and pass the native types. minor_changes: - Added a -vvvvv log message indicating when a host fails to produce output within the timeout period. - AnsibleModule.uri - Add option ``multipart_encoding`` for ``form-multipart`` files in body to change default base64 encoding for files - INVENTORY_IGNORE_EXTS config, removed ``ini`` from the default list, inventory scripts using a corresponding .ini configuration are rare now and inventory.ini files are more common. Those that need to ignore the ini files for inventory scripts can still add it to configuration. - Jinja plugins - Plugins can declare support for undefined values. - Jinja2 version 3.1.0 or later is now required on the controller. - Move ``follow_redirects`` parameter to module_utils so external modules can reuse it. - PlayIterator - do not return tasks from already executed roles so specific strategy plugins do not have to do the filtering of such tasks themselves - SSH Escalation-related -vvv log messages now include the associated host information. - Windows - Add support for Windows Server 2025 to Ansible and as an ``ansible-test`` remote target - https://github.com/ansible/ansible/issues/84229 - Windows - refactor the async implementation to better handle errors during bootstrapping and avoid WMI when possible. - "``ansible-galaxy collection install`` \u2014 the collection dependency resolver now prints out conflicts it hits during dependency resolution when it's taking too long and it ends up backtracking a lot. It also displays suggestions on how to help it compute the result more quickly." - 'ansible, ansible-console, ansible-pull - add --flush-cache option (https://github.com/ansible/ansible/issues/83749). ' - ansible-galaxy - Add support for Keycloak service accounts - ansible-galaxy - support ``resolvelib >= 0.5.3, < 2.0.0`` (https://github.com/ansible/ansible/issues/84217). - ansible-test - Added a macOS 15.3 remote VM, replacing 14.3. - ansible-test - Automatically retry HTTP GET/PUT/DELETE requests on exceptions. - ansible-test - Default to Python 3.13 in the ``base`` and ``default`` containers. - ansible-test - Disable the ``deprecated-`` prefixed ``pylint`` rules as their results vary by Python version. - ansible-test - Disable the ``pep8`` sanity test rules ``E701`` and ``E704`` to improve compatibility with ``black``. - ansible-test - Improve container runtime probe error handling. When unexpected probe output is encountered, an error with more useful debugging information is provided. - ansible-test - Replace container Alpine 3.20 with 3.21. - ansible-test - Replace container Fedora 40 with 41. - ansible-test - Replace remote Alpine 3.20 with 3.21. - ansible-test - Replace remote Fedora 40 with 41. - ansible-test - Replace remote FreeBSD 13.3 with 13.5. - ansible-test - Replace remote FreeBSD 14.1 with 14.2. - ansible-test - Replace remote RHEL 9.4 with 9.5. - ansible-test - Show a more user-friendly error message when a ``runme.sh`` script is not executable. - ansible-test - The ``yamllint`` sanity test now enforces string values for the ``!vault`` tag. - ansible-test - Update ``nios-test-container`` to version 7.0.0. - ansible-test - Update ``pylint`` sanity test to use version 3.3.1. - ansible-test - Update distro containers to remove unnecessary pakages (apache2, subversion, ruby). - ansible-test - Update sanity test requirements to latest available versions. - ansible-test - Update the HTTP test container. - ansible-test - Update the PyPI test container. - ansible-test - Update the ``base`` and ``default`` containers. - ansible-test - Update the utility container. - ansible-test - Use Python's ``urllib`` instead of ``curl`` for HTTP requests. - ansible-test - When detection of the current container network fails, a warning is now issued and execution continues. This simplifies usage in cases where the current container cannot be inspected, such as when running in GitHub Codespaces. - ansible-test acme test container - bump `version to 2.3.0 `__ to include newer versions of Pebble, dependencies, and runtimes. This adds support for ACME profiles, ``dns-account-01`` support, and some smaller improvements (https://github.com/ansible/ansible/pull/84547). - apt_key module - add notes to docs and errors to point at the CLI tool deprecation by Debian and alternatives - apt_repository module - add notes to errors to point at the CLI tool deprecation by Debian and alternatives - become plugins get new property 'pipelining' to show support or lack there of for the feature. - callback plugins - add has_option() to CallbackBase to match other functions overloaded from AnsiblePlugin - callback plugins - fix get_options() for CallbackBase - copy - fix sanity test failures (https://github.com/ansible/ansible/pull/83643). - copy - parameter ``local_follow`` was incorrectly documented as having default value ``True`` (https://github.com/ansible/ansible/pull/83643). - cron - Provide additional error information while writing cron file (https://github.com/ansible/ansible/issues/83223). - csvfile - let the config system do the typecasting (https://github.com/ansible/ansible/pull/82263). - display - Deduplication of warning and error messages considers the full content of the message (including source and traceback contexts, if enabled). This may result in fewer messages being omitted. - distribution - Added openSUSE MicroOS to Suse OS family (#84685). - dnf5, apt - add ``auto_install_module_deps`` option (https://github.com/ansible/ansible/issues/84206) - docs - add collection name in message from which the module is being deprecated (https://github.com/ansible/ansible/issues/84116). - env lookup - The error message generated for a missing environment variable when ``default`` is an undefined value (e.g. ``undef('something')``) will contain the hint from that undefined value, except when the undefined value is the default of ``undef()`` with no arguments. Previously, any existing undefined hint would be ignored. - file - enable file module to disable diff_mode (https://github.com/ansible/ansible/issues/80817). - file - make code more readable and simple. - filter - add support for URL-safe encoding and decoding in b64encode and b64decode (https://github.com/ansible/ansible/issues/84147). - find - add a checksum_algorithm parameter to specify which type of checksum the module will return - from_json filter - The filter accepts a ``profile`` argument, which defaults to ``tagless``. - handlers - Templated handler names with syntax errors, or that resolve to ``omit`` are now skipped like handlers with undefined variables in their name. - improved error message for yaml parsing errors in plugin documentation - local connection plugin - A new ``become_strip_preamble`` config option (default True) was added; disable to preserve diagnostic ``become`` output in task results. - local connection plugin - A new ``become_success_timeout`` operation-wide timeout config (default 10s) was added for ``become``. - local connection plugin - When a ``become`` plugin's ``prompt`` value is a non-string after the ``check_password_prompt`` callback has completed, no prompt stripping will occur on stderr. - lookup_template - add an option to trim blocks while templating (https://github.com/ansible/ansible/issues/75962). - module - set ipv4 and ipv6 rules simultaneously in iptables module (https://github.com/ansible/ansible/issues/84404). - module_utils - Add ``NoReturn`` type annotations to functions which never return. - modules - PowerShell modules can now receive ``datetime.date``, ``datetime.time`` and ``datetime.datetime`` values as ISO 8601 strings. - modules - PowerShell modules can now receive strings sourced from inline vault-encrypted strings. - modules - Unhandled exceptions during Python module execution are now returned as structured data from the target. This allows the new traceback handling to be applied to exceptions raised on targets. - pipelining logic has mostly moved to connection plugins so they can decide/override settings. - plugin error handling - When raising exceptions in an exception handler, be sure to use ``raise ... from`` as appropriate. This supersedes the use of the ``AnsibleError`` arg ``orig_exc`` to represent the cause. Specifying ``orig_exc`` as the cause is still permitted. Failure to use ``raise ... from`` when ``orig_exc`` is set will result in a warning. Additionally, if the two cause exceptions do not match, a warning will be issued. - removed harcoding of su plugin as it now works with pipelining. - runtime-metadata sanity test - improve validation of ``action_groups`` (https://github.com/ansible/ansible/pull/83965). - service_facts module got freebsd support added. - ssh connection plugin - Support ``SSH_ASKPASS`` mechanism to provide passwords, making it the default, but still offering an explicit choice to use ``sshpass`` (https://github.com/ansible/ansible/pull/83936) - ssh connection plugin now overrides pipelining when a tty is requested. - ssh-agent - ``ansible``, ``ansible-playbook`` and ``ansible-console`` are capable of spawning or reusing an ssh-agent, allowing plugins to interact with the ssh-agent. Additionally a pure python ssh-agent client has been added, enabling easy interaction with the agent. The ssh connection plugin contains new functionality via ``ansible_ssh_private_key`` and ``ansible_ssh_private_key_passphrase``, for loading an SSH private key into the agent from a variable. - templating - Access to an undefined variable from inside a lookup, filter, or test (which raises MarkerError) no longer ends processing of the current template. The triggering undefined value is returned as the result of the offending plugin invocation, and the template continues to execute. - templating - Embedding ``range()`` values in containers such as lists will result in an error on use. Previously the value would be converted to a string representing the range parameters, such as ``range(0, 3)``. - templating - Handling of omitted values is now a first-class feature of the template engine, and is usable in all Ansible Jinja template contexts. Any template that resolves to ``omit`` is automatically removed from its parent container during templating. - templating - Template evaluation is lazier than in previous versions. Template expressions which resolve only portions of a data structure no longer result in the entire structure being templated. - templating - Templating errors now provide more information about both the location and context of the error, especially for deeply-nested and/or indirected templating scenarios. - templating - Unified ``omit`` behavior now requires that plugins calling ``Templar.template()`` handle cases where the entire template result is omitted, by catching the ``AnsibleValueOmittedError`` that is raised. Previously, this condition caused a randomly-generated string marker to appear in the template result. - templating - Variables of type ``set`` and ``tuple`` are now converted to ``list`` when exiting the final pass of templating. - to_json / to_nice_json filters - The filters accept a ``profile`` argument, which defaults to ``tagless``. - troubleshooting - Tracebacks can be collected and displayed for most errors, warnings, and deprecation warnings (including those generated by modules). Tracebacks are no longer enabled with ``-vvv``; the behavior is directly configurable via the ``DISPLAY_TRACEBACK`` config option. Module tracebacks passed to ``fail_json`` via the ``exception`` kwarg will not be included in the task result unless error tracebacks are configured. - undef jinja function - The ``undef`` jinja function now raises an error if a non-string hint is given. Attempting to use an undefined hint also results in an error, ensuring incorrect use of the function can be distinguished from the function's normal behavior. - validate-modules sanity test - make sure that ``module`` and ``plugin`` ``seealso`` entries use FQCNs (https://github.com/ansible/ansible/pull/84325). - vault - improved vault filter documentation by adding missing example content for dump_template_data.j2, refining examples for clarity, and ensuring variable consistency (https://github.com/ansible/ansible/issues/83583). - warnings - All warnings (including deprecation warnings) issued during a task's execution are now accessible via the ``warnings`` and ``deprecations`` keys on the task result. - when the ``dict`` lookup is given a non-dict argument, show the value of the argument and its type in the error message. - windows - add hard minimum limit for PowerShell to 5.1. Ansible dropped support for older versions of PowerShell in the 2.16 release but this reqirement is now enforced at runtime. - windows - refactor windows exec runner to improve efficiency and add better error reporting on failures. - winrm - Remove need for pexpect on macOS hosts when using ``kinit`` to retrieve the Kerberos TGT. By default the code will now only use the builtin ``subprocess`` library which should handle issues with select and a high fd count and also simplify the code. release_summary: '| Release Date: 2025-04-14 | `Porting Guide `__ ' removed_features: - Remove deprecated plural form of collection path (https://github.com/ansible/ansible/pull/84156). - Removed deprecated STRING_CONVERSION_ACTION (https://github.com/ansible/ansible/issues/84220). - encrypt - passing unsupported passlib hashtype now raises AnsibleFilterError. - manager - remove deprecated include_delegate_to parameter from get_vars API. - modules - Modules returning non-UTF8 strings now result in an error. The ``MODULE_STRICT_UTF8_RESPONSE`` setting can be used to disable this check. - removed deprecated pycompat24 and compat.importlib. - selector - remove deprecated compat.selector related files (https://github.com/ansible/ansible/pull/84155). - windows - removed common module functions ``ConvertFrom-AnsibleJson``, ``Format-AnsibleException`` from Windows modules as they are not used and add uneeded complexity to the code. security_fixes: - include_vars action - Ensure that result masking is correctly requested when vault-encrypted files are read. (CVE-2024-8775) - task result processing - Ensure that action-sourced result masking (``_ansible_no_log=True``) is preserved. (CVE-2024-8775) - templating - Ansible's template engine no longer processes Jinja templates in strings unless they are marked as coming from a trusted source. Untrusted strings containing Jinja template markers are ignored with a warning. Examples of trusted sources include playbooks, vars files, and many inventory sources. Examples of untrusted sources include module results and facts. Plugins which have not been updated to preserve trust while manipulating strings may inadvertently cause them to lose their trusted status. - templating - Changes to conditional expression handling removed numerous instances of insecure multi-pass templating (which could result in execution of untrusted template expressions). - user action won't allow ssh-keygen, chown and chmod to run on existing ssh public key file, avoiding traversal on existing symlinks (CVE-2024-9902). codename: What Is and What Should Never Be fragments: - 2.19.0b1_summary.yaml - 81709-ansible-galaxy-slow-resolution-hints.yml - 81812-ansible-galaxy-negative-spec-is-pinned.yml - 81874-deprecate-datetime-compat.yml - 83642-fix-sanity-ignore-for-uri.yml - 83643-fix-sanity-ignore-for-copy.yml - 83690-get_url-content-disposition-filename.yml - 83700-enable-file-disable-diff.yml - 83757-deprecate-paramiko.yml - 83936-ssh-askpass.yml - 83965-action-groups-schema.yml - 84008-additional-logging.yml - 84019-ignore_unreachable-loop.yml - 84149-add-flush-cache-for-adhoc-commands.yml - 84206-dnf5-apt-auto-install-module-deps.yml - 84213-ansible-galaxy-url-building.yml - 84229-windows-server-2025.yml - 84238-fix-reset_connection-ssh_executable-templated.yml - 84259-dnf5-latest-fix.yml - 84321-added-ansible_uptime_seconds_aix.yml - 84325-validate-modules-seealso-fqcn.yml - 84334-dnf5-consolidate-settings.yml - 84384-fix-undefined-key-host-group-vars.yml - 84419-fix-wait_for_connection-warning.yml - 84468-timeout_become_unreachable.yml - 84473-dict-lookup-type-error-message.yml - 84490-allow-iptables-chain-creation-with-wait.yml - 84496-CallbackBase-get_options.yml - 84540-uri-relative-redirect.yml - 84547-acme-test-container.yml - 84578-dnf5-is_installed-provides.yml - 84660-fix-meta-end_role-linear-strategy.yml - 84685-add-opensuse-microos.yml - 84705-error-message-malformed-plugin-documentation.yml - 84725-deprecate-strategy-plugins.yml - Ansible.Basic-required_if-null.yml - ansible-galaxy-keycloak-service-accounts.yml - ansible-test-added-macos-15.3.yml - ansible-test-containers.yml - ansible-test-coverage-test-files.yml - ansible-test-curl.yml - ansible-test-fix-command-traceback.yml - ansible-test-freebsd-nss.yml - ansible-test-network-detection.yml - ansible-test-nios-container.yml - ansible-test-no-exec-script.yml - ansible-test-probe-error-handling.yml - ansible-test-pylint-fix.yml - ansible-test-remotes.yml - ansible-test-update.yml - apt_key_bye.yml - become-runas-system-deux.yml - buildroot.yml - compat_removal.yml - config.yml - config_dump.yml - copy_validate_input.yml - cron_err.yml - csvfile-col.yml - cve-2024-8775.yml - darwin_pagesize.yml - debconf_empty_password.yml - deprecated.yml - distro_LMDE_6.yml - dnf5-exception-forwarding.yml - dnf5-plugins-compat.yml - dnf5-remove-usage-deprecated-option.yml - feature-uri-add-option-multipart-encoding.yml - file_simplify.yml - find-checksum.yml - find_enoent.yml - fix-ansible-galaxy-ignore-certs.yml - fix-cli-doc-path_undefined.yaml - fix-display-bug-in-action-plugin.yml - fix-include_vars-merge-hash.yml - fix-ipv6-pattern.yml - fix-is-filter-is-test.yml - fix-lookup-sequence-keyword-args-only.yml - fix-module-utils-facts-timeout.yml - fix_errors.yml - follow_redirects_url.yml - gather_facts_netos_fixes.yml - gather_facts_smart_fix.yml - get_url_bsd_style_digest.yml - hide-loop-vars-debug-vars.yml - implicit_flush_handlers_parents.yml - include_delegate_to.yml - interpreter-discovery-auto-legacy.yml - jinja-version.yml - libvirt_lxc.yml - local-become-fixes.yml - lookup_config.yml - macos-correct-lock.yml - no-inherit-stdio.yml - no-return.yml - openrc-status.yml - os_family.yml - package-dnf-action-plugins-facts-fail-msg.yml - package_facts_fix.yml - passlib.yml - pin-wheel.yml - pipelining_refactor.yml - playiterator-add_tasks-optimize.yml - ps-import-sanity.yml - pull_changed_fix.yml - remove_ini_ignored_dir.yml - reserved_module_chekc.yml - respawn-min-python.yml - respawn_os_env.yml - selector_removal.yml - service_facts_fbsd.yml - set_ipv4_and_ipv6_simultaneously.yml - simplify-copy-module.yml - skip-handlers-tagged-play.yml - skip-implicit-flush_handlers-no-notify.yml - skip-role-task-iterator.yml - ssh-agent.yml - ssh-clixml.yml - ssh_raise_exception.yml - string_conversion.yml - sunos_virtinfo.yml - templates_types_datatagging.yml - toml-library-support-dropped.yml - trim_blocks.yml - unarchive_timestamp_t32.yaml - update-resolvelib-lt-2_0_0.yml - uri_httpexception.yml - url_safe_b64_encode_decode.yml - user_action_fix.yml - user_module.yml - user_passphrase.yml - user_ssh_fix.yml - v2.19.0-initial-commit.yaml - vault_cli_fix.yml - vault_docs_fix.yaml - win-async-refactor.yml - win-wdac-audit.yml - windows-exec.yml - winrm-kinit-pexpect.yml release_date: '2025-04-14' 2.19.0b2: changes: bugfixes: - Remove use of `required` parameter in `get_bin_path` which has been deprecated. - ansible-doc - fix indentation for first line of descriptions of suboptions and sub-return values (https://github.com/ansible/ansible/pull/84690). - ansible-doc - fix line wrapping for first line of description of options and return values (https://github.com/ansible/ansible/pull/84690). minor_changes: - comment filter - Improve the error message shown when an invalid ``style`` argument is provided. release_summary: '| Release Date: 2025-04-24 | `Porting Guide `__ ' codename: What Is and What Should Never Be fragments: - 2.19.0b2_summary.yaml - 84690-ansible-doc-indent-wrapping.yml - comment_fail.yml - get_bin_path-remove-use-of-deprecated-param.yml release_date: '2025-04-23' 2.19.0b3: changes: bugfixes: - Ansible will now ensure predictable permissions on remote artifacts, until now it only ensured executable and relied on system masks for the rest. - dnf5 - avoid generating excessive transaction entries in the dnf5 history (https://github.com/ansible/ansible/issues/85046) deprecated_features: - Passing a ``warnings` or ``deprecations`` key to ``exit_json`` or ``fail_json`` is deprecated. Use ``AnsibleModule.warn`` or ``AnsibleModule.deprecate`` instead. - plugins - Accessing plugins with ``_``-prefixed filenames without the ``_`` prefix is deprecated. minor_changes: - ansible-config will now show internal, but not test configuration entries. This allows for debugging but still denoting the configurations as internal use only (_ prefix). - ansible-test - Improved ``pylint`` checks for Ansible-specific deprecation functions. - ansible-test - Use the ``-t`` option to set the stop timeout when stopping a container. This avoids use of the ``--time`` option which was deprecated in Docker v28.0. - collection metadata - The collection loader now parses scalar values from ``meta/runtime.yml`` as strings. This avoids issues caused by unquoted values such as versions or dates being parsed as types other than strings. - deprecation warnings - Deprecation warning APIs automatically capture the identity of the deprecating plugin. The ``collection_name`` argument is only required to correctly attribute deprecations that occur in module_utils or other non-plugin code. - deprecation warnings - Improved deprecation messages to more clearly indicate the affected content, including plugin name when available. - deprecations - Collection name strings not of the form ``ns.coll`` passed to deprecation API functions will result in an error. - deprecations - Removed support for specifying deprecation dates as a ``datetime.date``, which was included in an earlier 2.19 pre-release. - deprecations - Some argument names to ``deprecate_value`` for consistency with existing APIs. An earlier 2.19 pre-release included a ``removal_`` prefix on the ``date`` and ``version`` arguments. - modules - The ``AnsibleModule.deprecate`` function no longer sends deprecation messages to the target host's logging system. release_summary: '| Release Date: 2025-05-06 | `Porting Guide `__ ' codename: What Is and What Should Never Be fragments: - 2.19.0b3_summary.yaml - 85046-dnf5-history-entries.yml - ansible-test-container-stop.yml - config_priv.yml - deprecator.yml - ensure_remote_perms.yml release_date: '2025-05-06' 2.19.0b4: changes: bugfixes: - ansible-test - Updated the ``pylint`` sanity test to skip some deprecation validation checks when all arguments are dynamic. - config - Preserve or apply Origin tag to values returned by config. - config - Prevented fatal errors when ``MODULE_IGNORE_EXTS`` configuration was set. - config - Templating failures on config defaults now issue a warning. Previously, failures silently returned an unrendered and untrusted template to the caller. - config - ``ensure_type`` correctly propagates trust and other tags on returned values. - config - ``ensure_type`` now converts mappings to ``dict`` when requested, instead of returning the mapping. - config - ``ensure_type`` now converts sequences to ``list`` when requested, instead of returning the sequence. - config - ``ensure_type`` now correctly errors when ``pathlist`` or ``pathspec`` types encounter non-string list items. - config - ``ensure_type`` now reports an error when ``bytes`` are provided for any known ``value_type``. Previously, the behavior was undefined, but often resulted in an unhandled exception or incorrect return type. - config - ``ensure_type`` with expected type ``int`` now properly converts ``True`` and ``False`` values to ``int``. Previously, these values were silently returned unmodified. - convert_bool.boolean API conversion function - Unhashable values passed to ``boolean`` behave like other non-boolean convertible values, returning False or raising ``TypeError`` depending on the value of ``strict``. Previously, unhashable values always raised ``ValueError`` due to an invalid set membership check. - dnf5 - when ``bugfix`` and/or ``security`` is specified, skip packages that do not have any such updates, even for new versions of libdnf5 where this functionality changed and it is considered failure - plugin loader - Apply template trust to strings loaded from plugin configuration definitions and doc fragments. - template action - Template files where the entire file's output renders as ``None`` are no longer emitted as the string "None", but instead render to an empty file as in previous releases. minor_changes: - facts - add "CloudStack KVM Hypervisor" for Linux VM in virtual facts (https://github.com/ansible/ansible/issues/85089). - modules - use ``AnsibleModule.warn`` instead of passing ``warnings`` to ``exit_json`` or ``fail_json`` which is deprecated. release_summary: '| Release Date: 2025-05-12 | `Porting Guide `__ ' codename: What Is and What Should Never Be fragments: - 2.19.0b4_summary.yaml - 85117-add-cloudstack-kvm-for-linux-facts.yml - ansible-test-pylint-deprecated-fix.yml - dnf5-advisory-type.yml - ensure_type.yml - plugin-loader-trust-docs.yml - preserve_config_origin.yml - remove-warnings-retval.yml - template-none.yml release_date: '2025-05-12' 2.19.0b5: changes: bugfixes: - Core Jinja test plugins - Builtin test plugins now always return ``bool`` to avoid spurious deprecation warnings for some malformed inputs. - ansible-test - Disabled the ``bad-super-call`` pylint rule due to false positives. - ansible-test - Fix incorrect handling of options with optional args (e.g. ``--color``), when followed by other options which are omitted during arg filtering (e.g. ``--docker``). Previously it was possible for non-option arguments to be incorrectly omitted in these cases. (https://github.com/ansible/ansible/issues/85173) - ansible-test - Improve type inference for pylint deprecated checks to accommodate some type annotations. - async_status module - The ``started`` and ``finished`` return values are now ``True`` or ``False`` instead of ``1`` or ``0``. - constructed inventory - Use the ``default_value`` or ``trailing_separator`` in a ``keyed_groups`` entry if the expression result of ``key`` is ``None`` and not just an empty string. - dnf5 - handle all libdnf5 specific exceptions (https://github.com/ansible/ansible/issues/84634) - error handling - Error details and tracebacks from connection and built-in action exceptions are preserved. Previously, much of the detail was lost or mixed into the error message. - from_yaml_all filter - `None` and empty string inputs now always return an empty list. Previously, `None` was returned in Jinja native mode and empty list in classic mode. - local connection plugin - The command-line used to create subprocesses is now always ``str`` to avoid issues with debuggers and profilers. - ssh agent - Fixed several potential startup hangs for badly-behaved or overloaded ssh agents. - task timeout - Specifying a negative task timeout now results in an error. deprecated_features: - The ``ShellModule.checksum`` method is now deprecated and will be removed in ansible-core 2.23. Use ``ActionBase._execute_remote_stat()`` instead. - The ``ansible.module_utils.common.collections.count()`` function is deprecated and will be removed in ansible-core 2.23. Use ``collections.Counter()`` from the Python standard library instead. - '``ansible.compat.importlib_resources`` is deprecated and will be removed in ansible-core 2.23. Use ``importlib.resources`` from the Python standard library instead.' minor_changes: - Improved SUSE distribution detection in distribution.py by parsing VARIANT_ID from /etc/os-release for identifying SLES_SAP and SL-Micro. Falls back to /etc/products.d/baseproduct symlink for older systems. - Remove unnecessary shebang from the ``hostname`` module. - Use ``importlib.metadata.version()`` to detect Jinja version as jinja2.__version__ is deprecated and will be removed in Jinja 3.3. - ansible-doc - Return dynamic stub when reporting on Jinja filters and tests not explicitly documented in Ansible - ansible-doc - Skip listing the internal ``ansible._protomatter`` plugins unless explicitly requested - ansible-test - Add RHEL 10.0 as a remote platform for testing. - apt_repository - remove Python 2 support - csvfile lookup - remove Python 2 compat - display - Add ``help_text`` and ``obj`` to ``Display.error_as_warning``. - display - Replace Windows newlines (``\r\n``) in display output with Unix newlines (``\n``). This ensures proper display of strings sourced from Windows hosts in environments which treat ``\r`` as ``\n``, such as Azure Pipelines. - facts - add "Linode" for Linux VM in virtual facts - module_utils - Add ``AnsibleModule.error_as_warning``. - module_utils - Add ``ansible.module_utils.common.warnings.error_as_warning``. - module_utils - Add optional ``help_text`` argument to ``AnsibleModule.warn``. - ssh agent - Added ``SSH_AGENT_EXECUTABLE`` config to allow override of ssh-agent. - ssh connection plugin - Added ``verbosity`` config to decouple SSH debug output verbosity from Ansible verbosity. Previously, the Ansible verbosity value was always applied to the SSH client command-line, leading to excessively verbose output. Set the ``ANSIBLE_SSH_VERBOSITY`` envvar or ``ansible_ssh_verbosity`` Ansible variable to a positive integer to increase SSH client verbosity. - task timeout - Specifying a timeout greater than 100,000,000 now results in an error. - templating - Added ``_ANSIBLE_TEMPLAR_SANDBOX_MODE=allow_unsafe_attributes`` environment variable to disable Jinja template attribute sandbox. (https://github.com/ansible/ansible/issues/85202) - windows - Added support for ``#AnsibleRequires -Wrapper`` to request a PowerShell module be run through the execution wrapper scripts without any module utils specified. - windows - Added support for running signed modules and scripts with a Windows host protected by Windows App Control/WDAC. This is a tech preview and the interface may be subject to change. - windows - Script modules will preserve UTF-8 encoding when executing the script. release_summary: '| Release Date: 2025-06-03 | `Porting Guide `__ ' codename: What Is and What Should Never Be fragments: - 2.19.0b5_summary.yaml - 84634-dnf5-all-exceptions.yml - 85184-add-linode-for-linux-facts.yml - ansible-doc-jinja-builtins.yml - ansible-doc-protomatter.yml - ansible-test-delegation-options.yml - ansible-test-pylint-fix-inference.yml - ansible-test-rhel-10.yml - apt_repository-remove-py2-compat.yml - async_really_true.yml - constructed-default-value.yml - deprecate-compat-importlib-resources.yml - deprecate-shell-checksum.yml - detect-variantid-suse.yaml - display-windows-newline.yml - from_yaml_all.yml - jinja2-__version__-deprecated.yml - local_popen_text.yml - lookup-csvfile-remove-py2-compat.yml - module_utils-common-collections-counter-deprecated.yml - module_utils_warnings.yml - sandbox_config.yml - ssh_agent_misc.yml - ssh_verbosity.yml - task-error-and-timeout.yml - truthy_tests.yml - unnecessary-shebang.yml - windows-app-control.yml release_date: '2025-06-03' ansible_core-2.19.0b5/lib/0000755000000000000000000000000015017704211013761 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/0000755000000000000000000000000015017704211015376 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/__init__.py0000644000000000000000000000227715017704211017517 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . from __future__ import annotations # make vendored top-level modules accessible EARLY import ansible._vendor # Note: Do not add any code to this file. The ansible module may be # a namespace package when using Ansible-2.1+ Anything in this file may not be # available if one of the other packages in the namespace is loaded first. # # This is for backwards compat. Code should be ported to get these from # ansible.release instead of from here. from ansible.release import __version__, __author__ ansible_core-2.19.0b5/lib/ansible/__main__.py0000644000000000000000000000143415017704211017472 0ustar00rootroot# Copyright: (c) 2021, Matt Martz # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import argparse from importlib.metadata import distribution def _short_name(name): return name.removeprefix('ansible-').replace('ansible', 'adhoc') def main(): dist = distribution('ansible-core') ep_map = {_short_name(ep.name): ep for ep in dist.entry_points if ep.group == 'console_scripts'} parser = argparse.ArgumentParser(prog='python -m ansible', add_help=False) parser.add_argument('entry_point', choices=list(ep_map)) args, extra = parser.parse_known_args() main = ep_map[args.entry_point].load() main([args.entry_point] + extra) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/_internal/0000755000000000000000000000000015017704211017351 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/__init__.py0000644000000000000000000000424015017704211021462 0ustar00rootrootfrom __future__ import annotations import importlib import typing as t from ansible.module_utils import _internal from ansible.module_utils._internal._json import _profiles def get_controller_serialize_map() -> dict[type, t.Callable]: """ Injected into module_utils code to augment serialization maps with controller-only types. This implementation replaces the no-op version in module_utils._internal in controller contexts. """ from ansible._internal._templating import _lazy_containers from ansible.parsing.vault import EncryptedString return { _lazy_containers._AnsibleLazyTemplateDict: _profiles._JSONSerializationProfile.discard_tags, _lazy_containers._AnsibleLazyTemplateList: _profiles._JSONSerializationProfile.discard_tags, EncryptedString: str, # preserves tags since this is an instance of EncryptedString; if tags should be discarded from str, another entry will handle it } def import_controller_module(module_name: str, /) -> t.Any: """ Injected into module_utils code to import and return the specified module. This implementation replaces the no-op version in module_utils._internal in controller contexts. """ return importlib.import_module(module_name) _T = t.TypeVar('_T') def experimental(obj: _T) -> _T: """ Decorator for experimental types and methods outside the `_internal` package which accept or expose internal types. As with internal APIs, these are subject to change at any time without notice. """ return obj def setup() -> None: """No-op function to ensure that side-effect only imports of this module are not flagged/removed as 'unused'.""" # DTFIX-FUTURE: this is really fragile- disordered/incorrect imports (among other things) can mess it up. Consider a hosting-env-managed context # with an enum with at least Controller/Target/Unknown values, and possibly using lazy-init module shims or some other mechanism to allow controller-side # notification/augmentation of this kind of metadata. _internal.get_controller_serialize_map = get_controller_serialize_map _internal.import_controller_module = import_controller_module _internal.is_controller = True ansible_core-2.19.0b5/lib/ansible/_internal/_ansiballz.py0000644000000000000000000002660115017704211022046 0ustar00rootroot# shebang placeholder from __future__ import annotations import datetime # For test-module.py script to tell this is a ANSIBALLZ_WRAPPER _ANSIBALLZ_WRAPPER = True # This code is part of Ansible, but is an independent component. # The code in this particular templatable string, and this templatable string # only, is BSD licensed. Modules which end up using this snippet, which is # dynamically combined together by Ansible still belong to the author of the # module, and they may assign their own license to the complete work. # # Copyright (c), James Cammarata, 2016 # Copyright (c), Toshio Kuratomi, 2016 # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. def _ansiballz_main( zipdata: str, ansible_module: str, module_fqn: str, params: str, profile: str, date_time: datetime.datetime, coverage_config: str | None, coverage_output: str | None, rlimit_nofile: int, ) -> None: import os import os.path # Access to the working directory is required by Python when using pipelining, as well as for the coverage module. # Some platforms, such as macOS, may not allow querying the working directory when using become to drop privileges. try: os.getcwd() except OSError: try: os.chdir(os.path.expanduser('~')) except OSError: os.chdir('/') if rlimit_nofile: import resource existing_soft, existing_hard = resource.getrlimit(resource.RLIMIT_NOFILE) # adjust soft limit subject to existing hard limit requested_soft = min(existing_hard, rlimit_nofile) if requested_soft != existing_soft: try: resource.setrlimit(resource.RLIMIT_NOFILE, (requested_soft, existing_hard)) except ValueError: # some platforms (eg macOS) lie about their hard limit pass import sys import __main__ # For some distros and python versions we pick up this script in the temporary # directory. This leads to problems when the ansible module masks a python # library that another import needs. We have not figured out what about the # specific distros and python versions causes this to behave differently. # # Tested distros: # Fedora23 with python3.4 Works # Ubuntu15.10 with python2.7 Works # Ubuntu15.10 with python3.4 Fails without this # Ubuntu16.04.1 with python3.5 Fails without this # To test on another platform: # * use the copy module (since this shadows the stdlib copy module) # * Turn off pipelining # * Make sure that the destination file does not exist # * ansible ubuntu16-test -m copy -a 'src=/etc/motd dest=/var/tmp/m' # This will traceback in shutil. Looking at the complete traceback will show # that shutil is importing copy which finds the ansible module instead of the # stdlib module scriptdir = None try: scriptdir = os.path.dirname(os.path.realpath(__main__.__file__)) except (AttributeError, OSError): # Some platforms don't set __file__ when reading from stdin # OSX raises OSError if using abspath() in a directory we don't have # permission to read (realpath calls abspath) pass # Strip cwd from sys.path to avoid potential permissions issues excludes = {'', '.', scriptdir} sys.path = [p for p in sys.path if p not in excludes] import base64 import shutil import tempfile import zipfile def invoke_module(modlib_path: str, json_params: bytes) -> None: # When installed via setuptools (including python setup.py install), # ansible may be installed with an easy-install.pth file. That file # may load the system-wide install of ansible rather than the one in # the module. sitecustomize is the only way to override that setting. z = zipfile.ZipFile(modlib_path, mode='a') # py3: modlib_path will be text, py2: it's bytes. Need bytes at the end sitecustomize = u'import sys\\nsys.path.insert(0,"%s")\\n' % modlib_path sitecustomize = sitecustomize.encode('utf-8') # Use a ZipInfo to work around zipfile limitation on hosts with # clocks set to a pre-1980 year (for instance, Raspberry Pi) zinfo = zipfile.ZipInfo() zinfo.filename = 'sitecustomize.py' zinfo.date_time = date_time.utctimetuple()[:6] z.writestr(zinfo, sitecustomize) z.close() # Put the zipped up module_utils we got from the controller first in the python path so that we # can monkeypatch the right basic sys.path.insert(0, modlib_path) from ansible.module_utils._internal._ansiballz import run_module run_module( json_params=json_params, profile=profile, module_fqn=module_fqn, modlib_path=modlib_path, coverage_config=coverage_config, coverage_output=coverage_output, ) def debug(command: str, modlib_path: str, json_params: bytes) -> None: # The code here normally doesn't run. It's only used for debugging on the # remote machine. # # The subcommands in this function make it easier to debug ansiballz # modules. Here's the basic steps: # # Run ansible with the environment variable: ANSIBLE_KEEP_REMOTE_FILES=1 and -vvv # to save the module file remotely:: # $ ANSIBLE_KEEP_REMOTE_FILES=1 ansible host1 -m ping -a 'data=october' -vvv # # Part of the verbose output will tell you where on the remote machine the # module was written to:: # [...] # SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o # PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o # ControlPath=/home/badger/.ansible/cp/ansible-ssh-%h-%p-%r -tt rhel7 '/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-1461173013.93-9076457629738/ping'"'"'' # [...] # # Login to the remote machine and run the module file via from the previous # step with the explode subcommand to extract the module payload into # source files:: # $ ssh host1 # $ /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461173013.93-9076457629738/ping explode # Module expanded into: # /home/badger/.ansible/tmp/ansible-tmp-1461173408.08-279692652635227/ansible # # You can now edit the source files to instrument the code or experiment with # different parameter values. When you're ready to run the code you've modified # (instead of the code from the actual zipped module), use the execute subcommand like this:: # $ /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461173013.93-9076457629738/ping execute # Okay to use __file__ here because we're running from a kept file basedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'debug_dir') args_path = os.path.join(basedir, 'args') if command == 'explode': # transform the ZIPDATA into an exploded directory of code and then # print the path to the code. This is an easy way for people to look # at the code on the remote machine for debugging it in that # environment z = zipfile.ZipFile(modlib_path) for filename in z.namelist(): if filename.startswith('/'): raise Exception('Something wrong with this module zip file: should not contain absolute paths') dest_filename = os.path.join(basedir, filename) if dest_filename.endswith(os.path.sep) and not os.path.exists(dest_filename): os.makedirs(dest_filename) else: directory = os.path.dirname(dest_filename) if not os.path.exists(directory): os.makedirs(directory) with open(dest_filename, 'wb') as writer: writer.write(z.read(filename)) # write the args file with open(args_path, 'wb') as writer: writer.write(json_params) print('Module expanded into:') print(basedir) elif command == 'execute': # Execute the exploded code instead of executing the module from the # embedded ZIPDATA. This allows people to easily run their modified # code on the remote machine to see how changes will affect it. # Set pythonpath to the debug dir sys.path.insert(0, basedir) # read in the args file which the user may have modified with open(args_path, 'rb') as reader: json_params = reader.read() from ansible.module_utils._internal._ansiballz import run_module run_module( json_params=json_params, profile=profile, module_fqn=module_fqn, modlib_path=modlib_path, ) else: print(f'FATAL: Unknown debug command {command!r}. Doing nothing.') # # See comments in the debug() method for information on debugging # encoded_params = params.encode() # There's a race condition with the controller removing the # remote_tmpdir and this module executing under async. So we cannot # store this in remote_tmpdir (use system tempdir instead) # Only need to use [ansible_module]_payload_ in the temp_path until we move to zipimport # (this helps ansible-test produce coverage stats) temp_path = tempfile.mkdtemp(prefix='ansible_' + ansible_module + '_payload_') try: zipped_mod = os.path.join(temp_path, 'ansible_' + ansible_module + '_payload.zip') with open(zipped_mod, 'wb') as modlib: modlib.write(base64.b64decode(zipdata)) if len(sys.argv) == 2: debug(sys.argv[1], zipped_mod, encoded_params) else: invoke_module(zipped_mod, encoded_params) finally: shutil.rmtree(temp_path, ignore_errors=True) ansible_core-2.19.0b5/lib/ansible/_internal/_collection_proxy.py0000644000000000000000000000231415017704211023456 0ustar00rootrootfrom __future__ import annotations as _annotations import collections.abc as _c import typing as _t _T_co = _t.TypeVar('_T_co', covariant=True) class SequenceProxy(_c.Sequence[_T_co]): """A read-only sequence proxy.""" # DTFIX5: needs unit test coverage __slots__ = ('__value',) def __init__(self, value: _c.Sequence[_T_co]) -> None: self.__value = value @_t.overload def __getitem__(self, index: int) -> _T_co: ... @_t.overload def __getitem__(self, index: slice) -> _c.Sequence[_T_co]: ... def __getitem__(self, index: int | slice) -> _T_co | _c.Sequence[_T_co]: if isinstance(index, slice): return self.__class__(self.__value[index]) return self.__value[index] def __len__(self) -> int: return len(self.__value) def __contains__(self, item: object) -> bool: return item in self.__value def __iter__(self) -> _t.Iterator[_T_co]: yield from self.__value def __reversed__(self) -> _c.Iterator[_T_co]: return reversed(self.__value) def index(self, *args) -> int: return self.__value.index(*args) def count(self, value: object) -> int: return self.__value.count(value) ansible_core-2.19.0b5/lib/ansible/_internal/_datatag/0000755000000000000000000000000015017704211021115 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_datatag/__init__.py0000644000000000000000000000000015017704211023214 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_datatag/_tags.py0000644000000000000000000001207415017704211022570 0ustar00rootrootfrom __future__ import annotations import dataclasses import os import types import typing as t from ansible.module_utils._internal._datatag import _tag_dataclass_kwargs, AnsibleDatatagBase, AnsibleSingletonTagBase @dataclasses.dataclass(**_tag_dataclass_kwargs) class Origin(AnsibleDatatagBase): """ A tag that stores origin metadata for a tagged value, intended for forensic/diagnostic use. Origin metadata should not be used to make runtime decisions, as it is not guaranteed to be present or accurate. Setting both `path` and `line_num` can result in diagnostic display of referenced file contents. Either `path` or `description` must be present. """ path: str | None = None """The path from which the tagged content originated.""" description: str | None = None """A description of the origin, for display to users.""" line_num: int | None = None """An optional line number, starting at 1.""" col_num: int | None = None """An optional column number, starting at 1.""" UNKNOWN: t.ClassVar[t.Self] @classmethod def get_or_create_tag(cls, value: t.Any, path: str | os.PathLike | None) -> Origin: """Return the tag from the given value, creating a tag from the provided path if no tag was found.""" if not (origin := cls.get_tag(value)): if path: origin = Origin(path=str(path)) # convert tagged strings and path-like values to a native str else: origin = Origin.UNKNOWN return origin def replace( self, path: str | types.EllipsisType = ..., description: str | types.EllipsisType = ..., line_num: int | None | types.EllipsisType = ..., col_num: int | None | types.EllipsisType = ..., ) -> t.Self: """Return a new origin based on an existing one, with the given fields replaced.""" return dataclasses.replace( self, **{ key: value for key, value in dict( path=path, description=description, line_num=line_num, col_num=col_num, ).items() if value is not ... }, # type: ignore[arg-type] ) def _post_validate(self) -> None: if self.path: if not self.path.startswith('/'): raise RuntimeError('The `src` field must be an absolute path.') elif not self.description: raise RuntimeError('The `src` or `description` field must be specified.') def __str__(self) -> str: """Renders the origin in the form of path:line_num:col_num, omitting missing/invalid elements from the right.""" if self.path: value = self.path else: value = self.description if self.line_num and self.line_num > 0: value += f':{self.line_num}' if self.col_num and self.col_num > 0: value += f':{self.col_num}' if self.path and self.description: value += f' ({self.description})' return value Origin.UNKNOWN = Origin(description='') @dataclasses.dataclass(**_tag_dataclass_kwargs) class VaultedValue(AnsibleDatatagBase): """Tag for vault-encrypted strings that carries the original ciphertext for round-tripping.""" ciphertext: str def _get_tag_to_propagate(self, src: t.Any, value: object, *, value_type: t.Optional[type] = None) -> t.Self | None: # Since VaultedValue stores the encrypted representation of the value on which it is tagged, # it is incorrect to propagate the tag to a value which is not equal to the original. # If the tag were copied to another value and subsequently serialized as the original encrypted value, # the result would then differ from the value on which the tag was applied. # Comparisons which can trigger an exception are indicative of a bug and should not be handled here. # For example: # * When `src` is an undecryptable `EncryptedString` -- it is not valid to apply this tag to that type. # * When `value` is a `Marker` -- this requires a templating, but vaulted values do not support templating. if src == value: # assume the tag was correctly applied to src return self # same plaintext value, tag propagation with same ciphertext is safe return self.get_tag(value) # different value, preserve the existing tag, if any @dataclasses.dataclass(**_tag_dataclass_kwargs) class TrustedAsTemplate(AnsibleSingletonTagBase): """ Indicates the tagged string is trusted to parse and render as a template. Do *NOT* apply this tag to data from untrusted sources, as this would allow code injection during templating. """ @dataclasses.dataclass(**_tag_dataclass_kwargs) class SourceWasEncrypted(AnsibleSingletonTagBase): """ For internal use only. Indicates the tagged value was sourced from an encrypted file. Currently applied only by DataLoader.get_text_file_contents() and by extension DataLoader.load_from_file(). """ ansible_core-2.19.0b5/lib/ansible/_internal/_datatag/_utils.py0000644000000000000000000000141615017704211022770 0ustar00rootrootfrom __future__ import annotations from ansible.module_utils._internal._datatag import AnsibleTagHelper def str_problematic_strip(value: str) -> str: """ Return a copy of `value` with leading and trailing whitespace removed. Used where `str.strip` is needed, but tags must be preserved *AND* the stripping behavior likely shouldn't exist. If the stripping behavior is non-problematic, use `AnsibleTagHelper.tag_copy` around `str.strip` instead. """ if (stripped_value := value.strip()) == value: return value # FUTURE: consider deprecating some/all usages of this method; they generally imply a code smell or pattern we shouldn't be supporting stripped_value = AnsibleTagHelper.tag_copy(value, stripped_value) return stripped_value ansible_core-2.19.0b5/lib/ansible/_internal/_datatag/_wrappers.py0000644000000000000000000000216115017704211023471 0ustar00rootrootfrom __future__ import annotations import io import typing as _t from .._wrapt import ObjectProxy from ...module_utils._internal import _datatag class TaggedStreamWrapper(ObjectProxy): """ Janky proxy around IOBase to allow streams to carry tags and support basic interrogation by the tagging API. Most tagging operations will have undefined behavior for this type. """ _self__ansible_tags_mapping: _datatag._AnsibleTagsMapping def __init__(self, stream: io.IOBase, tags: _datatag.AnsibleDatatagBase | _t.Iterable[_datatag.AnsibleDatatagBase]) -> None: super().__init__(stream) tag_list: list[_datatag.AnsibleDatatagBase] # noinspection PyProtectedMember if type(tags) in _datatag._known_tag_types: tag_list = [tags] # type: ignore[list-item] else: tag_list = list(tags) # type: ignore[arg-type] self._self__ansible_tags_mapping = _datatag._AnsibleTagsMapping((type(tag), tag) for tag in tag_list) @property def _ansible_tags_mapping(self) -> _datatag._AnsibleTagsMapping: return self._self__ansible_tags_mapping ansible_core-2.19.0b5/lib/ansible/_internal/_errors/0000755000000000000000000000000015017704211021024 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_errors/__init__.py0000644000000000000000000000000015017704211023123 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_errors/_alarm_timeout.py0000644000000000000000000000472715017704211024411 0ustar00rootrootfrom __future__ import annotations import contextlib import signal import types import typing as _t from ansible.module_utils import datatag class AnsibleTimeoutError(BaseException): """A general purpose timeout.""" _MAX_TIMEOUT = 100_000_000 """ The maximum supported timeout value. This value comes from BSD's alarm limit, which is due to that function using setitimer. """ def __init__(self, timeout: int) -> None: self.timeout = timeout super().__init__(f"Timed out after {timeout} second(s).") @classmethod @contextlib.contextmanager def alarm_timeout(cls, timeout: int | None) -> _t.Iterator[None]: """ Context for running code under an optional timeout. Raises an instance of this class if the timeout occurs. New usages of this timeout mechanism are discouraged. """ if timeout is not None: if not isinstance(timeout, int): raise TypeError(f"Timeout requires 'int' argument, not {datatag.native_type_name(timeout)!r}.") if timeout < 0 or timeout > cls._MAX_TIMEOUT: # On BSD based systems, alarm is implemented using setitimer. # If out-of-bounds values are passed to alarm, they will return -1, which would be interpreted as an existing timer being set. # To avoid that, bounds checking is performed in advance. raise ValueError(f'Timeout {timeout} is invalid, it must be between 0 and {cls._MAX_TIMEOUT}.') if not timeout: yield # execute the context manager's body return # no timeout to deal with, exit immediately def on_alarm(_signal: int, _frame: types.FrameType) -> None: raise cls(timeout) if signal.signal(signal.SIGALRM, on_alarm): raise RuntimeError("An existing alarm handler was present.") try: try: if signal.alarm(timeout): raise RuntimeError("An existing alarm was set.") yield # execute the context manager's body finally: # Disable the alarm. # If the alarm fires inside this finally block, the alarm is still disabled. # This guarantees the cleanup code in the outer finally block runs without risk of encountering the `TaskTimeoutError` from the alarm. signal.alarm(0) finally: signal.signal(signal.SIGALRM, signal.SIG_DFL) ansible_core-2.19.0b5/lib/ansible/_internal/_errors/_captured.py0000644000000000000000000001062315017704211023346 0ustar00rootrootfrom __future__ import annotations import collections.abc as _c import dataclasses import typing as t from ansible._internal._errors import _error_utils from ansible.errors import AnsibleRuntimeError from ansible.module_utils._internal import _messages class AnsibleCapturedError(AnsibleRuntimeError): """An exception representing error detail captured in another context where the error detail must be serialized to be preserved.""" context: t.ClassVar[str] def __init__( self, *, obj: t.Any = None, event: _messages.Event, ) -> None: super().__init__( obj=obj, ) self._event = event class AnsibleResultCapturedError(AnsibleCapturedError, _error_utils.ContributesToTaskResult): """ An exception representing error detail captured in a foreign context where an action/module result dictionary is involved. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ def __init__(self, event: _messages.Event, result: dict[str, t.Any]) -> None: super().__init__(event=event) self._result = result @property def result_contribution(self) -> _c.Mapping[str, object]: return self._result @classmethod def maybe_raise_on_result(cls, result: dict[str, t.Any]) -> None: """Normalize the result and raise an exception if the result indicated failure.""" if error_summary := cls.normalize_result_exception(result): raise error_summary.error_type(error_summary.event, result) @classmethod def normalize_result_exception(cls, result: dict[str, t.Any]) -> CapturedErrorSummary | None: """ Normalize the result `exception`, if any, to be a `CapturedErrorSummary` instance. If a new `CapturedErrorSummary` was created, the `error_type` will be `cls`. The `exception` key will be removed if falsey. A `CapturedErrorSummary` instance will be returned if `failed` is truthy. """ if type(cls) is AnsibleResultCapturedError: # pylint: disable=unidiomatic-typecheck raise TypeError('The normalize_result_exception method cannot be called on the AnsibleCapturedError base type, use a derived type.') if not isinstance(result, dict): raise TypeError(f'Malformed result. Received {type(result)} instead of {dict}.') failed = result.get('failed') # DTFIX-FUTURE: warn if failed is present and not a bool, or exception is present without failed being True exception = result.pop('exception', None) if not failed and not exception: return None if isinstance(exception, CapturedErrorSummary): error_summary = exception elif isinstance(exception, _messages.ErrorSummary): error_summary = CapturedErrorSummary( event=exception.event, error_type=cls, ) else: # translate non-ErrorDetail errors error_summary = CapturedErrorSummary( event=_messages.Event( msg=str(result.get('msg', 'Unknown error.')), formatted_traceback=cls._normalize_traceback(exception), ), error_type=cls, ) result.update(exception=error_summary) return error_summary if failed else None # even though error detail was normalized, only return it if the result indicated failure @classmethod def _normalize_traceback(cls, value: object | None) -> str | None: """Normalize the provided traceback value, returning None if it is falsey.""" if not value: return None value = str(value).rstrip() if not value: return None return value + '\n' class AnsibleActionCapturedError(AnsibleResultCapturedError): """An exception representing error detail sourced directly by an action in its result dictionary.""" _default_message = 'Action failed.' context = 'action' class AnsibleModuleCapturedError(AnsibleResultCapturedError): """An exception representing error detail captured in a module context and returned from an action's result dictionary.""" _default_message = 'Module failed.' context = 'target' @dataclasses.dataclass(**_messages._dataclass_kwargs) class CapturedErrorSummary(_messages.ErrorSummary): error_type: type[AnsibleResultCapturedError] | None = None ansible_core-2.19.0b5/lib/ansible/_internal/_errors/_error_factory.py0000644000000000000000000000673415017704211024427 0ustar00rootrootfrom __future__ import annotations as _annotations from ansible.module_utils._internal import _errors, _messages class ControllerEventFactory(_errors.EventFactory): """Factory for creating `Event` instances from `BaseException` instances on the controller.""" def _get_msg(self, exception: BaseException) -> str | None: from ansible.errors import AnsibleError if not isinstance(exception, AnsibleError): return super()._get_msg(exception) return exception._original_message.strip() def _get_formatted_source_context(self, exception: BaseException) -> str | None: from ansible.errors import AnsibleError if not isinstance(exception, AnsibleError): return super()._get_formatted_source_context(exception) return exception._formatted_source_context def _get_help_text(self, exception: BaseException) -> str | None: from ansible.errors import AnsibleError if not isinstance(exception, AnsibleError): return super()._get_help_text(exception) return exception._help_text def _get_chain(self, exception: BaseException) -> _messages.EventChain | None: from ansible._internal._errors import _captured # avoid circular import due to AnsibleError import if isinstance(exception, _captured.AnsibleCapturedError): # a captured error provides its own cause event, it never has a normal __cause__ return _messages.EventChain( msg_reason=_errors.MSG_REASON_DIRECT_CAUSE, traceback_reason=f'The above {exception.context} exception was the direct cause of the following controller exception:', event=exception._event, ) return super()._get_chain(exception) def _follow_cause(self, exception: BaseException) -> bool: from ansible.errors import AnsibleError return not isinstance(exception, AnsibleError) or exception._include_cause_message def _get_cause(self, exception: BaseException) -> BaseException | None: # deprecated: description='remove support for orig_exc (deprecated in 2.23)' core_version='2.27' cause = super()._get_cause(exception) from ansible.errors import AnsibleError if not isinstance(exception, AnsibleError): return cause try: from ansible.utils.display import _display except Exception: # pylint: disable=broad-except # if config is broken, this can raise things other than ImportError _display = None if cause: if exception.orig_exc and exception.orig_exc is not cause and _display: _display.warning( msg=f"The `orig_exc` argument to `{type(exception).__name__}` was given, but differed from the cause given by `raise ... from`.", ) return cause if exception.orig_exc: if _display: # encourage the use of `raise ... from` before deprecating `orig_exc` _display.warning( msg=f"The `orig_exc` argument to `{type(exception).__name__}` was given without using `raise ... from orig_exc`.", ) return exception.orig_exc return None def _get_events(self, exception: BaseException) -> tuple[_messages.Event, ...] | None: if isinstance(exception, BaseExceptionGroup): return tuple(self._convert_exception(ex) for ex in exception.exceptions) return None ansible_core-2.19.0b5/lib/ansible/_internal/_errors/_error_utils.py0000644000000000000000000002166515017704211024120 0ustar00rootrootfrom __future__ import annotations import abc import collections.abc as _c import dataclasses import itertools import pathlib import textwrap import typing as t from ansible._internal._datatag._tags import Origin from ansible._internal._errors import _error_factory from ansible.module_utils._internal import _ambient_context, _event_utils, _messages, _traceback class ContributesToTaskResult(metaclass=abc.ABCMeta): """Exceptions may include this mixin to contribute task result dictionary data directly to the final result.""" @property @abc.abstractmethod def result_contribution(self) -> _c.Mapping[str, object]: """Mapping of results to apply to the task result.""" @property def omit_exception_key(self) -> bool: """Non-error exceptions (e.g., `AnsibleActionSkip`) must return `True` to ensure omission of the `exception` key.""" return False @property def omit_failed_key(self) -> bool: """Exceptions representing non-failure scenarios (e.g., `skipped`, `unreachable`) must return `True` to ensure omisson of the `failed` key.""" return False class RedactAnnotatedSourceContext(_ambient_context.AmbientContextBase): """When active, this context will redact annotated source lines, showing only the origin.""" @dataclasses.dataclass(kw_only=True, frozen=True) class SourceContext: origin: Origin annotated_source_lines: list[str] target_line: str | None def __str__(self) -> str: msg_lines = [f'Origin: {self.origin}'] if self.annotated_source_lines: msg_lines.append('') msg_lines.extend(self.annotated_source_lines) return '\n'.join(msg_lines) @classmethod def from_value(cls, value: t.Any) -> SourceContext | None: """Attempt to retrieve source and render a contextual indicator from the value's origin (if any).""" if value is None: return None if isinstance(value, Origin): origin = value value = None else: origin = Origin.get_tag(value) if RedactAnnotatedSourceContext.current(optional=True): return cls.error('content redacted') if origin and origin.path: return cls.from_origin(origin) if value is None: truncated_value = None annotated_source_lines = [] else: # DTFIX-FUTURE: cleanup/share width try: value = str(value) except Exception as ex: value = f'<< context unavailable: {ex} >>' truncated_value = textwrap.shorten(value, width=120) annotated_source_lines = [truncated_value] return SourceContext( origin=origin or Origin.UNKNOWN, annotated_source_lines=annotated_source_lines, target_line=truncated_value, ) @staticmethod def error(message: str | None, origin: Origin | None = None) -> SourceContext: return SourceContext( origin=origin, annotated_source_lines=[f'(source not shown: {message})'] if message else [], target_line=None, ) @classmethod def from_origin(cls, origin: Origin) -> SourceContext: """Attempt to retrieve source and render a contextual indicator of an error location.""" from ansible.parsing.vault import is_encrypted # avoid circular import # DTFIX-FUTURE: support referencing the column after the end of the target line, so we can indicate where a missing character (quote) needs to be added # this is also useful for cases like end-of-stream reported by the YAML parser # DTFIX-FUTURE: Implement line wrapping and match annotated line width to the terminal display width. context_line_count: t.Final = 2 max_annotated_line_width: t.Final = 120 truncation_marker: t.Final = '...' target_line_num = origin.line_num if RedactAnnotatedSourceContext.current(optional=True): return cls.error('content redacted', origin) if not target_line_num or target_line_num < 1: return cls.error(None, origin) # message omitted since lack of line number is obvious from pos start_line_idx = max(0, (target_line_num - 1) - context_line_count) # if near start of file target_col_num = origin.col_num try: with pathlib.Path(origin.path).open() as src: first_line = src.readline() lines = list(itertools.islice(itertools.chain((first_line,), src), start_line_idx, target_line_num)) except Exception as ex: return cls.error(type(ex).__name__, origin) if is_encrypted(first_line): return cls.error('content encrypted', origin) if len(lines) != target_line_num - start_line_idx: return cls.error('file truncated', origin) annotated_source_lines = [] line_label_width = len(str(target_line_num)) max_src_line_len = max_annotated_line_width - line_label_width - 1 usable_line_len = max_src_line_len for line_num, line in enumerate(lines, start_line_idx + 1): line = line.rstrip('\n') # universal newline default mode on `open` ensures we'll never see anything but \n line = line.replace('\t', ' ') # mixed tab/space handling is intentionally disabled since we're both format and display config agnostic if len(line) > max_src_line_len: line = line[: max_src_line_len - len(truncation_marker)] + truncation_marker usable_line_len = max_src_line_len - len(truncation_marker) annotated_source_lines.append(f'{str(line_num).rjust(line_label_width)}{" " if line else ""}{line}') if target_col_num and usable_line_len >= target_col_num >= 1: column_marker = f'column {target_col_num}' target_col_idx = target_col_num - 1 if target_col_idx + 2 + len(column_marker) > max_src_line_len: column_marker = f'{" " * (target_col_idx - len(column_marker) - 1)}{column_marker} ^' else: column_marker = f'{" " * target_col_idx}^ {column_marker}' column_marker = f'{" " * line_label_width} {column_marker}' annotated_source_lines.append(column_marker) elif target_col_num is None: underline_length = len(annotated_source_lines[-1]) - line_label_width - 1 annotated_source_lines.append(f'{" " * line_label_width} {"^" * underline_length}') return SourceContext( origin=origin, annotated_source_lines=annotated_source_lines, target_line=lines[-1].rstrip('\n'), # universal newline default mode on `open` ensures we'll never see anything but \n ) def format_exception_message(exception: BaseException) -> str: """Return the full chain of exception messages by concatenating the cause(s) until all are exhausted.""" return _event_utils.format_event_brief_message(_error_factory.ControllerEventFactory.from_exception(exception, False)) def result_dict_from_exception(exception: BaseException, accept_result_contribution: bool = False) -> dict[str, object]: """Return a failed task result dict from the given exception.""" event = _error_factory.ControllerEventFactory.from_exception(exception, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR)) result: dict[str, object] = {} omit_failed_key = False omit_exception_key = False if accept_result_contribution: while exception: if isinstance(exception, ContributesToTaskResult): result = dict(exception.result_contribution) omit_failed_key = exception.omit_failed_key omit_exception_key = exception.omit_exception_key break exception = exception.__cause__ if omit_failed_key: result.pop('failed', None) else: result.update(failed=True) if omit_exception_key: result.pop('exception', None) else: result.update(exception=_messages.ErrorSummary(event=event)) if 'msg' not in result: # if nothing contributed `msg`, generate one from the exception messages result.update(msg=_event_utils.format_event_brief_message(event)) return result def result_dict_from_captured_errors( msg: str, *, errors: list[_messages.ErrorSummary] | None = None, ) -> dict[str, object]: """Return a failed task result dict from the given error message and captured errors.""" _skip_stackwalk = True event = _messages.Event( msg=msg, formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.ERROR), events=tuple(error.event for error in errors) if errors else None, ) result = dict( failed=True, exception=_messages.ErrorSummary( event=event, ), msg=_event_utils.format_event_brief_message(event), ) return result ansible_core-2.19.0b5/lib/ansible/_internal/_errors/_handler.py0000644000000000000000000000657715017704211023171 0ustar00rootrootfrom __future__ import annotations import contextlib import enum import typing as t from ansible.utils.display import Display from ansible.constants import config display = Display() # FUTURE: add sanity test to detect use of skip_on_ignore without Skippable (and vice versa) class ErrorAction(enum.Enum): """Action to take when an error is encountered.""" IGNORE = enum.auto() WARNING = enum.auto() ERROR = enum.auto() @classmethod def from_config(cls, setting: str, variables: dict[str, t.Any] | None = None) -> t.Self: """Return an `ErrorAction` enum from the specified Ansible config setting.""" return cls[config.get_config_value(setting, variables=variables).upper()] class _SkipException(BaseException): """Internal flow control exception for skipping code blocks within a `Skippable` context manager.""" def __init__(self) -> None: super().__init__('Skipping ignored action due to use of `skip_on_ignore`. It is a bug to encounter this message outside of debugging.') class _SkippableContextManager: """Internal context manager to support flow control for skipping code blocks.""" def __enter__(self) -> None: pass def __exit__(self, exc_type, _exc_val, _exc_tb) -> bool: if exc_type is None: raise RuntimeError('A `Skippable` context manager was entered, but a `skip_on_ignore` handler was never invoked.') return exc_type is _SkipException # only mask a _SkipException, allow all others to raise Skippable = _SkippableContextManager() """Context manager singleton required to enclose `ErrorHandler.handle` invocations when `skip_on_ignore` is `True`.""" class ErrorHandler: """ Provides a configurable error handler context manager for a specific list of exception types. Unhandled errors leaving the context manager can be ignored, treated as warnings, or allowed to raise by setting `ErrorAction`. """ def __init__(self, action: ErrorAction) -> None: self.action = action @contextlib.contextmanager def handle(self, *args: type[BaseException], skip_on_ignore: bool = False) -> t.Iterator[None]: """ Handle the specified exception(s) using the defined error action. If `skip_on_ignore` is `True`, the body of the context manager will be skipped for `ErrorAction.IGNORE`. Use of `skip_on_ignore` requires enclosure within the `Skippable` context manager. """ if not args: raise ValueError('At least one exception type is required.') if skip_on_ignore and self.action == ErrorAction.IGNORE: raise _SkipException() # skipping ignored action try: yield except args as ex: match self.action: case ErrorAction.WARNING: display.error_as_warning(msg=None, exception=ex) case ErrorAction.ERROR: raise case _: # ErrorAction.IGNORE pass if skip_on_ignore: raise _SkipException() # completed skippable action, ensures the `Skippable` context was used @classmethod def from_config(cls, setting: str, variables: dict[str, t.Any] | None = None) -> t.Self: """Return an `ErrorHandler` instance configured using the specified Ansible config setting.""" return cls(ErrorAction.from_config(setting, variables=variables)) ansible_core-2.19.0b5/lib/ansible/_internal/_errors/_task_timeout.py0000644000000000000000000000163315017704211024250 0ustar00rootrootfrom __future__ import annotations from collections import abc as _c from ansible._internal._errors._alarm_timeout import AnsibleTimeoutError from ansible._internal._errors._error_utils import ContributesToTaskResult from ansible.module_utils.datatag import deprecate_value class TaskTimeoutError(AnsibleTimeoutError, ContributesToTaskResult): """ A task-specific timeout. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ @property def result_contribution(self) -> _c.Mapping[str, object]: help_text = "Configure `DISPLAY_TRACEBACK` to see a traceback on timeout errors." frame = deprecate_value( value=help_text, msg="The `timedout.frame` task result key is deprecated.", help_text=help_text, version="2.23", ) return dict(timedout=dict(frame=frame, period=self.timeout)) ansible_core-2.19.0b5/lib/ansible/_internal/_event_formatting.py0000644000000000000000000001017615017704211023442 0ustar00rootrootfrom __future__ import annotations as _annotations import collections.abc as _c import textwrap as _textwrap from ansible.module_utils._internal import _event_utils, _messages def format_event(event: _messages.Event, include_traceback: bool) -> str: """Format an event into a verbose message and traceback.""" msg = format_event_verbose_message(event) if include_traceback: msg += '\n' + format_event_traceback(event) msg = msg.strip() if '\n' in msg: msg += '\n\n' else: msg += '\n' return msg def format_event_traceback(event: _messages.Event) -> str: """Format an event into a traceback.""" segments: list[str] = [] while event: segment = event.formatted_traceback or '(traceback missing)\n' if event.events: child_tracebacks = [format_event_traceback(child) for child in event.events] segment += _format_event_children("Sub-Traceback", child_tracebacks) segments.append(segment) if event.chain: segments.append(f'\n{event.chain.traceback_reason}\n\n') event = event.chain.event else: event = None return ''.join(reversed(segments)) def format_event_verbose_message(event: _messages.Event) -> str: """ Format an event into a verbose message. Help text, contextual information and sub-events will be included. """ segments: list[str] = [] original_event = event while event: messages = [event.msg] chain: _messages.EventChain = event.chain while chain and chain.follow: if chain.event.events: break # do not collapse a chained event with sub-events, since they would be lost if chain.event.formatted_source_context or chain.event.help_text: if chain.event.formatted_source_context != event.formatted_source_context or chain.event.help_text != event.help_text: break # do not collapse a chained event with different details, since they would be lost if chain.event.chain and chain.msg_reason != chain.event.chain.msg_reason: break # do not collapse a chained event which has a chain with a different msg_reason messages.append(chain.event.msg) chain = chain.event.chain msg = _event_utils.deduplicate_message_parts(messages) segment = '\n'.join(_get_message_lines(msg, event.help_text, event.formatted_source_context)) + '\n' if event.events: child_msgs = [format_event_verbose_message(child) for child in event.events] segment += _format_event_children("Sub-Event", child_msgs) segments.append(segment) if chain and chain.follow: segments.append(f'\n{chain.msg_reason}\n\n') event = chain.event else: event = None if len(segments) > 1: segments.insert(0, _event_utils.format_event_brief_message(original_event) + '\n\n') return ''.join(segments) def _format_event_children(label: str, children: _c.Iterable[str]) -> str: """Format the given list of child messages into a single string.""" items = list(children) count = len(items) lines = ['\n'] for idx, item in enumerate(items): lines.append(f'+--[ {label} {idx + 1} of {count} ]---\n') lines.append(_textwrap.indent(f"\n{item}\n", "| ", lambda value: True)) lines.append(f'+--[ End {label} ]---\n') return ''.join(lines) def _get_message_lines(message: str, help_text: str | None, formatted_source_context: str | None) -> list[str]: """Return a list of message lines constructed from the given message, help text and formatted source context.""" if help_text and not formatted_source_context and '\n' not in message and '\n' not in help_text: return [f'{message} {help_text}'] # prefer a single-line message with help text when there is no source context message_lines = [message] if formatted_source_context: message_lines.append(formatted_source_context) if help_text: message_lines.append('') message_lines.append(help_text) return message_lines ansible_core-2.19.0b5/lib/ansible/_internal/_json/0000755000000000000000000000000015017704211020461 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_json/__init__.py0000644000000000000000000002113415017704211022573 0ustar00rootroot"""Internal utilities for serialization and deserialization.""" # DTFIX-FUTURE: most of this isn't JSON specific, find a better home from __future__ import annotations import enum import json import typing as t from ansible.errors import AnsibleVariableTypeError from ansible.module_utils._internal._datatag import ( _ANSIBLE_ALLOWED_MAPPING_VAR_TYPES, _ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES, _ANSIBLE_ALLOWED_VAR_TYPES, _AnsibleTaggedStr, AnsibleTagHelper, ) from ansible.module_utils._internal._json._profiles import _tagless from ansible.parsing.vault import EncryptedString from ansible._internal._datatag._tags import Origin, TrustedAsTemplate from ansible._internal._templating import _transform from ansible.module_utils import _internal from ansible.module_utils._internal import _datatag _T = t.TypeVar('_T') _sentinel = object() class HasCurrent(t.Protocol): """Utility protocol for mixin type safety.""" _current: t.Any class StateTrackingMixIn(HasCurrent): """Mixin for use with `AnsibleVariableVisitor` to track current visitation context.""" def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self._stack: list[t.Any] = [] def __enter__(self) -> None: self._stack.append(self._current) def __exit__(self, *_args, **_kwargs) -> None: self._stack.pop() def _get_stack(self) -> list[t.Any]: if not self._stack: return [] return self._stack[1:] + [self._current] class EncryptedStringBehavior(enum.Enum): """How `AnsibleVariableVisitor` will handle instances of `EncryptedString`.""" PRESERVE = enum.auto() """Preserves the unmodified `EncryptedString` instance.""" DECRYPT = enum.auto() """Replaces the value with its decrypted plaintext.""" REDACT = enum.auto() """Replaces the value with a placeholder string.""" FAIL = enum.auto() """Raises an `AnsibleVariableTypeError` error.""" class AnsibleVariableVisitor: """Utility visitor base class to recursively apply various behaviors and checks to variable object graphs.""" def __init__( self, *, trusted_as_template: bool = False, origin: Origin | None = None, convert_mapping_to_dict: bool = False, convert_sequence_to_list: bool = False, convert_custom_scalars: bool = False, convert_to_native_values: bool = False, apply_transforms: bool = False, encrypted_string_behavior: EncryptedStringBehavior = EncryptedStringBehavior.DECRYPT, ): super().__init__() # supports StateTrackingMixIn self.trusted_as_template = trusted_as_template self.origin = origin self.convert_mapping_to_dict = convert_mapping_to_dict self.convert_sequence_to_list = convert_sequence_to_list self.convert_custom_scalars = convert_custom_scalars self.convert_to_native_values = convert_to_native_values self.apply_transforms = apply_transforms self.encrypted_string_behavior = encrypted_string_behavior if apply_transforms: from ansible._internal._templating import _engine self._template_engine = _engine.TemplateEngine() else: self._template_engine = None self._current: t.Any = None # supports StateTrackingMixIn def __enter__(self) -> t.Any: """No-op context manager dispatcher (delegates to mixin behavior if present).""" if func := getattr(super(), '__enter__', None): func() def __exit__(self, *args, **kwargs) -> t.Any: """No-op context manager dispatcher (delegates to mixin behavior if present).""" if func := getattr(super(), '__exit__', None): func(*args, **kwargs) def visit(self, value: _T) -> _T: """ Enforces Ansible's variable type system restrictions before a var is accepted in inventory. Also, conditionally implements template trust compatibility, depending on the plugin's declared understanding (or lack thereof). This always recursively copies inputs to fully isolate inventory data from what the plugin provided, and prevent any later mutation. """ return self._visit(None, value) def _early_visit(self, value, value_type) -> t.Any: """Overridable hook point to allow custom string handling in derived visitors.""" if value_type in (str, _AnsibleTaggedStr): # apply compatibility behavior if self.trusted_as_template: result = TrustedAsTemplate().tag(value) else: result = value else: result = _sentinel return result def _visit(self, key: t.Any, value: _T) -> _T: """Internal implementation to recursively visit a data structure's contents.""" self._current = key # supports StateTrackingMixIn value_type = type(value) if self.apply_transforms and value_type in _transform._type_transform_mapping: value = self._template_engine.transform(value) value_type = type(value) # DTFIX3: need to handle native copy for keys too if self.convert_to_native_values and isinstance(value, _datatag.AnsibleTaggedObject): value = value._native_copy() value_type = type(value) result: _T # DTFIX3: the visitor is ignoring dict/mapping keys except for debugging and schema-aware checking, it should be doing type checks on keys # keep in mind the allowed types for keys is a more restrictive set than for values (str and tagged str only, not EncryptedString) # DTFIX5: some type lists being consulted (the ones from datatag) are probably too permissive, and perhaps should not be dynamic if (result := self._early_visit(value, value_type)) is not _sentinel: pass # DTFIX7: de-duplicate and optimize; extract inline generator expressions and fallback function or mapping for native type calculation? elif value_type in _ANSIBLE_ALLOWED_MAPPING_VAR_TYPES: # check mappings first, because they're also collections with self: # supports StateTrackingMixIn result = AnsibleTagHelper.tag_copy(value, ((k, self._visit(k, v)) for k, v in value.items()), value_type=value_type) elif value_type in _ANSIBLE_ALLOWED_NON_SCALAR_COLLECTION_VAR_TYPES: with self: # supports StateTrackingMixIn result = AnsibleTagHelper.tag_copy(value, (self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))), value_type=value_type) elif self.encrypted_string_behavior != EncryptedStringBehavior.FAIL and isinstance(value, EncryptedString): match self.encrypted_string_behavior: case EncryptedStringBehavior.REDACT: result = "" # type: ignore[assignment] case EncryptedStringBehavior.PRESERVE: result = value # type: ignore[assignment] case EncryptedStringBehavior.DECRYPT: result = str(value) # type: ignore[assignment] elif self.convert_mapping_to_dict and _internal.is_intermediate_mapping(value): with self: # supports StateTrackingMixIn result = {k: self._visit(k, v) for k, v in value.items()} # type: ignore[assignment] elif self.convert_sequence_to_list and _internal.is_intermediate_iterable(value): with self: # supports StateTrackingMixIn result = [self._visit(k, v) for k, v in enumerate(t.cast(t.Iterable, value))] # type: ignore[assignment] elif self.convert_custom_scalars and isinstance(value, str): result = str(value) # type: ignore[assignment] elif self.convert_custom_scalars and isinstance(value, float): result = float(value) # type: ignore[assignment] elif self.convert_custom_scalars and isinstance(value, int) and not isinstance(value, bool): result = int(value) # type: ignore[assignment] else: if value_type not in _ANSIBLE_ALLOWED_VAR_TYPES: raise AnsibleVariableTypeError.from_value(obj=value) # supported scalar type that requires no special handling, just return as-is result = value if self.origin and not Origin.is_tagged_on(result): # apply shared instance default origin tag result = self.origin.tag(result) return result def json_dumps_formatted(value: object) -> str: """Return a JSON dump of `value` with formatting and keys sorted.""" return json.dumps(value, cls=_tagless.Encoder, sort_keys=True, indent=4) ansible_core-2.19.0b5/lib/ansible/_internal/_json/_legacy_encoder.py0000644000000000000000000000315615017704211024142 0ustar00rootrootfrom __future__ import annotations as _annotations import typing as _t from ansible.module_utils._internal._json import _profiles from ansible._internal._json._profiles import _legacy from ansible.parsing import vault as _vault class LegacyControllerJSONEncoder(_legacy.Encoder): """Compatibility wrapper over `legacy` profile JSON encoder to support trust stripping and vault value plaintext conversion.""" def __init__(self, preprocess_unsafe: bool = False, vault_to_text: bool = False, _decode_bytes: bool = False, **kwargs) -> None: self._preprocess_unsafe = preprocess_unsafe self._vault_to_text = vault_to_text self._decode_bytes = _decode_bytes super().__init__(**kwargs) def default(self, o: _t.Any) -> _t.Any: """Hooked default that can conditionally bypass base encoder behavior based on this instance's config.""" if type(o) is _profiles._WrappedValue: # pylint: disable=unidiomatic-typecheck o = o.wrapped if not self._preprocess_unsafe and type(o) is _legacy._Untrusted: # pylint: disable=unidiomatic-typecheck return o.value # if not emitting unsafe markers, bypass custom unsafe serialization and just return the raw value if self._vault_to_text and type(o) is _vault.EncryptedString: # pylint: disable=unidiomatic-typecheck return str(o) # decrypt and return the plaintext (or fail trying) if self._decode_bytes and isinstance(o, bytes): return o.decode(errors='surrogateescape') # backward compatibility with `ansible.module_utils.basic.jsonify` return super().default(o) ansible_core-2.19.0b5/lib/ansible/_internal/_json/_profiles/0000755000000000000000000000000015017704211022443 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_json/_profiles/__init__.py0000644000000000000000000000000015017704211024542 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_json/_profiles/_cache_persistence.py0000644000000000000000000000357115017704211026631 0ustar00rootrootfrom __future__ import annotations import datetime as _datetime from ansible.module_utils._internal import _datatag from ansible.module_utils._internal._json import _profiles from ansible.parsing import vault as _vault from ansible._internal._datatag import _tags class _Profile(_profiles._JSONSerializationProfile): """Profile for external cache persistence of inventory/fact data that preserves most tags.""" serialize_map = {} schema_id = 1 @classmethod def post_init(cls, **kwargs): cls.allowed_ansible_serializable_types = ( _profiles._common_module_types | _profiles._common_module_response_types | { _datatag._AnsibleTaggedDate, _datatag._AnsibleTaggedTime, _datatag._AnsibleTaggedDateTime, _datatag._AnsibleTaggedStr, _datatag._AnsibleTaggedInt, _datatag._AnsibleTaggedFloat, _datatag._AnsibleTaggedList, _datatag._AnsibleTaggedSet, _datatag._AnsibleTaggedTuple, _datatag._AnsibleTaggedDict, _tags.SourceWasEncrypted, _tags.Origin, _tags.TrustedAsTemplate, _vault.EncryptedString, _vault.VaultedValue, } ) cls.serialize_map = { set: cls.serialize_as_list, tuple: cls.serialize_as_list, _datetime.date: _datatag.AnsibleSerializableDate, _datetime.time: _datatag.AnsibleSerializableTime, _datetime.datetime: _datatag.AnsibleSerializableDateTime, } cls.handle_key = cls._handle_key_str_fallback # legacy stdlib-compatible key behavior class Encoder(_profiles.AnsibleProfileJSONEncoder): _profile = _Profile class Decoder(_profiles.AnsibleProfileJSONDecoder): _profile = _Profile ansible_core-2.19.0b5/lib/ansible/_internal/_json/_profiles/_inventory_legacy.py0000644000000000000000000000207315017704211026537 0ustar00rootroot""" Backwards compatibility profile for serialization for persisted ansible-inventory output. Behavior is equivalent to pre 2.18 `AnsibleJSONEncoder` with vault_to_text=True. """ from __future__ import annotations from ... import _json from . import _legacy class _InventoryVariableVisitor(_legacy._LegacyVariableVisitor, _json.StateTrackingMixIn): """State-tracking visitor implementation that only applies trust to `_meta.hostvars` and `vars` inventory values.""" # DTFIX5: does the variable visitor need to support conversion of sequence/mapping for inventory? @property def _allow_trust(self) -> bool: stack = self._get_stack() if len(stack) >= 4 and stack[:2] == ['_meta', 'hostvars']: return True if len(stack) >= 3 and stack[1] == 'vars': return True return False class _Profile(_legacy._Profile): visitor_type = _InventoryVariableVisitor encode_strings_as_utf8 = True class Encoder(_legacy.Encoder): _profile = _Profile class Decoder(_legacy.Decoder): _profile = _Profile ansible_core-2.19.0b5/lib/ansible/_internal/_json/_profiles/_legacy.py0000644000000000000000000001660315017704211024426 0ustar00rootroot""" Backwards compatibility profile for serialization other than inventory (which should use inventory_legacy for backward-compatible trust behavior). Behavior is equivalent to pre 2.18 `AnsibleJSONEncoder` with vault_to_text=True. """ from __future__ import annotations as _annotations import datetime as _datetime import typing as _t from ansible._internal import _json from ansible._internal._datatag import _tags from ansible.module_utils._internal import _datatag from ansible.module_utils._internal._json import _profiles from ansible.parsing import vault as _vault class _Untrusted: """ Temporarily wraps strings which are not trusted for templating. Used before serialization of strings not tagged TrustedAsTemplate when trust inversion is enabled and trust is allowed in the string's context. Used during deserialization of `__ansible_unsafe` strings to indicate they should not be tagged TrustedAsTemplate. """ __slots__ = ('value',) def __init__(self, value: str) -> None: self.value = value class _LegacyVariableVisitor(_json.AnsibleVariableVisitor): """Variable visitor that supports optional trust inversion for legacy serialization.""" def __init__( self, *, trusted_as_template: bool = False, invert_trust: bool = False, origin: _tags.Origin | None = None, convert_mapping_to_dict: bool = False, convert_sequence_to_list: bool = False, convert_custom_scalars: bool = False, ): super().__init__( trusted_as_template=trusted_as_template, origin=origin, convert_mapping_to_dict=convert_mapping_to_dict, convert_sequence_to_list=convert_sequence_to_list, convert_custom_scalars=convert_custom_scalars, encrypted_string_behavior=_json.EncryptedStringBehavior.PRESERVE, ) self.invert_trust = invert_trust if trusted_as_template and invert_trust: raise ValueError('trusted_as_template is mutually exclusive with invert_trust') @property def _allow_trust(self) -> bool: """ This profile supports trust application in all contexts. Derived implementations can override this behavior for application-dependent/schema-aware trust. """ return True def _early_visit(self, value, value_type) -> _t.Any: """Similar to base implementation, but supports an intermediate wrapper for trust inversion.""" if value_type in (str, _datatag._AnsibleTaggedStr): # apply compatibility behavior if self.trusted_as_template and self._allow_trust: result = _tags.TrustedAsTemplate().tag(value) elif self.invert_trust and not _tags.TrustedAsTemplate.is_tagged_on(value) and self._allow_trust: result = _Untrusted(value) else: result = value elif value_type is _Untrusted: result = value.value else: result = _json._sentinel return result class _Profile(_profiles._JSONSerializationProfile["Encoder", "Decoder"]): visitor_type = _LegacyVariableVisitor @classmethod def serialize_untrusted(cls, value: _Untrusted) -> dict[str, str] | str: return dict( __ansible_unsafe=_datatag.AnsibleTagHelper.untag(value.value), ) @classmethod def serialize_tagged_str(cls, value: _datatag.AnsibleTaggedObject) -> _t.Any: if ciphertext := _vault.VaultHelper.get_ciphertext(value, with_tags=False): return dict( __ansible_vault=ciphertext, ) return _datatag.AnsibleTagHelper.untag(value) @classmethod def deserialize_unsafe(cls, value: dict[str, _t.Any]) -> _Untrusted: ansible_unsafe = value['__ansible_unsafe'] if type(ansible_unsafe) is not str: # pylint: disable=unidiomatic-typecheck raise TypeError(f"__ansible_unsafe is {type(ansible_unsafe)} not {str}") return _Untrusted(ansible_unsafe) @classmethod def deserialize_vault(cls, value: dict[str, _t.Any]) -> _vault.EncryptedString: ansible_vault = value['__ansible_vault'] if type(ansible_vault) is not str: # pylint: disable=unidiomatic-typecheck raise TypeError(f"__ansible_vault is {type(ansible_vault)} not {str}") encrypted_string = _vault.EncryptedString(ciphertext=ansible_vault) return encrypted_string @classmethod def serialize_encrypted_string(cls, value: _vault.EncryptedString) -> dict[str, str]: return dict( __ansible_vault=_vault.VaultHelper.get_ciphertext(value, with_tags=False), ) @classmethod def post_init(cls) -> None: cls.serialize_map = { set: cls.serialize_as_list, tuple: cls.serialize_as_list, _datetime.date: cls.serialize_as_isoformat, # existing devel behavior _datetime.time: cls.serialize_as_isoformat, # always failed pre-2.18, so okay to include for consistency _datetime.datetime: cls.serialize_as_isoformat, # existing devel behavior _datatag._AnsibleTaggedDate: cls.discard_tags, _datatag._AnsibleTaggedTime: cls.discard_tags, _datatag._AnsibleTaggedDateTime: cls.discard_tags, _vault.EncryptedString: cls.serialize_encrypted_string, _datatag._AnsibleTaggedStr: cls.serialize_tagged_str, # for VaultedValue tagged str _datatag._AnsibleTaggedInt: cls.discard_tags, _datatag._AnsibleTaggedFloat: cls.discard_tags, _datatag._AnsibleTaggedList: cls.discard_tags, _datatag._AnsibleTaggedSet: cls.discard_tags, _datatag._AnsibleTaggedTuple: cls.discard_tags, _datatag._AnsibleTaggedDict: cls.discard_tags, _Untrusted: cls.serialize_untrusted, # equivalent to AnsibleJSONEncoder(preprocess_unsafe=True) in devel } cls.deserialize_map = { '__ansible_unsafe': cls.deserialize_unsafe, '__ansible_vault': cls.deserialize_vault, } cls.handle_key = cls._handle_key_str_fallback # type: ignore[method-assign] # legacy stdlib-compatible key behavior @classmethod def pre_serialize(cls, encoder: Encoder, o: _t.Any) -> _t.Any: # DTFIX7: these conversion args probably aren't needed avv = cls.visitor_type(invert_trust=True, convert_mapping_to_dict=True, convert_sequence_to_list=True, convert_custom_scalars=True) return avv.visit(o) @classmethod def post_deserialize(cls, decoder: Decoder, o: _t.Any) -> _t.Any: avv = cls.visitor_type(trusted_as_template=decoder._trusted_as_template, origin=decoder._origin) return avv.visit(o) class Encoder(_profiles.AnsibleProfileJSONEncoder): _profile = _Profile class Decoder(_profiles.AnsibleProfileJSONDecoder): _profile = _Profile def __init__(self, **kwargs) -> None: super().__init__(**kwargs) # NB: these can only be sampled properly when loading strings, eg, `json.loads`; the global `json.load` function does not expose the file-like to us self._origin: _tags.Origin | None = None self._trusted_as_template: bool = False def raw_decode(self, s: str, idx: int = 0) -> tuple[_t.Any, int]: self._origin = _tags.Origin.get_tag(s) self._trusted_as_template = _tags.TrustedAsTemplate.is_tagged_on(s) return super().raw_decode(s, idx) ansible_core-2.19.0b5/lib/ansible/_internal/_locking.py0000644000000000000000000000123515017704211021511 0ustar00rootrootfrom __future__ import annotations import contextlib import fcntl import typing as t @contextlib.contextmanager def named_mutex(path: str) -> t.Iterator[None]: """ Lightweight context manager wrapper over `fcntl.flock` to provide IPC locking via a shared filename. Entering the context manager blocks until the lock is acquired. The lock file will be created automatically, but creation of the parent directory and deletion of the lockfile are the caller's responsibility. """ with open(path, 'a') as file: fcntl.flock(file, fcntl.LOCK_EX) try: yield finally: fcntl.flock(file, fcntl.LOCK_UN) ansible_core-2.19.0b5/lib/ansible/_internal/_plugins/0000755000000000000000000000000015017704211021171 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_plugins/__init__.py0000644000000000000000000000000015017704211023270 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_plugins/_cache.py0000644000000000000000000000370515017704211022752 0ustar00rootrootfrom __future__ import annotations import functools import json import json.encoder import json.decoder import typing as t from .._wrapt import ObjectProxy from .._json._profiles import _cache_persistence class PluginInterposer(ObjectProxy): """Proxies a Cache plugin instance to implement transparent encapsulation of serialized Ansible internal data types.""" _PAYLOAD_KEY = '__payload__' """The key used to store the serialized payload.""" def get(self, key: str) -> dict[str, object]: return self._decode(self.__wrapped__.get(self._get_key(key))) def set(self, key: str, value: dict[str, object]) -> None: self.__wrapped__.set(self._get_key(key), self._encode(value)) def keys(self) -> t.Sequence[str]: return [k for k in (self._restore_key(k) for k in self.__wrapped__.keys()) if k is not None] def contains(self, key: t.Any) -> bool: return self.__wrapped__.contains(self._get_key(key)) def delete(self, key: str) -> None: self.__wrapped__.delete(self._get_key(key)) @classmethod def _restore_key(cls, wrapped_key: str) -> str | None: prefix = cls._get_wrapped_key_prefix() if not wrapped_key.startswith(prefix): return None return wrapped_key[len(prefix) :] @classmethod @functools.cache def _get_wrapped_key_prefix(cls) -> str: return f's{_cache_persistence._Profile.schema_id}_' @classmethod def _get_key(cls, key: str) -> str: """Augment the supplied key with a schema identifier to allow for side-by-side caching across incompatible schemas.""" return f'{cls._get_wrapped_key_prefix()}{key}' def _encode(self, value: dict[str, object]) -> dict[str, object]: return {self._PAYLOAD_KEY: json.dumps(value, cls=_cache_persistence.Encoder)} def _decode(self, value: dict[str, t.Any]) -> dict[str, object]: return json.loads(value[self._PAYLOAD_KEY], cls=_cache_persistence.Decoder) ansible_core-2.19.0b5/lib/ansible/_internal/_ssh/0000755000000000000000000000000015017704211020305 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_ssh/__init__.py0000644000000000000000000000000015017704211022404 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_ssh/_agent_launch.py0000644000000000000000000000655715017704211023463 0ustar00rootrootfrom __future__ import annotations import atexit import os import subprocess from ansible import constants as C from ansible._internal._errors import _alarm_timeout from ansible._internal._ssh._ssh_agent import SshAgentClient from ansible.cli import display from ansible.errors import AnsibleError from ansible.module_utils.common.process import get_bin_path _SSH_AGENT_STDOUT_READ_TIMEOUT = 5 # seconds def launch_ssh_agent() -> None: """If configured via `SSH_AGENT`, launch an ssh-agent for Ansible's use and/or verify access to an existing one.""" try: _launch_ssh_agent() except Exception as ex: raise AnsibleError("Failed to launch ssh agent.") from ex def _launch_ssh_agent() -> None: ssh_agent_cfg = C.config.get_config_value('SSH_AGENT') match ssh_agent_cfg: case 'none': display.debug('SSH_AGENT set to none') return case 'auto': try: ssh_agent_bin = get_bin_path(C.config.get_config_value('SSH_AGENT_EXECUTABLE')) except ValueError as e: raise AnsibleError('SSH_AGENT set to auto, but cannot find ssh-agent binary.') from e ssh_agent_dir = os.path.join(C.DEFAULT_LOCAL_TMP, 'ssh_agent') os.mkdir(ssh_agent_dir, 0o700) sock = os.path.join(ssh_agent_dir, 'agent.sock') display.vvv('SSH_AGENT: starting...') try: p = subprocess.Popen( [ssh_agent_bin, '-D', '-s', '-a', sock], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, ) except OSError as e: raise AnsibleError('Could not start ssh-agent.') from e atexit.register(p.terminate) help_text = f'The ssh-agent {ssh_agent_bin!r} might be an incompatible agent.' expected_stdout = 'SSH_AUTH_SOCK' try: with _alarm_timeout.AnsibleTimeoutError.alarm_timeout(_SSH_AGENT_STDOUT_READ_TIMEOUT): stdout = p.stdout.read(len(expected_stdout)) except _alarm_timeout.AnsibleTimeoutError as e: display.error_as_warning( msg=f'Timed out waiting for expected stdout {expected_stdout!r} from ssh-agent.', exception=e, help_text=help_text, ) else: if stdout != expected_stdout: display.warning( msg=f'The ssh-agent output {stdout!r} did not match expected {expected_stdout!r}.', help_text=help_text, ) if p.poll() is not None: raise AnsibleError( message='The ssh-agent terminated prematurely.', help_text=f'{help_text}\n\nReturn Code: {p.returncode}\nStandard Error:\n{p.stderr.read()}', ) display.vvv(f'SSH_AGENT: ssh-agent[{p.pid}] started and bound to {sock}') case _: sock = ssh_agent_cfg try: with SshAgentClient(sock) as client: client.list() except Exception as e: raise AnsibleError(f'Could not communicate with ssh-agent using auth sock {sock!r}.') from e os.environ['SSH_AUTH_SOCK'] = os.environ['ANSIBLE_SSH_AGENT'] = sock ansible_core-2.19.0b5/lib/ansible/_internal/_ssh/_ssh_agent.py0000644000000000000000000005035615017704211023002 0ustar00rootroot# Copyright: Contributors to the Ansible project # BSD 3 Clause License (see licenses/BSD-3-Clause.txt or https://opensource.org/license/bsd-3-clause/) from __future__ import annotations import binascii import copy import dataclasses import enum import functools import hashlib import socket import types import typing as t try: from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric.dsa import ( DSAParameterNumbers, DSAPrivateKey, DSAPublicKey, DSAPublicNumbers, ) from cryptography.hazmat.primitives.asymmetric.ec import ( EllipticCurve, EllipticCurvePrivateKey, EllipticCurvePublicKey, SECP256R1, SECP384R1, SECP521R1, ) from cryptography.hazmat.primitives.asymmetric.ed25519 import ( Ed25519PrivateKey, Ed25519PublicKey, ) from cryptography.hazmat.primitives.asymmetric.rsa import ( RSAPrivateKey, RSAPublicKey, RSAPublicNumbers, ) except ImportError: HAS_CRYPTOGRAPHY = False else: HAS_CRYPTOGRAPHY = True CryptoPublicKey = t.Union[ DSAPublicKey, EllipticCurvePublicKey, Ed25519PublicKey, RSAPublicKey, ] CryptoPrivateKey = t.Union[ DSAPrivateKey, EllipticCurvePrivateKey, Ed25519PrivateKey, RSAPrivateKey, ] if t.TYPE_CHECKING: from cryptography.hazmat.primitives.asymmetric.dsa import DSAPrivateNumbers from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateNumbers from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateNumbers _SSH_AGENT_CLIENT_SOCKET_TIMEOUT = 10 class ProtocolMsgNumbers(enum.IntEnum): # Responses SSH_AGENT_FAILURE = 5 SSH_AGENT_SUCCESS = 6 SSH_AGENT_IDENTITIES_ANSWER = 12 SSH_AGENT_SIGN_RESPONSE = 14 SSH_AGENT_EXTENSION_FAILURE = 28 SSH_AGENT_EXTENSION_RESPONSE = 29 # Constraints SSH_AGENT_CONSTRAIN_LIFETIME = 1 SSH_AGENT_CONSTRAIN_CONFIRM = 2 SSH_AGENT_CONSTRAIN_EXTENSION = 255 # Requests SSH_AGENTC_REQUEST_IDENTITIES = 11 SSH_AGENTC_SIGN_REQUEST = 13 SSH_AGENTC_ADD_IDENTITY = 17 SSH_AGENTC_REMOVE_IDENTITY = 18 SSH_AGENTC_REMOVE_ALL_IDENTITIES = 19 SSH_AGENTC_ADD_SMARTCARD_KEY = 20 SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21 SSH_AGENTC_LOCK = 22 SSH_AGENTC_UNLOCK = 23 SSH_AGENTC_ADD_ID_CONSTRAINED = 25 SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26 SSH_AGENTC_EXTENSION = 27 def to_blob(self) -> bytes: return bytes([self]) class SshAgentFailure(RuntimeError): """Server failure or unexpected response.""" # NOTE: Classes below somewhat represent "Data Type Representations Used in the SSH Protocols" # as specified by RFC4251 @t.runtime_checkable class SupportsToBlob(t.Protocol): def to_blob(self) -> bytes: ... @t.runtime_checkable class SupportsFromBlob(t.Protocol): @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: ... @classmethod def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]: ... def _split_blob(blob: memoryview | bytes, length: int) -> tuple[memoryview | bytes, memoryview | bytes]: if len(blob) < length: raise ValueError("_split_blob: unexpected data length") return blob[:length], blob[length:] class VariableSized: @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: raise NotImplementedError @classmethod def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]: length = uint32.from_blob(blob[:4]) blob = blob[4:] data, rest = _split_blob(blob, length) return cls.from_blob(data), rest class uint32(int): def to_blob(self) -> bytes: return self.to_bytes(length=4, byteorder='big') @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: return cls.from_bytes(blob, byteorder='big') @classmethod def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]: length = uint32(4) data, rest = _split_blob(blob, length) return cls.from_blob(data), rest class mpint(int, VariableSized): def to_blob(self) -> bytes: if self < 0: raise ValueError("negative mpint not allowed") if not self: return b"" nbytes = (self.bit_length() + 8) // 8 ret = bytearray(self.to_bytes(length=nbytes, byteorder='big')) ret[:0] = uint32(len(ret)).to_blob() return ret @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: if blob and blob[0] > 127: raise ValueError("Invalid data") return cls.from_bytes(blob, byteorder='big') class constraints(bytes): def to_blob(self) -> bytes: return self class binary_string(bytes, VariableSized): def to_blob(self) -> bytes: if length := len(self): return uint32(length).to_blob() + self else: return b"" @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: return cls(blob) class unicode_string(str, VariableSized): def to_blob(self) -> bytes: val = self.encode('utf-8') if length := len(val): return uint32(length).to_blob() + val else: return b"" @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: return cls(bytes(blob).decode('utf-8')) class KeyAlgo(str, VariableSized, enum.Enum): RSA = "ssh-rsa" DSA = "ssh-dss" ECDSA256 = "ecdsa-sha2-nistp256" SKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com" ECDSA384 = "ecdsa-sha2-nistp384" ECDSA521 = "ecdsa-sha2-nistp521" ED25519 = "ssh-ed25519" SKED25519 = "sk-ssh-ed25519@openssh.com" RSASHA256 = "rsa-sha2-256" RSASHA512 = "rsa-sha2-512" @property def main_type(self) -> str: match self: case self.RSA: return 'RSA' case self.DSA: return 'DSA' case self.ECDSA256 | self.ECDSA384 | self.ECDSA521: return 'ECDSA' case self.ED25519: return 'ED25519' case _: raise NotImplementedError(self.name) def to_blob(self) -> bytes: b_self = self.encode('utf-8') return uint32(len(b_self)).to_blob() + b_self @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: return cls(bytes(blob).decode('utf-8')) if HAS_CRYPTOGRAPHY: _ECDSA_KEY_TYPE: dict[KeyAlgo, type[EllipticCurve]] = { KeyAlgo.ECDSA256: SECP256R1, KeyAlgo.ECDSA384: SECP384R1, KeyAlgo.ECDSA521: SECP521R1, } @dataclasses.dataclass class Msg: def to_blob(self) -> bytes: rv = bytearray() for field in dataclasses.fields(self): fv = getattr(self, field.name) if isinstance(fv, SupportsToBlob): rv.extend(fv.to_blob()) else: raise NotImplementedError(field.type) return rv @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: args: list[t.Any] = [] for _field_name, field_type in t.get_type_hints(cls).items(): if isinstance(field_type, SupportsFromBlob): fv, blob = field_type.consume_from_blob(blob) args.append(fv) else: raise NotImplementedError(str(field_type)) return cls(*args) @dataclasses.dataclass class PrivateKeyMsg(Msg): @staticmethod def from_private_key(private_key: CryptoPrivateKey) -> PrivateKeyMsg: match private_key: case RSAPrivateKey(): rsa_pn: RSAPrivateNumbers = private_key.private_numbers() return RSAPrivateKeyMsg( KeyAlgo.RSA, mpint(rsa_pn.public_numbers.n), mpint(rsa_pn.public_numbers.e), mpint(rsa_pn.d), mpint(rsa_pn.iqmp), mpint(rsa_pn.p), mpint(rsa_pn.q), ) case DSAPrivateKey(): dsa_pn: DSAPrivateNumbers = private_key.private_numbers() return DSAPrivateKeyMsg( KeyAlgo.DSA, mpint(dsa_pn.public_numbers.parameter_numbers.p), mpint(dsa_pn.public_numbers.parameter_numbers.q), mpint(dsa_pn.public_numbers.parameter_numbers.g), mpint(dsa_pn.public_numbers.y), mpint(dsa_pn.x), ) case EllipticCurvePrivateKey(): ecdsa_pn: EllipticCurvePrivateNumbers = private_key.private_numbers() key_size = private_key.key_size return EcdsaPrivateKeyMsg( getattr(KeyAlgo, f'ECDSA{key_size}'), unicode_string(f'nistp{key_size}'), binary_string( private_key.public_key().public_bytes( encoding=serialization.Encoding.X962, format=serialization.PublicFormat.UncompressedPoint, ) ), mpint(ecdsa_pn.private_value), ) case Ed25519PrivateKey(): public_bytes = private_key.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw, ) private_bytes = private_key.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), ) return Ed25519PrivateKeyMsg( KeyAlgo.ED25519, binary_string(public_bytes), binary_string(private_bytes + public_bytes), ) case _: raise NotImplementedError(private_key) @dataclasses.dataclass(order=True, slots=True) class RSAPrivateKeyMsg(PrivateKeyMsg): type: KeyAlgo n: mpint e: mpint d: mpint iqmp: mpint p: mpint q: mpint comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) constraints: constraints = dataclasses.field(default=constraints(b'')) @dataclasses.dataclass(order=True, slots=True) class DSAPrivateKeyMsg(PrivateKeyMsg): type: KeyAlgo p: mpint q: mpint g: mpint y: mpint x: mpint comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) constraints: constraints = dataclasses.field(default=constraints(b'')) @dataclasses.dataclass(order=True, slots=True) class EcdsaPrivateKeyMsg(PrivateKeyMsg): type: KeyAlgo ecdsa_curve_name: unicode_string Q: binary_string d: mpint comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) constraints: constraints = dataclasses.field(default=constraints(b'')) @dataclasses.dataclass(order=True, slots=True) class Ed25519PrivateKeyMsg(PrivateKeyMsg): type: KeyAlgo enc_a: binary_string k_env_a: binary_string comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) constraints: constraints = dataclasses.field(default=constraints(b'')) @dataclasses.dataclass class PublicKeyMsg(Msg): @staticmethod def get_dataclass(type: KeyAlgo) -> type[ t.Union[ RSAPublicKeyMsg, EcdsaPublicKeyMsg, Ed25519PublicKeyMsg, DSAPublicKeyMsg, ] ]: match type: case KeyAlgo.RSA: return RSAPublicKeyMsg case KeyAlgo.ECDSA256 | KeyAlgo.ECDSA384 | KeyAlgo.ECDSA521: return EcdsaPublicKeyMsg case KeyAlgo.ED25519: return Ed25519PublicKeyMsg case KeyAlgo.DSA: return DSAPublicKeyMsg case _: raise NotImplementedError(type) @functools.cached_property def public_key(self) -> CryptoPublicKey: type: KeyAlgo = self.type match type: case KeyAlgo.RSA: return RSAPublicNumbers(self.e, self.n).public_key() case KeyAlgo.ECDSA256 | KeyAlgo.ECDSA384 | KeyAlgo.ECDSA521: curve = _ECDSA_KEY_TYPE[KeyAlgo(type)] return EllipticCurvePublicKey.from_encoded_point(curve(), self.Q) case KeyAlgo.ED25519: return Ed25519PublicKey.from_public_bytes(self.enc_a) case KeyAlgo.DSA: return DSAPublicNumbers(self.y, DSAParameterNumbers(self.p, self.q, self.g)).public_key() case _: raise NotImplementedError(type) @staticmethod def from_public_key(public_key: CryptoPublicKey) -> PublicKeyMsg: match public_key: case DSAPublicKey(): dsa_pn: DSAPublicNumbers = public_key.public_numbers() return DSAPublicKeyMsg( KeyAlgo.DSA, mpint(dsa_pn.parameter_numbers.p), mpint(dsa_pn.parameter_numbers.q), mpint(dsa_pn.parameter_numbers.g), mpint(dsa_pn.y), ) case EllipticCurvePublicKey(): return EcdsaPublicKeyMsg( getattr(KeyAlgo, f'ECDSA{public_key.curve.key_size}'), unicode_string(f'nistp{public_key.curve.key_size}'), binary_string( public_key.public_bytes( encoding=serialization.Encoding.X962, format=serialization.PublicFormat.UncompressedPoint, ) ), ) case Ed25519PublicKey(): return Ed25519PublicKeyMsg( KeyAlgo.ED25519, binary_string( public_key.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw, ) ), ) case RSAPublicKey(): rsa_pn: RSAPublicNumbers = public_key.public_numbers() return RSAPublicKeyMsg(KeyAlgo.RSA, mpint(rsa_pn.e), mpint(rsa_pn.n)) case _: raise NotImplementedError(public_key) @functools.cached_property def fingerprint(self) -> str: digest = hashlib.sha256() msg = copy.copy(self) msg.comments = unicode_string('') k = msg.to_blob() digest.update(k) return binascii.b2a_base64(digest.digest(), newline=False).rstrip(b'=').decode('utf-8') @dataclasses.dataclass(order=True, slots=True) class RSAPublicKeyMsg(PublicKeyMsg): type: KeyAlgo e: mpint n: mpint comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) @dataclasses.dataclass(order=True, slots=True) class DSAPublicKeyMsg(PublicKeyMsg): type: KeyAlgo p: mpint q: mpint g: mpint y: mpint comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) @dataclasses.dataclass(order=True, slots=True) class EcdsaPublicKeyMsg(PublicKeyMsg): type: KeyAlgo ecdsa_curve_name: unicode_string Q: binary_string comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) @dataclasses.dataclass(order=True, slots=True) class Ed25519PublicKeyMsg(PublicKeyMsg): type: KeyAlgo enc_a: binary_string comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False) @dataclasses.dataclass(order=True, slots=True) class KeyList(Msg): nkeys: uint32 keys: PublicKeyMsgList def __post_init__(self) -> None: if self.nkeys != len(self.keys): raise SshAgentFailure("agent: invalid number of keys received for identities list") @dataclasses.dataclass(order=True, slots=True) class PublicKeyMsgList(Msg): keys: list[PublicKeyMsg] def __iter__(self) -> t.Iterator[PublicKeyMsg]: yield from self.keys def __len__(self) -> int: return len(self.keys) @classmethod def from_blob(cls, blob: memoryview | bytes) -> t.Self: ... @classmethod def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]: args: list[PublicKeyMsg] = [] while blob: prev_blob = blob key_blob, key_blob_length, comment_blob = cls._consume_field(blob) peek_key_algo, _length, _blob = cls._consume_field(key_blob) pub_key_msg_cls = PublicKeyMsg.get_dataclass(KeyAlgo(bytes(peek_key_algo).decode('utf-8'))) _fv, comment_blob_length, blob = cls._consume_field(comment_blob) key_plus_comment = prev_blob[4 : (4 + key_blob_length) + (4 + comment_blob_length)] args.append(pub_key_msg_cls.from_blob(key_plus_comment)) return cls(args), b"" @staticmethod def _consume_field(blob: memoryview | bytes) -> tuple[memoryview | bytes, uint32, memoryview | bytes]: length = uint32.from_blob(blob[:4]) blob = blob[4:] data, rest = _split_blob(blob, length) return data, length, rest class SshAgentClient: def __init__(self, auth_sock: str) -> None: self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._sock.settimeout(_SSH_AGENT_CLIENT_SOCKET_TIMEOUT) self._sock.connect(auth_sock) def close(self) -> None: self._sock.close() def __enter__(self) -> t.Self: return self def __exit__( self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: types.TracebackType | None, ) -> None: self.close() def send(self, msg: bytes) -> bytes: length = uint32(len(msg)).to_blob() self._sock.sendall(length + msg) bufsize = uint32.from_blob(self._sock.recv(4)) resp = self._sock.recv(bufsize) if resp[0] == ProtocolMsgNumbers.SSH_AGENT_FAILURE: raise SshAgentFailure('agent: failure') return resp def remove_all(self) -> None: self.send(ProtocolMsgNumbers.SSH_AGENTC_REMOVE_ALL_IDENTITIES.to_blob()) def remove(self, public_key: CryptoPublicKey) -> None: key_blob = PublicKeyMsg.from_public_key(public_key).to_blob() self.send(ProtocolMsgNumbers.SSH_AGENTC_REMOVE_IDENTITY.to_blob() + uint32(len(key_blob)).to_blob() + key_blob) def add( self, private_key: CryptoPrivateKey, comments: str | None = None, lifetime: int | None = None, confirm: bool | None = None, ) -> None: key_msg = PrivateKeyMsg.from_private_key(private_key) key_msg.comments = unicode_string(comments or '') if lifetime: key_msg.constraints += constraints([ProtocolMsgNumbers.SSH_AGENT_CONSTRAIN_LIFETIME]).to_blob() + uint32(lifetime).to_blob() if confirm: key_msg.constraints += constraints([ProtocolMsgNumbers.SSH_AGENT_CONSTRAIN_CONFIRM]).to_blob() if key_msg.constraints: msg = ProtocolMsgNumbers.SSH_AGENTC_ADD_ID_CONSTRAINED.to_blob() else: msg = ProtocolMsgNumbers.SSH_AGENTC_ADD_IDENTITY.to_blob() msg += key_msg.to_blob() self.send(msg) def list(self) -> KeyList: req = ProtocolMsgNumbers.SSH_AGENTC_REQUEST_IDENTITIES.to_blob() r = memoryview(bytearray(self.send(req))) if r[0] != ProtocolMsgNumbers.SSH_AGENT_IDENTITIES_ANSWER: raise SshAgentFailure('agent: non-identities answer received for identities list') return KeyList.from_blob(r[1:]) def __contains__(self, public_key: CryptoPublicKey) -> bool: msg = PublicKeyMsg.from_public_key(public_key) return msg in self.list().keys @functools.cache def key_data_into_crypto_objects(key_data: bytes, passphrase: bytes | None) -> tuple[CryptoPrivateKey, CryptoPublicKey, str]: private_key = serialization.ssh.load_ssh_private_key(key_data, passphrase) public_key = private_key.public_key() fingerprint = PublicKeyMsg.from_public_key(public_key).fingerprint return private_key, public_key, fingerprint ansible_core-2.19.0b5/lib/ansible/_internal/_task.py0000644000000000000000000000633515017704211021033 0ustar00rootrootfrom __future__ import annotations import dataclasses import typing as t from collections import abc as c from ansible import constants from ansible._internal._templating import _engine from ansible._internal._templating._chain_templar import ChainTemplar from ansible.errors import AnsibleError from ansible.module_utils._internal._ambient_context import AmbientContextBase from ansible.module_utils.datatag import native_type_name from ansible.parsing import vault as _vault from ansible.utils.display import Display if t.TYPE_CHECKING: from ansible.playbook.task import Task @dataclasses.dataclass class TaskContext(AmbientContextBase): """Ambient context that wraps task execution on workers. It provides access to the currently executing task.""" task: Task TaskArgsFinalizerCallback = t.Callable[[str, t.Any, _engine.TemplateEngine, t.Any], t.Any] """Type alias for the shape of the `ActionBase.finalize_task_arg` method.""" class TaskArgsChainTemplar(ChainTemplar): """ A ChainTemplar that carries a user-provided context object, optionally provided by `ActionBase.get_finalize_task_args_context`. TaskArgsFinalizer provides the context to each `ActionBase.finalize_task_arg` call to allow for more complex/stateful customization. """ def __init__(self, *sources: c.Mapping, templar: _engine.TemplateEngine, callback: TaskArgsFinalizerCallback, context: t.Any) -> None: super().__init__(*sources, templar=templar) self.callback = callback self.context = context def template(self, key: t.Any, value: t.Any) -> t.Any: return self.callback(key, value, self.templar, self.context) class TaskArgsFinalizer: """Invoked during task args finalization; allows actions to override default arg processing (e.g., templating).""" def __init__(self, *args: c.Mapping[str, t.Any] | str | None, templar: _engine.TemplateEngine) -> None: self._args_layers = [arg for arg in args if arg is not None] self._templar = templar def finalize(self, callback: TaskArgsFinalizerCallback, context: t.Any) -> dict[str, t.Any]: resolved_layers: list[c.Mapping[str, t.Any]] = [] for layer in self._args_layers: if isinstance(layer, (str, _vault.EncryptedString)): # EncryptedString can hide a template if constants.config.get_config_value('INJECT_FACTS_AS_VARS'): Display().warning( "Using a template for task args is unsafe in some situations " "(see https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-unsafe).", obj=layer, ) resolved_layer = self._templar.resolve_to_container(layer, options=_engine.TemplateOptions(value_for_omit={})) else: resolved_layer = layer if not isinstance(resolved_layer, dict): raise AnsibleError(f'Task args must resolve to a {native_type_name(dict)!r} not {native_type_name(resolved_layer)!r}.', obj=layer) resolved_layers.append(resolved_layer) ct = TaskArgsChainTemplar(*reversed(resolved_layers), templar=self._templar, callback=callback, context=context) return ct.as_dict() ansible_core-2.19.0b5/lib/ansible/_internal/_templating/0000755000000000000000000000000015017704211021654 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_templating/__init__.py0000644000000000000000000000077215017704211023773 0ustar00rootrootfrom __future__ import annotations import importlib.metadata jinja2_version = importlib.metadata.version('jinja2') # DTFIX-FUTURE: sanity test to ensure this doesn't drift from requirements _MINIMUM_JINJA_VERSION = (3, 1) _CURRENT_JINJA_VERSION = tuple(map(int, jinja2_version.split('.', maxsplit=2)[:2])) if _CURRENT_JINJA_VERSION < _MINIMUM_JINJA_VERSION: raise RuntimeError(f'Jinja version {".".join(map(str, _MINIMUM_JINJA_VERSION))} or higher is required (current version {jinja2_version}).') ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_access.py0000644000000000000000000000661315017704211023634 0ustar00rootrootfrom __future__ import annotations import abc import typing as t from contextvars import ContextVar from ansible.module_utils._internal._datatag import AnsibleTagHelper class NotifiableAccessContextBase(metaclass=abc.ABCMeta): """Base class for a context manager that, when active, receives notification of managed access for types/tags in which it has registered an interest.""" _type_interest: t.FrozenSet[type] = frozenset() """Set of types (including tag types) for which this context will be notified upon access.""" _mask: t.ClassVar[bool] = False """When true, only the innermost (most recently created) context of this type will be notified.""" def __enter__(self): # noinspection PyProtectedMember AnsibleAccessContext.current()._register_interest(self) return self def __exit__(self, exc_type, exc_val, exc_tb) -> None: # noinspection PyProtectedMember AnsibleAccessContext.current()._unregister_interest(self) return None @abc.abstractmethod def _notify(self, o: t.Any) -> t.Any: """Derived classes implement custom notification behavior when a registered type or tag is accessed.""" class AnsibleAccessContext: """ Broker object for managed access registration and notification. Each thread or other logical callstack has a dedicated `AnsibleAccessContext` object with which `NotifiableAccessContext` objects can register interest. When a managed access occurs on an object, each active `NotifiableAccessContext` within the current callstack that has registered interest in that object's type or a tag present on it will be notified. """ _contextvar: t.ClassVar[ContextVar[AnsibleAccessContext]] = ContextVar('AnsibleAccessContext') @staticmethod def current() -> AnsibleAccessContext: """Creates or retrieves an `AnsibleAccessContext` for the current logical callstack.""" try: ctx: AnsibleAccessContext = AnsibleAccessContext._contextvar.get() except LookupError: # didn't exist; create it ctx = AnsibleAccessContext() AnsibleAccessContext._contextvar.set(ctx) # we ignore the token, since this should live for the life of the thread/async ctx return ctx def __init__(self) -> None: self._notify_contexts: list[NotifiableAccessContextBase] = [] def _register_interest(self, context: NotifiableAccessContextBase) -> None: self._notify_contexts.append(context) def _unregister_interest(self, context: NotifiableAccessContextBase) -> None: ctx = self._notify_contexts.pop() if ctx is not context: raise RuntimeError(f'Out-of-order context deactivation detected. Found {ctx} instead of {context}.') def access(self, value: t.Any) -> None: """Notify all contexts which have registered interest in the given value that it is being accessed.""" if not self._notify_contexts: return value_types = AnsibleTagHelper.tag_types(value) | frozenset((type(value),)) masked: set[type] = set() for ctx in reversed(self._notify_contexts): if ctx._mask: if (ctx_type := type(ctx)) in masked: continue masked.add(ctx_type) # noinspection PyProtectedMember if ctx._type_interest.intersection(value_types): ctx._notify(value) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_chain_templar.py0000644000000000000000000000432015017704211025172 0ustar00rootrootfrom __future__ import annotations import collections.abc as c import itertools import typing as t from ansible.errors import AnsibleValueOmittedError, AnsibleError from ._engine import TemplateEngine class ChainTemplar: """A basic variable layering mechanism that supports templating and obliteration of `omit` values.""" def __init__(self, *sources: c.Mapping, templar: TemplateEngine) -> None: self.sources = sources self.templar = templar def template(self, key: t.Any, value: t.Any) -> t.Any: """ Render the given value using the templar. Intended to be overridden by subclasses. """ return self.templar.template(value) def get(self, key: t.Any) -> t.Any: """Get the value for the given key, templating the result before returning it.""" for source in self.sources: if key not in source: continue value = source[key] try: return self.template(key, value) except AnsibleValueOmittedError: break # omit == obliterate - matches historical behavior where dict layers were squashed before templating was applied except Exception as ex: raise AnsibleError(f'Error while resolving value for {key!r}.', obj=value) from ex raise KeyError(key) def keys(self) -> t.Iterable[t.Any]: """ Returns a sorted iterable of all keys present in all source layers, without templating associated values. Values that resolve to `omit` are thus included. """ return sorted(set(itertools.chain.from_iterable(self.sources))) def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]: """ Returns a sorted iterable of (key, templated value) tuples. Any tuple where the templated value resolves to `omit` will not be included in the result. """ for key in self.keys(): try: yield key, self.get(key) except KeyError: pass def as_dict(self) -> dict[t.Any, t.Any]: """Returns a dict representing all layers, squashed and templated, with `omit` values dropped.""" return dict(self.items()) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_datatag.py0000644000000000000000000000747715017704211024011 0ustar00rootrootfrom __future__ import annotations import contextlib as _contextlib import dataclasses import typing as t from ansible.module_utils._internal._datatag import AnsibleSingletonTagBase, _tag_dataclass_kwargs from ansible.module_utils._internal._datatag._tags import Deprecated from ansible._internal._datatag._tags import Origin from ansible.utils.display import Display from ._access import NotifiableAccessContextBase from ._utils import TemplateContext display = Display() @dataclasses.dataclass(**_tag_dataclass_kwargs) class _JinjaConstTemplate(AnsibleSingletonTagBase): # deprecated: description='embedded Jinja constant string template support' core_version='2.23' pass @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class _TrippedDeprecationInfo: template: str deprecated: Deprecated class DeprecatedAccessAuditContext(NotifiableAccessContextBase): """When active, captures metadata about managed accesses to `Deprecated` tagged objects.""" _type_interest = frozenset([Deprecated]) @classmethod def when(cls, condition: bool, /) -> t.Self | _contextlib.nullcontext: """Returns a new instance if `condition` is True (usually `TemplateContext.is_top_level`), otherwise a `nullcontext` instance.""" if condition: return cls() return _contextlib.nullcontext() def __init__(self) -> None: self._tripped_deprecation_info: dict[int, _TrippedDeprecationInfo] = {} def __exit__(self, exc_type, exc_val, exc_tb) -> None: result = super().__exit__(exc_type, exc_val, exc_tb) for item in self._tripped_deprecation_info.values(): if Origin.is_tagged_on(item.template): msg = item.deprecated.msg else: # without an origin, we need to include what context we do have (the template) msg = f'While processing {item.template!r}: {item.deprecated.msg}' display._deprecated_with_plugin_info( msg=msg, help_text=item.deprecated.help_text, version=item.deprecated.version, date=item.deprecated.date, obj=item.template, deprecator=item.deprecated.deprecator, formatted_traceback=item.deprecated.formatted_traceback, ) return result def _notify(self, o: t.Any) -> None: deprecated = Deprecated.get_required_tag(o) deprecated_key = id(deprecated) if deprecated_key in self._tripped_deprecation_info: return # record only the first access for each deprecated tag in a given context template_ctx = TemplateContext.current(optional=True) template = template_ctx.template_value if template_ctx else None # when the current template input is a container, provide a descriptive string with origin propagated (if possible) if not isinstance(template, str): # DTFIX-FUTURE: ascend the template stack to try and find the nearest string source template origin = Origin.get_tag(template) # DTFIX-FUTURE: this should probably use a synthesized description value on the tag # it is reachable from the data_tagging_controller test: ../playbook_output_validator/filter.py actual_stdout.txt actual_stderr.txt # -[DEPRECATION WARNING]: `something_old` is deprecated, don't use it! This feature will be removed in version 1.2.3. # +[DEPRECATION WARNING]: While processing '<>': `something_old` is deprecated, don't use it! This feature will be removed in ... template = '<>' if origin: origin.tag(template) self._tripped_deprecation_info[deprecated_key] = _TrippedDeprecationInfo( template=template, deprecated=deprecated, ) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_engine.py0000644000000000000000000006677315017704211023655 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import copy import dataclasses import enum import textwrap import typing as t import collections.abc as c import re from collections import ChainMap from ansible.errors import ( AnsibleError, AnsibleValueOmittedError, AnsibleUndefinedVariable, AnsibleTemplateSyntaxError, AnsibleBrokenConditionalError, AnsibleTemplateTransformLimitError, TemplateTrustCheckFailedError, ) from ansible.module_utils._internal._datatag import AnsibleTaggedObject, NotTaggableError, AnsibleTagHelper from ansible._internal._errors._handler import Skippable from ansible._internal._datatag._tags import Origin, TrustedAsTemplate from ansible.utils.display import Display from ansible.utils.vars import validate_variable_name from ansible.parsing.dataloader import DataLoader from ._datatag import DeprecatedAccessAuditContext from ._jinja_bits import ( AnsibleTemplate, _TemplateCompileContext, TemplateOverrides, AnsibleEnvironment, defer_template_error, create_template_error, is_possibly_template, is_possibly_all_template, AnsibleTemplateExpression, _finalize_template_result, FinalizeMode, ) from ._jinja_common import _TemplateConfig, MarkerError, ExceptionMarker from ._lazy_containers import _AnsibleLazyTemplateMixin from ._marker_behaviors import MarkerBehavior, FAIL_ON_UNDEFINED from ._transform import _type_transform_mapping from ._utils import Omit, TemplateContext, IGNORE_SCALAR_VAR_TYPES, LazyOptions from ...module_utils.datatag import native_type_name _display = Display() _shared_empty_unmask_type_names: frozenset[str] = frozenset() TRANSFORM_CHAIN_LIMIT: int = 10 """Arbitrary limit for chained transforms to prevent cycles; an exception will be raised if exceeded.""" class TemplateMode(enum.Enum): # DTFIX-FUTURE: this enum ideally wouldn't exist - revisit/rename before making public DEFAULT = enum.auto() STOP_ON_TEMPLATE = enum.auto() STOP_ON_CONTAINER = enum.auto() ALWAYS_FINALIZE = enum.auto() @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class TemplateOptions: DEFAULT: t.ClassVar[t.Self] value_for_omit: object = Omit escape_backslashes: bool = True preserve_trailing_newlines: bool = True # DTFIX-FUTURE: these aren't really overrides anymore, rename the dataclass and this field # also mention in docstring this has no effect unless used to template a string overrides: TemplateOverrides = TemplateOverrides.DEFAULT TemplateOptions.DEFAULT = TemplateOptions() class TemplateEncountered(Exception): pass class TemplateEngine: """ The main class for templating, with the main entry-point of template(). """ _sentinel = object() def __init__( self, loader: DataLoader | None = None, variables: dict[str, t.Any] | ChainMap[str, t.Any] | None = None, variables_factory: t.Callable[[], dict[str, t.Any] | ChainMap[str, t.Any]] | None = None, marker_behavior: MarkerBehavior | None = None, ): self._loader = loader self._variables = variables self._variables_factory = variables_factory self._environment: AnsibleEnvironment | None = None # inherit marker behavior from the active template context's templar unless otherwise specified if not marker_behavior: if template_ctx := TemplateContext.current(optional=True): marker_behavior = template_ctx.templar.marker_behavior else: marker_behavior = FAIL_ON_UNDEFINED self._marker_behavior = marker_behavior def copy(self) -> t.Self: new_engine = copy.copy(self) new_engine._environment = None return new_engine def extend(self, marker_behavior: MarkerBehavior | None = None) -> t.Self: new_templar = type(self)( loader=self._loader, variables=self._variables, variables_factory=self._variables_factory, marker_behavior=marker_behavior or self._marker_behavior, ) if self._environment: new_templar._environment = self._environment return new_templar @property def marker_behavior(self) -> MarkerBehavior: return self._marker_behavior @property def basedir(self) -> str: """The basedir from DataLoader.""" return self._loader.get_basedir() if self._loader else '.' @property def environment(self) -> AnsibleEnvironment: if not self._environment: self._environment = AnsibleEnvironment(ansible_basedir=self.basedir) return self._environment def _create_overlay(self, template: str, overrides: TemplateOverrides) -> tuple[str, AnsibleEnvironment]: try: template, overrides = overrides._extract_template_overrides(template) except Exception as ex: raise AnsibleTemplateSyntaxError("Syntax error in template.", obj=template) from ex env = self.environment if overrides is not TemplateOverrides.DEFAULT and (overlay_kwargs := overrides.overlay_kwargs()): env = t.cast(AnsibleEnvironment, env.overlay(**overlay_kwargs)) return template, env @staticmethod def _count_newlines_from_end(in_str): """ Counts the number of newlines at the end of a string. This is used during the jinja2 templating to ensure the count matches the input, since some newlines may be thrown away during the templating. """ i = len(in_str) j = i - 1 try: while in_str[j] == '\n': j -= 1 except IndexError: # Uncommon cases: zero length string and string containing only newlines return i return i - 1 - j @property def available_variables(self) -> dict[str, t.Any] | ChainMap[str, t.Any]: """Available variables this instance will use when templating.""" # DTFIX3: ensure that we're always accessing this as a shallow container-level snapshot, and eliminate uses of anything # that directly mutates this value. _new_context may resolve this for us? if self._variables is None: self._variables = self._variables_factory() if self._variables_factory else {} return self._variables @available_variables.setter def available_variables(self, variables: dict[str, t.Any]) -> None: self._variables = variables def resolve_variable_expression( self, expression: str, *, local_variables: dict[str, t.Any] | None = None, ) -> t.Any: """ Resolve a potentially untrusted string variable expression consisting only of valid identifiers, integers, dots, and indexing containing these. Optional local variables may be provided, which can only be referenced directly by the given expression. Valid: x, x.y, x[y].z, x[1], 1, x[y.z] Error: 'x', x['y'], q('env') """ components = re.split(r'[.\[\]]', expression) try: for component in components: if re.fullmatch('[0-9]*', component): continue # allow empty strings and integers validate_variable_name(component) except Exception as ex: raise AnsibleError(f'Invalid variable expression: {expression}', obj=expression) from ex return self.evaluate_expression(TrustedAsTemplate().tag(expression), local_variables=local_variables) @staticmethod def variable_name_as_template(name: str) -> str: """Return a trusted template string that will resolve the provided variable name. Raises an error if `name` is not a valid identifier.""" validate_variable_name(name) return AnsibleTagHelper.tag('{{' + name + '}}', (AnsibleTagHelper.tags(name) | {TrustedAsTemplate()})) def transform(self, variable: t.Any) -> t.Any: """Recursively apply transformations to the given value and return the result.""" return self.template(variable, mode=TemplateMode.ALWAYS_FINALIZE, lazy_options=LazyOptions.SKIP_TEMPLATES_AND_ACCESS) def template( self, variable: t.Any, # DTFIX-FUTURE: once we settle the new/old API boundaries, rename this (here and in other methods) *, options: TemplateOptions = TemplateOptions.DEFAULT, mode: TemplateMode = TemplateMode.DEFAULT, lazy_options: LazyOptions = LazyOptions.DEFAULT, ) -> t.Any: """Templates (possibly recursively) any given data as input.""" original_variable = variable for _attempt in range(TRANSFORM_CHAIN_LIMIT): if variable is None or (value_type := type(variable)) in IGNORE_SCALAR_VAR_TYPES: return variable # quickly ignore supported scalar types which are not be templated value_is_str = isinstance(variable, str) if template_ctx := TemplateContext.current(optional=True): stop_on_template = template_ctx.stop_on_template else: stop_on_template = False if mode is TemplateMode.STOP_ON_TEMPLATE: stop_on_template = True with ( TemplateContext(template_value=variable, templar=self, options=options, stop_on_template=stop_on_template) as ctx, DeprecatedAccessAuditContext.when(ctx.is_top_level), ): try: if not value_is_str: # transforms are currently limited to non-str types as an optimization if (transform := _type_transform_mapping.get(value_type)) and value_type.__name__ not in lazy_options.unmask_type_names: variable = transform(variable) continue template_result = _AnsibleLazyTemplateMixin._try_create(variable, lazy_options) elif not lazy_options.template: template_result = variable elif not is_possibly_template(variable, options.overrides): template_result = variable elif not self._trust_check(variable, skip_handler=stop_on_template): template_result = variable elif stop_on_template: raise TemplateEncountered() else: compiled_template = self._compile_template(variable, options) template_result = compiled_template(self.available_variables) template_result = self._post_render_mutation(variable, template_result, options) except TemplateEncountered: raise except Exception as ex: template_result = defer_template_error(ex, variable, is_expression=False) if ctx.is_top_level or mode is TemplateMode.ALWAYS_FINALIZE: template_result = self._finalize_top_level_template_result( variable, options, template_result, stop_on_container=mode is TemplateMode.STOP_ON_CONTAINER ) return template_result raise AnsibleTemplateTransformLimitError(obj=original_variable) @staticmethod def _finalize_top_level_template_result( variable: t.Any, options: TemplateOptions, template_result: t.Any, is_expression: bool = False, stop_on_container: bool = False, ) -> t.Any: """ This method must be called for expressions and top-level templates to recursively finalize the result. This renders any embedded templates and triggers `Marker` and omit behaviors. """ try: if template_result is Omit: # When the template result is Omit, raise an AnsibleValueOmittedError if value_for_omit is Omit, otherwise return value_for_omit. # Other occurrences of Omit will simply drop out of containers during _finalize_template_result. if options.value_for_omit is Omit: raise AnsibleValueOmittedError() return options.value_for_omit # trust that value_for_omit is an allowed type if stop_on_container and type(template_result) in AnsibleTaggedObject._collection_types: # Use of stop_on_container implies the caller will perform necessary checks on values, # most likely by passing them back into the templating system. try: return template_result._non_lazy_copy() except AttributeError: return template_result # non-lazy containers are returned as-is return _finalize_template_result(template_result, FinalizeMode.TOP_LEVEL) except TemplateEncountered: raise except Exception as ex: raise_from: BaseException if isinstance(ex, MarkerError): exception_to_raise = ex.source._as_exception() # MarkerError is never suitable for use as the cause of another exception, it is merely a raiseable container for the source marker # used for flow control (so its stack trace is rarely useful). However, if the source derives from a ExceptionMarker, its contained # exception (previously raised) should be used as the cause. Other sources do not contain exceptions, so cannot provide a cause. raise_from = exception_to_raise if isinstance(ex.source, ExceptionMarker) else None else: exception_to_raise = ex raise_from = ex exception_to_raise = create_template_error(exception_to_raise, variable, is_expression) if exception_to_raise is ex: raise # when the exception to raise is the active exception, just re-raise it if exception_to_raise is raise_from: raise_from = exception_to_raise.__cause__ # preserve the exception's cause, if any, otherwise no cause will be used raise exception_to_raise from raise_from # always raise from something to avoid the currently active exception becoming __context__ def _compile_template(self, template: str, options: TemplateOptions) -> t.Callable[[c.Mapping[str, t.Any]], t.Any]: # NOTE: Creating an overlay that lives only inside _compile_template means that overrides are not applied # when templating nested variables, where Templar.environment is used, not the overlay. They are, however, # applied to includes and imports. try: stripped_template, env = self._create_overlay(template, options.overrides) with _TemplateCompileContext(escape_backslashes=options.escape_backslashes): return t.cast(AnsibleTemplate, env.from_string(stripped_template)) except Exception as ex: return self._defer_jinja_compile_error(ex, template, False) def _compile_expression(self, expression: str, options: TemplateOptions) -> t.Callable[[c.Mapping[str, t.Any]], t.Any]: """ Compile a Jinja expression, applying optional compile-time behavior via an environment overlay (if needed). The overlay is necessary to avoid mutating settings on the Templar's shared environment, which could be visible to other code running concurrently. In the specific case of escape_backslashes, the setting only applies to a top-level template at compile-time, not runtime, to ensure that any nested template calls (e.g., include and import) do not inherit the (lack of) escaping behavior. """ try: with _TemplateCompileContext(escape_backslashes=options.escape_backslashes): return AnsibleTemplateExpression(self.environment.compile_expression(expression, False)) except Exception as ex: return self._defer_jinja_compile_error(ex, expression, True) def _defer_jinja_compile_error(self, ex: Exception, variable: str, is_expression: bool) -> t.Callable[[c.Mapping[str, t.Any]], t.Any]: deferred_error = defer_template_error(ex, variable, is_expression=is_expression) def deferred_exception(_jinja_vars: c.Mapping[str, t.Any]) -> t.Any: # a template/expression compile error always results in a single node representing the compile error return self.marker_behavior.handle_marker(deferred_error) return deferred_exception def _post_render_mutation(self, template: str, result: t.Any, options: TemplateOptions) -> t.Any: if options.preserve_trailing_newlines and isinstance(result, str): # The low level calls above do not preserve the newline # characters at the end of the input data, so we # calculate the difference in newlines and append them # to the resulting output for parity # # Using AnsibleEnvironment's keep_trailing_newline instead would # result in change in behavior when trailing newlines # would be kept also for included templates, for example: # "Hello {% include 'world.txt' %}!" would render as # "Hello world\n!\n" instead of "Hello world!\n". data_newlines = self._count_newlines_from_end(template) res_newlines = self._count_newlines_from_end(result) if data_newlines > res_newlines: newlines = options.overrides.newline_sequence * (data_newlines - res_newlines) result = AnsibleTagHelper.tag_copy(result, result + newlines) # If the input string template was source-tagged and the result is not, propagate the source tag to the new value. # This provides further contextual information when a template-derived value/var causes an error. if not Origin.is_tagged_on(result) and (origin := Origin.get_tag(template)): try: result = origin.tag(result) except NotTaggableError: pass # best effort- if we can't, oh well return result def is_template(self, data: t.Any, overrides: TemplateOverrides = TemplateOverrides.DEFAULT) -> bool: """ Evaluate the input data to determine if it contains a template, even if that template is invalid. Containers will be recursively searched. Objects subject to template-time transforms that do not yield a template are not considered templates by this method. Gating a conditional call to `template` with this method is redundant and inefficient -- request templating unconditionally instead. """ options = TemplateOptions(overrides=overrides) if overrides is not TemplateOverrides.DEFAULT else TemplateOptions.DEFAULT try: self.template(data, options=options, mode=TemplateMode.STOP_ON_TEMPLATE) except TemplateEncountered: return True else: return False def resolve_to_container(self, variable: t.Any, options: TemplateOptions = TemplateOptions.DEFAULT) -> t.Any: """ Recursively resolve scalar string template input, stopping at the first container encountered (if any). Used for e.g., partial templating of task arguments, where the plugin needs to handle final resolution of some args internally. """ return self.template(variable, options=options, mode=TemplateMode.STOP_ON_CONTAINER) def evaluate_expression( self, expression: str, *, local_variables: dict[str, t.Any] | None = None, escape_backslashes: bool = True, _render_jinja_const_template: bool = False, ) -> t.Any: """ Evaluate a trusted string expression and return its result. Optional local variables may be provided, which can only be referenced directly by the given expression. """ if not isinstance(expression, str): raise TypeError(f"Expressions must be {str!r}, got {type(expression)!r}.") options = TemplateOptions(escape_backslashes=escape_backslashes, preserve_trailing_newlines=False) with ( TemplateContext(template_value=expression, templar=self, options=options, _render_jinja_const_template=_render_jinja_const_template) as ctx, DeprecatedAccessAuditContext.when(ctx.is_top_level), ): try: if not TrustedAsTemplate.is_tagged_on(expression): raise TemplateTrustCheckFailedError(obj=expression) template_variables = ChainMap(local_variables, self.available_variables) if local_variables else self.available_variables compiled_template = self._compile_expression(expression, options) template_result = compiled_template(template_variables) template_result = self._post_render_mutation(expression, template_result, options) except Exception as ex: template_result = defer_template_error(ex, expression, is_expression=True) return self._finalize_top_level_template_result(expression, options, template_result, is_expression=True) _BROKEN_CONDITIONAL_ALLOWED_FRAGMENT = 'Broken conditionals are currently allowed because the `ALLOW_BROKEN_CONDITIONALS` configuration option is enabled.' _CONDITIONAL_AS_TEMPLATE_MSG = 'Conditionals should not be surrounded by templating delimiters such as {{ }} or {% %}.' def _strip_conditional_handle_empty(self, conditional) -> t.Any: """ Strips leading/trailing whitespace from the input expression. If `ALLOW_BROKEN_CONDITIONALS` is enabled, None/empty is coerced to True (legacy behavior, deprecated). Otherwise, None/empty results in a broken conditional error being raised. """ if isinstance(conditional, str): # Leading/trailing whitespace on conditional expressions is not a problem, except we can't tell if the expression is empty (which *is* a problem). # Always strip conditional input strings. Neither conditional expressions nor all-template conditionals have legit reasons to preserve # surrounding whitespace, and they complicate detection and processing of all-template fallback cases. conditional = AnsibleTagHelper.tag_copy(conditional, conditional.strip()) if conditional in (None, ''): # deprecated backward-compatible behavior; None/empty input conditionals are always True if _TemplateConfig.allow_broken_conditionals: _display.deprecated( msg='Empty conditional expression was evaluated as True.', help_text=self._BROKEN_CONDITIONAL_ALLOWED_FRAGMENT, obj=conditional, version='2.23', ) return True raise AnsibleBrokenConditionalError("Empty conditional expressions are not allowed.", obj=conditional) return conditional def _normalize_and_evaluate_conditional(self, conditional: str | bool) -> t.Any: """Validate and normalize a conditional input value, resolving allowed embedded template cases and evaluating the resulting expression.""" conditional = self._strip_conditional_handle_empty(conditional) # this must follow `_strip_conditional_handle_empty`, since None/empty are coerced to bool (deprecated) if type(conditional) is bool: # pylint: disable=unidiomatic-typecheck return conditional try: if not isinstance(conditional, str): if _TemplateConfig.allow_broken_conditionals: # because the input isn't a string, the result will never be a bool; the broken conditional warning in the caller will apply on the result return self.template(conditional, mode=TemplateMode.ALWAYS_FINALIZE) raise AnsibleBrokenConditionalError(message="Conditional expressions must be strings.", obj=conditional) if is_possibly_all_template(conditional): # Indirection of trusted expressions is always allowed. If the expression appears to be entirely wrapped in template delimiters, # we must resolve it. e.g. `when: "{{ some_var_resolving_to_a_trusted_expression_string }}"`. # Some invalid meta-templating corner cases may sneak through here (e.g., `when: '{{ "foo" }} == {{ "bar" }}'`); these will # result in an untrusted expression error. result = self.template(conditional, mode=TemplateMode.ALWAYS_FINALIZE) result = self._strip_conditional_handle_empty(result) if not isinstance(result, str): _display.deprecated(msg=self._CONDITIONAL_AS_TEMPLATE_MSG, obj=conditional, version='2.23') return result # not an expression # The only allowed use of templates for conditionals is for indirect usage of an expression. # Any other usage should simply be an expression, not an attempt at meta templating. expression = result else: expression = conditional # Disable escape_backslashes when processing conditionals, to maintain backwards compatibility. # This is necessary because conditionals were previously evaluated using {% %}, which was *NOT* affected by escape_backslashes. # Now that conditionals use expressions, they would be affected by escape_backslashes if it was not disabled. return self.evaluate_expression(expression, escape_backslashes=False, _render_jinja_const_template=True) except AnsibleUndefinedVariable as ex: # DTFIX-FUTURE: we're only augmenting the message for context here; once we have proper contextual tracking, we can dump the re-raise raise AnsibleUndefinedVariable("Error while evaluating conditional.", obj=conditional) from ex def evaluate_conditional(self, conditional: str | bool) -> bool: """ Evaluate a trusted string expression or boolean and return its boolean result. A non-boolean result will raise `AnsibleBrokenConditionalError`. The ALLOW_BROKEN_CONDITIONALS configuration option can temporarily relax this requirement, allowing truthy conditionals to succeed. """ result = self._normalize_and_evaluate_conditional(conditional) if isinstance(result, bool): return result bool_result = bool(result) msg = ( f'Conditional result was {textwrap.shorten(str(result), width=40)!r} of type {native_type_name(result)!r}, ' f'which evaluates to {bool_result}. Conditionals must have a boolean result.' ) if _TemplateConfig.allow_broken_conditionals: _display.deprecated( msg=msg, obj=conditional, help_text=self._BROKEN_CONDITIONAL_ALLOWED_FRAGMENT, version='2.23', ) return bool_result raise AnsibleBrokenConditionalError(msg, obj=conditional) @staticmethod def _trust_check(value: str, skip_handler: bool = False) -> bool: """ Return True if the given value is trusted for templating, otherwise return False. When the value is not trusted, a warning or error may be generated, depending on configuration. """ if TrustedAsTemplate.is_tagged_on(value): return True if not skip_handler: with Skippable, _TemplateConfig.untrusted_template_handler.handle(TemplateTrustCheckFailedError, skip_on_ignore=True): raise TemplateTrustCheckFailedError(obj=value) return False ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_errors.py0000644000000000000000000000242615017704211023705 0ustar00rootrootfrom __future__ import annotations from ansible.errors import AnsibleTemplatePluginError class AnsibleTemplatePluginRuntimeError(AnsibleTemplatePluginError): """The specified template plugin (lookup/filter/test) raised an exception during execution.""" def __init__(self, plugin_type: str, plugin_name: str) -> None: super().__init__(f'The {plugin_type} plugin {plugin_name!r} failed.') class AnsibleTemplatePluginLoadError(AnsibleTemplatePluginError): """The specified template plugin (lookup/filter/test) failed to load.""" def __init__(self, plugin_type: str, plugin_name: str) -> None: super().__init__(f'The {plugin_type} plugin {plugin_name!r} failed to load.') class AnsibleTemplatePluginNotFoundError(AnsibleTemplatePluginError, KeyError): """ The specified template plugin (lookup/filter/test) was not found. This exception extends KeyError since Jinja filter/test resolution requires a KeyError to detect missing plugins. Jinja compilation fails if a non-KeyError is raised for a missing filter/test, even if the plugin will not be invoked (inconsistent with stock Jinja). """ def __init__(self, plugin_type: str, plugin_name: str) -> None: super().__init__(f'The {plugin_type} plugin {plugin_name!r} was not found.') ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_jinja_bits.py0000644000000000000000000013431315017704211024506 0ustar00rootrootfrom __future__ import annotations import ast import collections.abc as c import dataclasses import enum import pathlib import tempfile import types import typing as t from collections import ChainMap import jinja2.nodes from jinja2 import pass_context, defaults, TemplateSyntaxError, FileSystemLoader from jinja2.environment import Environment, Template, TemplateModule, TemplateExpression from jinja2.compiler import Frame from jinja2.lexer import TOKEN_VARIABLE_BEGIN, TOKEN_VARIABLE_END, TOKEN_STRING, Lexer from jinja2.nativetypes import NativeCodeGenerator from jinja2.nodes import Const, EvalContext from jinja2.runtime import Context from jinja2.sandbox import ImmutableSandboxedEnvironment from jinja2.utils import missing, LRUCache from ansible.utils.display import Display from ansible.errors import AnsibleVariableTypeError, AnsibleTemplateSyntaxError, AnsibleTemplateError from ansible.module_utils.common.text.converters import to_text from ansible.module_utils._internal._datatag import ( _AnsibleTaggedDict, _AnsibleTaggedList, _AnsibleTaggedTuple, _AnsibleTaggedStr, AnsibleTagHelper, ) from ansible._internal._errors._handler import ErrorAction from ansible._internal._datatag._tags import Origin, TrustedAsTemplate from ._access import AnsibleAccessContext from ._datatag import _JinjaConstTemplate from ._utils import LazyOptions from ._jinja_common import ( MarkerError, Marker, CapturedExceptionMarker, UndefinedMarker, _TemplateConfig, TruncationMarker, validate_arg_type, JinjaCallContext, _SandboxMode, ) from ._jinja_plugins import JinjaPluginIntercept, _query, _lookup, _now, _wrap_plugin_output, get_first_marker_arg, _DirectCall, _jinja_const_template_warning from ._lazy_containers import ( _AnsibleLazyTemplateMixin, _AnsibleLazyTemplateDict, _AnsibleLazyTemplateList, _AnsibleLazyAccessTuple, lazify_container_args, lazify_container_kwargs, lazify_container, register_known_types, ) from ._utils import Omit, TemplateContext, PASS_THROUGH_SCALAR_VAR_TYPES from ansible.module_utils._internal._json._profiles import _json_subclassable_scalar_types from ansible.module_utils import _internal from ansible.module_utils._internal import _ambient_context, _dataclass_validation from ansible.plugins.loader import filter_loader, test_loader from ansible.vars.hostvars import HostVars, HostVarsVars from ...module_utils.datatag import native_type_name JINJA2_OVERRIDE = '#jinja2:' """ String values prefixed with this sequence are interpreted as templates, even without template delimiters. The values following this prefix up to the first newline are parsed as Jinja2 template overrides. To include this literal value at the start of a string, a space or other character must precede it. """ display = Display() @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class TemplateOverrides: DEFAULT: t.ClassVar[t.Self] block_start_string: str = defaults.BLOCK_START_STRING block_end_string: str = defaults.BLOCK_END_STRING variable_start_string: str = defaults.VARIABLE_START_STRING variable_end_string: str = defaults.VARIABLE_END_STRING comment_start_string: str = defaults.COMMENT_START_STRING comment_end_string: str = defaults.COMMENT_END_STRING line_statement_prefix: str | None = defaults.LINE_STATEMENT_PREFIX line_comment_prefix: str | None = defaults.LINE_COMMENT_PREFIX trim_blocks: bool = True # AnsibleEnvironment overrides this default, so don't use the Jinja default here lstrip_blocks: bool = defaults.LSTRIP_BLOCKS newline_sequence: t.Literal['\n', '\r\n', '\r'] = defaults.NEWLINE_SEQUENCE keep_trailing_newline: bool = defaults.KEEP_TRAILING_NEWLINE def __post_init__(self) -> None: pass # overridden by _dataclass_validation._inject_post_init_validation def _post_validate(self) -> None: if not (self.block_start_string != self.variable_start_string != self.comment_start_string != self.block_start_string): raise ValueError('Block, variable and comment start strings must be different.') def overlay_kwargs(self) -> dict[str, t.Any]: """ Return a dictionary of arguments for passing to Environment.overlay. The dictionary will be empty if all fields have their default value. """ # DTFIX-FUTURE: calculate default/non-default during __post_init__ fields = [(field, getattr(self, field.name)) for field in dataclasses.fields(self)] kwargs = {field.name: value for field, value in fields if value != field.default} return kwargs def _contains_start_string(self, value: str) -> bool: """Returns True if the given value contains a variable, block or comment start string.""" # DTFIX-FUTURE: this is inefficient, use a compiled regex instead for marker in (self.block_start_string, self.variable_start_string, self.comment_start_string): if marker in value: return True return False def _starts_and_ends_with_jinja_delimiters(self, value: str) -> bool: """Returns True if the given value starts and ends with Jinja variable, block or comment delimiters.""" # DTFIX-FUTURE: this is inefficient, use a compiled regex instead for marker in (self.block_start_string, self.variable_start_string, self.comment_start_string): if value.startswith(marker): break else: return False for marker in (self.block_end_string, self.variable_end_string, self.comment_end_string): if value.endswith(marker): return True return False def _extract_template_overrides(self, template: str) -> tuple[str, TemplateOverrides]: if template.startswith(JINJA2_OVERRIDE): eol = template.find('\n') if eol == -1: raise ValueError(f"Missing newline after {JINJA2_OVERRIDE!r} override.") line = template[len(JINJA2_OVERRIDE) : eol] template = template[eol + 1 :] override_kwargs = {} for pair in line.split(','): if not pair.strip(): raise ValueError(f"Empty {JINJA2_OVERRIDE!r} override pair not allowed.") if ':' not in pair: raise ValueError(f"Missing key-value separator `:` in {JINJA2_OVERRIDE!r} override pair {pair!r}.") key, val = pair.split(':', 1) key = key.strip() if key not in _TEMPLATE_OVERRIDE_FIELD_NAMES: raise ValueError(f"Invalid {JINJA2_OVERRIDE!r} override key {key!r}.") override_kwargs[key] = ast.literal_eval(val) overrides = dataclasses.replace(self, **override_kwargs) else: overrides = self return template, overrides def merge(self, kwargs: dict[str, t.Any] | None, /) -> TemplateOverrides: """Return a new instance based on the current instance with the given kwargs overridden.""" if kwargs: return self.from_kwargs(dataclasses.asdict(self) | kwargs) return self @classmethod def from_kwargs(cls, kwargs: dict[str, t.Any] | None, /) -> TemplateOverrides: """TemplateOverrides instance factory; instances resolving to all default values will instead return the DEFAULT singleton for optimization.""" if kwargs: value = cls(**kwargs) if value.overlay_kwargs(): return value return cls.DEFAULT _dataclass_validation.inject_post_init_validation(TemplateOverrides, allow_subclasses=True) TemplateOverrides.DEFAULT = TemplateOverrides() _TEMPLATE_OVERRIDE_FIELD_NAMES: t.Final[tuple[str, ...]] = tuple(sorted(field.name for field in dataclasses.fields(TemplateOverrides))) class AnsibleContext(Context): """ A custom context which intercepts resolve_or_missing() calls and runs them through AnsibleAccessContext. This allows usage of variables to be tracked. If needed, values can also be modified before being returned. """ environment: AnsibleEnvironment # narrow the type specified by the base def __init__(self, *args, **kwargs): super(AnsibleContext, self).__init__(*args, **kwargs) __repr__ = object.__repr__ # prevent Jinja from dumping vars in case this gets repr'd def get_all(self): """ Override Jinja's default get_all to return all vars in the context as a ChainMap with a mutable layer at the bottom. This provides some isolation against accidental changes to inherited variable contexts without requiring copies. """ layers = [] if self.vars: layers.append(self.vars) if self.parent: layers.append(self.parent) # HACK: always include a sacrificial plain-dict on the bottom layer, since Jinja's debug and stacktrace rewrite code invokes # `__setitem__` outside a call context; this will ensure that it always occurs on a plain dict instead of a lazy one. return ChainMap({}, *layers) # noinspection PyShadowingBuiltins def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> Context: # this is a clone of Jinja's impl of derived, but using our lazy-aware _new_context context = _new_context( environment=self.environment, template_name=self.name, blocks={}, shared=True, jinja_locals=locals, jinja_vars=self.get_all(), ) context.eval_ctx = self.eval_ctx context.blocks.update((k, list(v)) for k, v in self.blocks.items()) return context def keys(self, *args, **kwargs): """Base Context delegates to `dict.keys` against `get_all`, which would fail since we return a ChainMap. No known usage.""" raise NotImplementedError() def values(self, *args, **kwargs): """Base Context delegates to `dict.values` against `get_all`, which would fail since we return a ChainMap. No known usage.""" raise NotImplementedError() def items(self, *args, **kwargs): """Base Context delegates to built-in `dict.items` against `get_all`, which would fail since we return a ChainMap. No known usage.""" raise NotImplementedError() @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class ArgSmuggler: """ Utility wrapper to wrap/unwrap args passed to Jinja `Template.render` and `TemplateExpression.__call__`. e.g., see https://github.com/pallets/jinja/blob/3.1.3/src/jinja2/environment.py#L1296 and https://github.com/pallets/jinja/blob/3.1.3/src/jinja2/environment.py#L1566. """ jinja_vars: c.Mapping[str, t.Any] | None @classmethod def package_jinja_vars(cls, jinja_vars: c.Mapping[str, t.Any]) -> dict[str, ArgSmuggler]: """Wrap the supplied vars dict in an ArgSmuggler to prevent premature templating from Jinja's internal dict copy.""" return dict(_smuggled_vars=ArgSmuggler(jinja_vars=jinja_vars)) @classmethod def extract_jinja_vars(cls, maybe_smuggled_vars: c.Mapping[str, t.Any] | None) -> c.Mapping[str, t.Any]: """ If the supplied vars dict contains an ArgSmuggler instance with the expected key, unwrap it and return the smuggled value. Otherwise, return the supplied dict as-is. """ if maybe_smuggled_vars and ((smuggler := maybe_smuggled_vars.get('_smuggled_vars')) and isinstance(smuggler, ArgSmuggler)): return smuggler.jinja_vars return maybe_smuggled_vars class AnsibleTemplateExpression: """ Wrapper around Jinja's TemplateExpression for converting MarkerError back into Marker. This is needed to make expression error handling consistent with templates, since Jinja does not support a custom type for Environment.compile_expression. """ def __init__(self, template_expression: TemplateExpression) -> None: self._template_expression = template_expression def __call__(self, jinja_vars: c.Mapping[str, t.Any]) -> t.Any: try: return self._template_expression(ArgSmuggler.package_jinja_vars(jinja_vars)) except MarkerError as ex: return ex.source class AnsibleTemplate(Template): """ A helper class, which prevents Jinja2 from running lazy containers through dict(). """ _python_source_temp_path: pathlib.Path | None = None def __del__(self): # DTFIX-FUTURE: this still isn't working reliably; something else must be keeping the template object alive if self._python_source_temp_path: self._python_source_temp_path.unlink(missing_ok=True) def __call__(self, jinja_vars: c.Mapping[str, t.Any]) -> t.Any: return self.render(ArgSmuggler.package_jinja_vars(jinja_vars)) # noinspection PyShadowingBuiltins def new_context( self, vars: c.Mapping[str, t.Any] | None = None, shared: bool = False, locals: c.Mapping[str, t.Any] | None = None, ) -> Context: return _new_context( environment=self.environment, template_name=self.name, blocks=self.blocks, shared=shared, jinja_locals=locals, jinja_vars=ArgSmuggler.extract_jinja_vars(vars), jinja_globals=self.globals, ) class AnsibleCodeGenerator(NativeCodeGenerator): """ Custom code generation behavior to support deprecated Ansible features and fill in gaps in Jinja native. This can be removed once the deprecated Ansible features are removed and the native fixes are upstreamed in Jinja. """ def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: """ Prevent Jinja's code generation from stringifying single nodes before generating its repr. This complements the behavioral change in AnsibleEnvironment.concat which returns single nodes without stringifying them. """ # DTFIX-FUTURE: contribute this upstream as a fix to Jinja's native support group_list = list(group) if len(group_list) == 1: return repr(group_list[0]) # NB: This is slightly more efficient than Jinja's _output_const_repr, which generates a throw-away list instance to pass to join. # Before removing this, ensure that upstream Jinja has this change. return repr("".join(map(str, group_list))) def visit_Const(self, node: Const, frame: Frame) -> None: """ Override Jinja's visit_Const to inject a runtime call to AnsibleEnvironment._access_const for constant strings that are possibly templates, which may require special handling at runtime. See that method for details. An example that hits this path: {{ lookup("file", "{{ output_dir }}/bla") }} """ value = node.as_const(frame.eval_ctx) if _TemplateConfig.allow_embedded_templates and type(value) is str and is_possibly_template(value): # pylint: disable=unidiomatic-typecheck # deprecated: description='embedded Jinja constant string template support' core_version='2.23' self.write(f'environment._access_const({value!r})') else: # NB: This is actually more efficient than Jinja's visit_Const, which contains obsolete (as of Py2.7/3.1) float conversion instance checks. Before # removing this override entirely, ensure that upstream Jinja has removed the obsolete code. # See https://docs.python.org/release/2.7/whatsnew/2.7.html#python-3-1-features for more details. self.write(repr(value)) @pass_context def _ansible_finalize(_ctx: AnsibleContext, value: t.Any) -> t.Any: """ This function is called by Jinja with the result of each variable template block (e.g., {{ }}) encountered in a template. The pass_context decorator prevents finalize from being called on constants at template compile time. The passed in AnsibleContext is unused -- it is the result of using the pass_context decorator. The important part for us is that this blocks constant folding, which ensures our custom visit_Const is used. It also ensures that template results are wrapped in lazy containers. """ return lazify_container(value) @dataclasses.dataclass(kw_only=True, slots=True) class _TemplateCompileContext(_ambient_context.AmbientContextBase): """ This context is active during Ansible's explicit compilation of templates/expressions, but not during Jinja's runtime compilation. Historically, Ansible-specific pre-processing like `escape_backslashes` was not applied to imported/included templates. """ escape_backslashes: bool class _CompileStateSmugglingCtx(_ambient_context.AmbientContextBase): template_source: str | None = None python_source: str | None = None python_source_temp_path: pathlib.Path | None = None class AnsibleLexer(Lexer): """ Lexer override to escape backslashes in string constants within Jinja expressions; prevents Jinja from double-escaping them. NOTE: This behavior is only applied to string constants within Jinja expressions (eg {{ "c:\newfile" }}), *not* statements ("{% set foo="c:\\newfile" %}"). This is useful when templates are sourced from YAML double-quoted strings, as it avoids having backslashes processed twice: first by the YAML parser, and then again by the Jinja parser. Instead, backslashes are only processed by YAML. Example YAML: - debug: msg: "Test Case 1\\3; {{ test1_name | regex_replace('^(.*)_name$', '\\1')}}" Since the outermost YAML string is double-quoted, the YAML parser converts the double backslashes to single backslashes. Without escaping, Jinja would see only a single backslash ('\1') while processing the embedded template expression, interpret it as an escape sequence, and convert it to '\x01' (ASCII "SOH"). This is clearly not the intended `\1` backreference argument to the `regex_replace` filter (which would require the double-escaped string '\\\\1' to yield the intended result). Since the "\\3" in the input YAML was not part of a template expression, the YAML-parsed "\3" remains after Jinja rendering. This would be confusing for playbook authors, as different escaping rules would be needed inside and outside the template expression. When templates are not sourced from YAML, escaping backslashes will prevent use of backslash escape sequences such as "\n" and "\t". See relevant Jinja lexer impl at e.g.: https://github.com/pallets/jinja/blob/3.1.2/src/jinja2/lexer.py#L646-L653. """ def tokeniter(self, *args, **kwargs) -> t.Iterator[t.Tuple[int, str, str]]: """Pre-escape backslashes in expression ({{ }}) raw string constants before Jinja's Lexer.wrap() can interpret them as ASCII escape sequences.""" token_stream = super().tokeniter(*args, **kwargs) # if we have no context, Jinja's doing a nested compile at runtime (eg, import/include); historically, no backslash escaping is performed if not (tcc := _TemplateCompileContext.current(optional=True)) or not tcc.escape_backslashes: yield from token_stream return in_variable = False for token in token_stream: token_type = token[1] if token_type == TOKEN_VARIABLE_BEGIN: in_variable = True elif token_type == TOKEN_VARIABLE_END: in_variable = False elif in_variable and token_type == TOKEN_STRING: token = token[0], token_type, token[2].replace('\\', '\\\\') yield token def defer_template_error(ex: Exception, variable: t.Any, *, is_expression: bool) -> Marker: if not ex.__traceback__: raise AssertionError('ex must be a previously raised exception') if isinstance(ex, MarkerError): return ex.source exception_to_raise = create_template_error(ex, variable, is_expression) if exception_to_raise is ex: return CapturedExceptionMarker(ex) # capture the previously raised exception try: raise exception_to_raise from ex # raise the newly synthesized exception before capturing it except Exception as captured_ex: return CapturedExceptionMarker(captured_ex) def create_template_error(ex: Exception, variable: t.Any, is_expression: bool) -> AnsibleTemplateError: if isinstance(ex, AnsibleTemplateError): exception_to_raise = ex else: kind = "expression" if is_expression else "template" ex_type = AnsibleTemplateError # always raise an AnsibleTemplateError/subclass if isinstance(ex, RecursionError): msg = f"Recursive loop detected in {kind}." elif isinstance(ex, TemplateSyntaxError): msg = f"Syntax error in {kind}." if is_expression and is_possibly_template(variable): msg += " Template delimiters are not supported in expressions." ex_type = AnsibleTemplateSyntaxError else: msg = f"Error rendering {kind}." exception_to_raise = ex_type(msg, obj=variable) if exception_to_raise.obj is None: exception_to_raise.obj = TemplateContext.current().template_value # DTFIX-FUTURE: Look through the TemplateContext hierarchy to find the most recent non-template # caller and use that for origin when no origin is available on obj. This could be useful for situations where the template # was embedded in a plugin, or a plugin is otherwise responsible for losing the origin and/or trust. We can't just use the first # non-template caller as that will lead to false positives for re-entrant calls (e.g. template plugins that call into templar). return exception_to_raise # DTFIX3: implement CapturedExceptionMarker deferral support on call (and lookup), filter/test plugins, etc. # also update the protomatter integration test once this is done (the test was written differently since this wasn't done yet) _BUILTIN_FILTER_ALIASES: dict[str, str] = {} _BUILTIN_TEST_ALIASES: dict[str, str] = { '!=': 'ne', '<': 'lt', '<=': 'le', '==': 'eq', '>': 'gt', '>=': 'ge', } _BUILTIN_FILTERS = filter_loader._wrap_funcs(defaults.DEFAULT_FILTERS, _BUILTIN_FILTER_ALIASES) _BUILTIN_TESTS = test_loader._wrap_funcs(t.cast(dict[str, t.Callable], defaults.DEFAULT_TESTS), _BUILTIN_TEST_ALIASES) class AnsibleEnvironment(ImmutableSandboxedEnvironment): """ Our custom environment, which simply allows us to override the class-level values for the Template and Context classes used by jinja2 internally. """ context_class = AnsibleContext template_class = AnsibleTemplate code_generator_class = AnsibleCodeGenerator intercepted_binops = frozenset(('eq',)) _lexer_cache = LRUCache(50) # DTFIX-FUTURE: bikeshed a name/mechanism to control template debugging _debuggable_template_source = False _debuggable_template_source_path: pathlib.Path = pathlib.Path(__file__).parent.parent.parent.parent / '.template_debug_source' def __init__(self, *args, ansible_basedir: str | None = None, **kwargs) -> None: if ansible_basedir: kwargs.update(loader=FileSystemLoader(ansible_basedir)) super().__init__(*args, extensions=_TemplateConfig.jinja_extensions, **kwargs) self.filters = JinjaPluginIntercept(_BUILTIN_FILTERS, filter_loader) # type: ignore[assignment] self.tests = JinjaPluginIntercept(_BUILTIN_TESTS, test_loader) # type: ignore[assignment,arg-type] # future Jinja releases may default-enable autoescape; force-disable to prevent the problems it could cause # see https://github.com/pallets/jinja/blob/3.1.2/docs/api.rst?plain=1#L69 self.autoescape = False self.trim_blocks = True self.undefined = UndefinedMarker self.finalize = _ansible_finalize self.globals.update( range=range, # the sandboxed environment limits range in ways that may cause us problems; use the real Python one now=_now, undef=_undef, omit=Omit, lookup=_lookup, query=_query, q=_query, ) # Disabling the optimizer prevents compile-time constant expression folding, which prevents our # visit_Const recursive inline template expansion tricks from working in many cases where Jinja's # ignorance of our embedded templates are optimized away as fully-constant expressions, # eg {{ "{{'hi'}}" == "hi" }}. As of Jinja ~3.1, this specifically avoids cases where the @optimizeconst # visitor decorator performs constant folding, which bypasses our visit_Const impl and causes embedded # templates to be lost. # See also optimizeconst impl: https://github.com/pallets/jinja/blob/3.1.0/src/jinja2/compiler.py#L48-L49 self.optimized = False def get_template( self, name: str | Template, parent: str | None = None, globals: c.MutableMapping[str, t.Any] | None = None, ) -> Template: """Ensures that templates built via `get_template` are also source debuggable.""" with _CompileStateSmugglingCtx.when(self._debuggable_template_source) as ctx: template_obj = t.cast(AnsibleTemplate, super().get_template(name, parent, globals)) if isinstance(ctx, _CompileStateSmugglingCtx): # only present if debugging is enabled template_obj._python_source_temp_path = ctx.python_source_temp_path # facilitate deletion of the temp file when template_obj is deleted return template_obj def is_safe_attribute(self, obj: t.Any, attr: str, value: t.Any) -> bool: # deprecated: description="remove relaxed template sandbox mode support" core_version="2.23" if _TemplateConfig.sandbox_mode == _SandboxMode.ALLOW_UNSAFE_ATTRIBUTES: return True return super().is_safe_attribute(obj, attr, value) @property def lexer(self) -> AnsibleLexer: """Return/cache an AnsibleLexer with settings from the current AnsibleEnvironment""" # DTFIX-FUTURE: optimization - we should pre-generate the default cached lexer before forking, not leave it to chance (e.g. simple playbooks) key = tuple(getattr(self, name) for name in _TEMPLATE_OVERRIDE_FIELD_NAMES) lex = self._lexer_cache.get(key) if lex is None: self._lexer_cache[key] = lex = AnsibleLexer(self) return lex def call_filter( self, name: str, value: t.Any, args: c.Sequence[t.Any] | None = None, kwargs: c.Mapping[str, t.Any] | None = None, context: Context | None = None, eval_ctx: EvalContext | None = None, ) -> t.Any: """ Ensure that filters directly invoked by plugins will see non-templating lazy containers. Without this, `_wrap_filter` will wrap `args` and `kwargs` in templating lazy containers. This provides consistency with plugin output handling by preventing auto-templating of trusted templates passed in native containers. """ # DTFIX-FUTURE: need better logic to handle non-list/non-dict inputs for args/kwargs args = _AnsibleLazyTemplateMixin._try_create(list(args or []), LazyOptions.SKIP_TEMPLATES) kwargs = _AnsibleLazyTemplateMixin._try_create(kwargs, LazyOptions.SKIP_TEMPLATES) return super().call_filter(name, value, args, kwargs, context, eval_ctx) def call_test( self, name: str, value: t.Any, args: c.Sequence[t.Any] | None = None, kwargs: c.Mapping[str, t.Any] | None = None, context: Context | None = None, eval_ctx: EvalContext | None = None, ) -> t.Any: """ Ensure that tests directly invoked by plugins will see non-templating lazy containers. Without this, `_wrap_test` will wrap `args` and `kwargs` in templating lazy containers. This provides consistency with plugin output handling by preventing auto-templating of trusted templates passed in native containers. """ # DTFIX-FUTURE: need better logic to handle non-list/non-dict inputs for args/kwargs args = _AnsibleLazyTemplateMixin._try_create(list(args or []), LazyOptions.SKIP_TEMPLATES) kwargs = _AnsibleLazyTemplateMixin._try_create(kwargs, LazyOptions.SKIP_TEMPLATES) return super().call_test(name, value, args, kwargs, context, eval_ctx) def compile_expression(self, source: str, *args, **kwargs) -> TemplateExpression: # compile_expression parses and passes the tree to from_string; for debug support, activate the context here to capture the intermediate results with _CompileStateSmugglingCtx.when(self._debuggable_template_source) as ctx: if isinstance(ctx, _CompileStateSmugglingCtx): # only present if debugging is enabled ctx.template_source = source return super().compile_expression(source, *args, **kwargs) def from_string(self, source: str | jinja2.nodes.Template, *args, **kwargs) -> AnsibleTemplate: # if debugging is enabled, use existing context when present (e.g., from compile_expression) current_ctx = _CompileStateSmugglingCtx.current(optional=True) if self._debuggable_template_source else None with _CompileStateSmugglingCtx.when(self._debuggable_template_source and not current_ctx) as new_ctx: template_obj = t.cast(AnsibleTemplate, super().from_string(source, *args, **kwargs)) if isinstance(ctx := current_ctx or new_ctx, _CompileStateSmugglingCtx): # only present if debugging is enabled template_obj._python_source_temp_path = ctx.python_source_temp_path # facilitate deletion of the temp file when template_obj is deleted return template_obj def _parse(self, source: str, *args, **kwargs) -> jinja2.nodes.Template: if csc := _CompileStateSmugglingCtx.current(optional=True): csc.template_source = source return super()._parse(source, *args, **kwargs) def _compile(self, source: str, filename: str) -> types.CodeType: if csc := _CompileStateSmugglingCtx.current(optional=True): origin = Origin.get_tag(csc.template_source) or Origin.UNKNOWN source = '\n'.join( ( "import sys; breakpoint() if type(sys.breakpointhook) is not type(breakpoint) else None", f"# original template source from {str(origin)!r}: ", '\n'.join(f'# {line}' for line in (csc.template_source or '').splitlines()), source, ) ) source_temp_dir = self._debuggable_template_source_path source_temp_dir.mkdir(parents=True, exist_ok=True) with tempfile.NamedTemporaryFile(dir=source_temp_dir, mode='w', suffix='.py', prefix='j2_src_', delete=False) as source_file: filename = source_file.name source_file.write(source) source_file.flush() csc.python_source = source csc.python_source_temp_path = pathlib.Path(filename) res = super()._compile(source, filename) return res @staticmethod def concat(nodes: t.Iterable[t.Any]) -> t.Any: # type: ignore[override] node_list = list(_flatten_nodes(nodes)) if not node_list: return None # this code is complemented by our tweaked CodeGenerator _output_const_repr that ensures that literal constants # in templates aren't double-repr'd in the generated code if len(node_list) == 1: return node_list[0] # In order to ensure that all markers are tripped, do a recursive finalize before we repr (otherwise we can end up # repr'ing a Marker). This requires two passes, but avoids the need for a parallel reimplementation of all repr methods. try: node_list = _finalize_template_result(node_list, FinalizeMode.CONCAT) except MarkerError as ex: return ex.source # return the first Marker encountered return ''.join([to_text(v) for v in node_list]) @staticmethod def _access_const(const_template: t.LiteralString) -> t.Any: """ Called during template rendering on template-looking string constants embedded in the template. It provides the following functionality: * Propagates origin from the containing template. * For backward compatibility when embedded templates are enabled: * Conditionals - Renders embedded template constants and accesses the result. Warns on each constant immediately. * Non-conditionals - Tags constants for deferred rendering of templates in lookup terms. Warns on each constant during lookup invocation. """ ctx = TemplateContext.current() if (tv := ctx.template_value) and (origin := Origin.get_tag(tv)): const_template = origin.tag(const_template) if ctx._render_jinja_const_template: _jinja_const_template_warning(const_template, is_conditional=True) result = ctx.templar.template(TrustedAsTemplate().tag(const_template)) AnsibleAccessContext.current().access(result) else: # warnings will be issued when lookup terms processing occurs, to avoid false positives result = _JinjaConstTemplate().tag(const_template) return result def getitem(self, obj: t.Any, argument: t.Any) -> t.Any: value = super().getitem(obj, argument) AnsibleAccessContext.current().access(value) return value def getattr(self, obj: t.Any, attribute: str) -> t.Any: """ Get `attribute` from the attributes of `obj`, falling back to items in `obj`. If no item was found, return a sandbox-specific `UndefinedMarker` if `attribute` is protected by the sandbox, otherwise return a normal `UndefinedMarker` instance. This differs from the built-in Jinja behavior which will not fall back to items if `attribute` is protected by the sandbox. """ # example template that uses this: "{{ some.thing }}" -- obj is the "some" dict, attribute is "thing" is_safe = True try: value = getattr(obj, attribute) except AttributeError: value = _sentinel else: if not (is_safe := self.is_safe_attribute(obj, attribute, value)): value = _sentinel if value is _sentinel: try: value = obj[attribute] except (TypeError, LookupError): return self.undefined(obj=obj, name=attribute) if is_safe else self.unsafe_undefined(obj, attribute) AnsibleAccessContext.current().access(value) return value def call( self, __context: Context, __obj: t.Any, *args: t.Any, **kwargs: t.Any, ) -> t.Any: if _DirectCall.is_marked(__obj): # Both `_lookup` and `_query` handle arg proxying and `Marker` args internally. # Performing either before calling them will interfere with that processing. return super().call(__context, __obj, *args, **kwargs) if (first_marker := get_first_marker_arg(args, kwargs)) is not None: return first_marker try: with JinjaCallContext(accept_lazy_markers=False): call_res = super().call(__context, __obj, *lazify_container_args(args), **lazify_container_kwargs(kwargs)) if __obj is range: # Preserve the ability to do `range(1000000000) | random` by not converting range objects to lists. # Historically, range objects were only converted on Jinja finalize and filter outputs, so they've always been floating around in templating # code and visible to user plugins. return call_res return _wrap_plugin_output(call_res) except MarkerError as ex: return ex.source AnsibleTemplate.environment_class = AnsibleEnvironment _DEFAULT_UNDEF = UndefinedMarker("Mandatory variable has not been overridden", _no_template_source=True) _sentinel: t.Final[object] = object() @_DirectCall.mark def _undef(hint=None): """Jinja2 global function (undef) for creating getting a `UndefinedMarker` instance, optionally with a custom hint.""" validate_arg_type('hint', hint, (str, type(None))) if not hint: return _DEFAULT_UNDEF return UndefinedMarker(hint) def _flatten_nodes(nodes: t.Iterable[t.Any]) -> t.Iterable[t.Any]: """ Yield nodes from a potentially recursive iterable of nodes. The recursion is required to expand template imports (TemplateModule). Any exception raised while consuming a template node will be yielded as a Marker for that node. """ iterator = iter(nodes) while True: try: node = next(iterator) except StopIteration: break except Exception as ex: yield defer_template_error(ex, TemplateContext.current().template_value, is_expression=False) # DTFIX-FUTURE: We should be able to determine if truncation occurred by having the code generator smuggle out the number of expected nodes. yield TruncationMarker() else: if type(node) is TemplateModule: # pylint: disable=unidiomatic-typecheck yield from _flatten_nodes(node._body_stream) else: yield node def _flatten_and_lazify_vars(mapping: c.Mapping) -> t.Iterable[c.Mapping]: """Prevent deeply-nested Jinja vars ChainMaps from being created by nested contexts and ensure that all top-level containers support lazy templating.""" mapping_type = type(mapping) if mapping_type is ChainMap: # noinspection PyUnresolvedReferences for m in mapping.maps: yield from _flatten_and_lazify_vars(m) elif mapping_type is _AnsibleLazyTemplateDict: yield mapping elif mapping_type in (dict, _AnsibleTaggedDict): # don't propagate empty dictionary layers if mapping: yield _AnsibleLazyTemplateMixin._try_create(mapping) else: raise NotImplementedError(f"unsupported mapping type in Jinja vars: {mapping_type}") def _new_context( *, environment: Environment, template_name: str | None, blocks: dict[str, t.Callable[[Context], c.Iterator[str]]], shared: bool = False, jinja_locals: c.Mapping[str, t.Any] | None = None, jinja_vars: c.Mapping[str, t.Any] | None = None, jinja_globals: c.MutableMapping[str, t.Any] | None = None, ) -> Context: """Override Jinja's context vars setup to use ChainMaps and containers that support lazy templating.""" layers = [] if jinja_locals: # Omit values set to Jinja's internal `missing` sentinel; they are locals that have not yet been # initialized in the current context, and should not be exposed to child contexts. e.g.: {% import 'a' as b with context %}. # The `b` local will be `missing` in the `a` context and should not be propagated as a local to the child context we're creating. layers.append(_AnsibleLazyTemplateMixin._try_create({k: v for k, v in jinja_locals.items() if v is not missing})) if jinja_vars: layers.extend(_flatten_and_lazify_vars(jinja_vars)) if jinja_globals and not shared: # Even though we don't currently support templating globals, it's easier to ensure that everything is template-able rather than trying to # pick apart the ChainMaps to enforce non-template-able globals, or to risk things that *should* be template-able not being lazified. layers.extend(_flatten_and_lazify_vars(jinja_globals)) if not layers: # ensure we have at least one layer (which should be lazy), since _flatten_and_lazify_vars eliminates most empty layers layers.append(_AnsibleLazyTemplateMixin._try_create({})) # only return a ChainMap if we're combining layers, or we have none parent = layers[0] if len(layers) == 1 else ChainMap(*layers) # the `parent` cast is only to satisfy Jinja's overly-strict type hint return environment.context_class(environment, t.cast(dict, parent), template_name, blocks, globals=jinja_globals) def is_possibly_template(value: str, overrides: TemplateOverrides = TemplateOverrides.DEFAULT): """ A lightweight check to determine if the given string looks like it contains a template, even if that template is invalid. Returns `True` if the given string starts with a Jinja overrides header or if it contains template start strings. """ return value.startswith(JINJA2_OVERRIDE) or overrides._contains_start_string(value) def is_possibly_all_template(value: str, overrides: TemplateOverrides = TemplateOverrides.DEFAULT): """ A lightweight check to determine if the given string looks like it contains *only* a template, even if that template is invalid. Returns `True` if the given string starts with a Jinja overrides header or if it starts and ends with Jinja template delimiters. """ return value.startswith(JINJA2_OVERRIDE) or overrides._starts_and_ends_with_jinja_delimiters(value) class FinalizeMode(enum.Enum): TOP_LEVEL = enum.auto() CONCAT = enum.auto() _FINALIZE_FAST_PATH_EXACT_MAPPING_TYPES = frozenset( ( dict, _AnsibleTaggedDict, _AnsibleLazyTemplateDict, HostVars, HostVarsVars, ) ) """Fast-path exact mapping types for finalization. These types bypass diagnostic warnings for type conversion.""" _FINALIZE_FAST_PATH_EXACT_ITERABLE_TYPES = frozenset( ( list, _AnsibleTaggedList, _AnsibleLazyTemplateList, tuple, _AnsibleTaggedTuple, _AnsibleLazyAccessTuple, ) ) """Fast-path exact iterable types for finalization. These types bypass diagnostic warnings for type conversion.""" _FINALIZE_DISALLOWED_EXACT_TYPES = frozenset((range,)) """Exact types that cannot be finalized.""" # Jinja passes these into filters/tests via @pass_environment register_known_types( AnsibleContext, AnsibleEnvironment, EvalContext, ) def _finalize_dict(o: t.Any, mode: FinalizeMode) -> t.Iterator[tuple[t.Any, t.Any]]: for k, v in o.items(): if v is not Omit: yield _finalize_template_result(k, mode), _finalize_template_result(v, mode) def _finalize_list(o: t.Any, mode: FinalizeMode) -> t.Iterator[t.Any]: for v in o: if v is not Omit: yield _finalize_template_result(v, mode) def _maybe_finalize_scalar(o: t.Any) -> t.Any: # DTFIX5: this should check all supported scalar subclasses, not just JSON ones (also, does the JSON serializer handle these cases?) for target_type in _json_subclassable_scalar_types: if not isinstance(o, target_type): continue match _TemplateConfig.unknown_type_conversion_handler.action: # we don't want to show the object value, and it can't be Origin-tagged; send the current template value for best effort case ErrorAction.WARNING: display.warning( msg=f'Type {native_type_name(o)!r} is unsupported in variable storage, converting to {native_type_name(target_type)!r}.', obj=TemplateContext.current(optional=True).template_value, ) case ErrorAction.ERROR: raise AnsibleVariableTypeError.from_value(obj=TemplateContext.current(optional=True).template_value) return target_type(o) return None def _finalize_fallback_collection( o: t.Any, mode: FinalizeMode, finalizer: t.Callable[[t.Any, FinalizeMode], t.Iterator], target_type: type[list | dict], ) -> t.Collection[t.Any]: match _TemplateConfig.unknown_type_conversion_handler.action: # we don't want to show the object value, and it can't be Origin-tagged; send the current template value for best effort case ErrorAction.WARNING: display.warning( msg=f'Type {native_type_name(o)!r} is unsupported in variable storage, converting to {native_type_name(target_type)!r}.', obj=TemplateContext.current(optional=True).template_value, ) case ErrorAction.ERROR: raise AnsibleVariableTypeError.from_value(obj=TemplateContext.current(optional=True).template_value) return _finalize_collection(o, mode, finalizer, target_type) def _finalize_collection( o: t.Any, mode: FinalizeMode, finalizer: t.Callable[[t.Any, FinalizeMode], t.Iterator], target_type: type[list | dict], ) -> t.Collection[t.Any]: return AnsibleTagHelper.tag(finalizer(o, mode), AnsibleTagHelper.tags(o), value_type=target_type) def _finalize_template_result(o: t.Any, mode: FinalizeMode) -> t.Any: """Recurse the template result, rendering any encountered templates, converting containers to non-lazy versions.""" # DTFIX5: add tests to ensure this method doesn't drift from allowed types o_type = type(o) # DTFIX-FUTURE: provide an optional way to check for trusted templates leaking out of templating (injected, but not passed through templar.template) if o_type is _AnsibleTaggedStr: return _JinjaConstTemplate.untag(o) # prevent _JinjaConstTemplate from leaking into finalized results if o_type in PASS_THROUGH_SCALAR_VAR_TYPES: return o if o_type in _FINALIZE_FAST_PATH_EXACT_MAPPING_TYPES: # silently convert known mapping types to dict return _finalize_collection(o, mode, _finalize_dict, dict) if o_type in _FINALIZE_FAST_PATH_EXACT_ITERABLE_TYPES: # silently convert known sequence types to list return _finalize_collection(o, mode, _finalize_list, list) if o_type in Marker._concrete_subclasses: # this early return assumes handle_marker follows our variable type rules return TemplateContext.current().templar.marker_behavior.handle_marker(o) if mode is not FinalizeMode.TOP_LEVEL: # unsupported type (do not raise) return o if o_type in _FINALIZE_DISALLOWED_EXACT_TYPES: # early abort for disallowed types that would otherwise be handled below raise AnsibleVariableTypeError.from_value(obj=o) if _internal.is_intermediate_mapping(o): # since isinstance checks are slower, this is separate from the exact type check above return _finalize_fallback_collection(o, mode, _finalize_dict, dict) if _internal.is_intermediate_iterable(o): # since isinstance checks are slower, this is separate from the exact type check above return _finalize_fallback_collection(o, mode, _finalize_list, list) if (result := _maybe_finalize_scalar(o)) is not None: return result raise AnsibleVariableTypeError.from_value(obj=o) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_jinja_common.py0000644000000000000000000002676015017704211025043 0ustar00rootrootfrom __future__ import annotations import abc import collections.abc as c import enum import inspect import itertools import typing as t from jinja2 import UndefinedError, StrictUndefined, TemplateRuntimeError from jinja2.utils import missing from ...module_utils._internal import _messages from ansible.constants import config from ansible.errors import AnsibleUndefinedVariable, AnsibleTypeError from ansible._internal._errors._handler import ErrorHandler from ansible.module_utils._internal._datatag import Tripwire, _untaggable_types from ._access import NotifiableAccessContextBase from ._jinja_patches import _patch_jinja from ._utils import TemplateContext from .._errors import _captured from ...module_utils.datatag import native_type_name _patch_jinja() # apply Jinja2 patches before types are declared that are dependent on the changes class _SandboxMode(enum.Enum): DEFAULT = enum.auto() ALLOW_UNSAFE_ATTRIBUTES = enum.auto() class _TemplateConfig: allow_embedded_templates: bool = config.get_config_value("ALLOW_EMBEDDED_TEMPLATES") allow_broken_conditionals: bool = config.get_config_value('ALLOW_BROKEN_CONDITIONALS') jinja_extensions: list[str] = config.get_config_value('DEFAULT_JINJA2_EXTENSIONS') sandbox_mode: _SandboxMode = _SandboxMode.__members__[config.get_config_value('_TEMPLAR_SANDBOX_MODE').upper()] unknown_type_encountered_handler = ErrorHandler.from_config('_TEMPLAR_UNKNOWN_TYPE_ENCOUNTERED') unknown_type_conversion_handler = ErrorHandler.from_config('_TEMPLAR_UNKNOWN_TYPE_CONVERSION') untrusted_template_handler = ErrorHandler.from_config('_TEMPLAR_UNTRUSTED_TEMPLATE_BEHAVIOR') class MarkerError(UndefinedError): """ An Ansible specific subclass of Jinja's UndefinedError, used to preserve and later restore the original Marker instance that raised the error. This error is only raised by Marker and should never escape the templating system. """ def __init__(self, message: str, source: Marker) -> None: super().__init__(message) self.source = source class Marker(StrictUndefined, Tripwire): """ Extends Jinja's `StrictUndefined`, allowing any kind of error occurring during recursive templating operations to be captured and deferred. Direct or managed access to most `Marker` attributes will raise a `MarkerError`, which usually ends the current innermost templating operation and converts the `MarkerError` back to the origin Marker instance (subject to the `MarkerBehavior` in effect at the time). """ __slots__ = ('_marker_template_source',) _concrete_subclasses: t.ClassVar[set[type[Marker]]] = set() def __init__( self, hint: t.Optional[str] = None, obj: t.Any = missing, name: t.Optional[str] = None, exc: t.Type[TemplateRuntimeError] = UndefinedError, # Ansible doesn't set this argument or consume the attribute it is stored under. *args, _no_template_source=False, **kwargs, ) -> None: if not hint and name and obj is not missing: hint = f"object of type {native_type_name(obj)!r} has no attribute {name!r}" kwargs.update( hint=hint, obj=obj, name=name, exc=exc, ) super().__init__(*args, **kwargs) if _no_template_source: self._marker_template_source = None else: self._marker_template_source = TemplateContext.current().template_value def _as_exception(self) -> Exception: """Return the exception instance to raise in a top-level templating context.""" return AnsibleUndefinedVariable(self._undefined_message, obj=self._marker_template_source) def _as_message(self) -> str: """Return the error message to show when this marker must be represented as a string, such as for subsitutions or warnings.""" return self._undefined_message def _fail_with_undefined_error(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: """Ansible-specific replacement for Jinja's _fail_with_undefined_error tripwire on dunder methods.""" self.trip() def trip(self) -> t.NoReturn: """Raise an internal exception which can be converted back to this instance.""" raise MarkerError(self._undefined_message, self) def __setattr__(self, name: str, value: t.Any) -> None: """ Any attempt to set an unknown attribute on a `Marker` should invoke the trip method to propagate the original context. This does not protect against mutation of known attributes, but the implementation is fairly simple. """ try: super().__setattr__(name, value) except AttributeError: pass else: return self.trip() def __getattr__(self, name: str) -> t.Any: """Raises AttributeError for dunder-looking accesses, self-propagates otherwise.""" if name.startswith('__') and name.endswith('__'): raise AttributeError(name) return self def __getitem__(self, key): """Self-propagates on all item accesses.""" return self @classmethod def __init_subclass__(cls, **kwargs) -> None: if not inspect.isabstract(cls): _untaggable_types.add(cls) cls._concrete_subclasses.add(cls) @classmethod def _init_class(cls): _untaggable_types.add(cls) # These are the methods StrictUndefined already intercepts. jinja_method_names = ( '__add__', '__bool__', '__call__', '__complex__', '__contains__', '__div__', '__eq__', '__float__', '__floordiv__', '__ge__', # '__getitem__', # using a custom implementation that propagates self instead '__gt__', '__hash__', '__int__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__pos__', '__pow__', '__radd__', '__rdiv__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__str__', '__sub__', '__truediv__', ) # These additional methods should be intercepted, even though they are not intercepted by StrictUndefined. additional_method_names = ( '__aiter__', '__delattr__', '__format__', '__repr__', '__setitem__', ) for name in jinja_method_names + additional_method_names: setattr(cls, name, cls._fail_with_undefined_error) Marker._init_class() class TruncationMarker(Marker): """ An `Marker` value was previously encountered and reported. A subsequent `Marker` value (this instance) indicates the template may have been truncated as a result. It will only be visible if the previous `Marker` was ignored/replaced instead of being tripped, which would raise an exception. """ __slots__ = () def __init__(self) -> None: super().__init__(hint='template potentially truncated') class UndefinedMarker(Marker): """A `Marker` value that represents an undefined value encountered during templating.""" __slots__ = () class ExceptionMarker(Marker, metaclass=abc.ABCMeta): """Base `Marker` class that represents exceptions encountered and deferred during templating.""" __slots__ = () @abc.abstractmethod def _as_exception(self) -> Exception: pass def _as_message(self) -> str: return str(self._as_exception()) def trip(self) -> t.NoReturn: """Raise an internal exception which can be converted back to this instance while maintaining the cause for callers that follow them.""" raise MarkerError(self._undefined_message, self) from self._as_exception() class CapturedExceptionMarker(ExceptionMarker): """A `Marker` value that represents an exception raised during templating.""" __slots__ = ('_marker_captured_exception',) def __init__(self, exception: Exception) -> None: super().__init__(hint=f'A captured exception marker was tripped: {exception}') self._marker_captured_exception = exception def _as_exception(self) -> Exception: return self._marker_captured_exception class UndecryptableVaultError(_captured.AnsibleCapturedError): """Template-external error raised by VaultExceptionMarker when an undecryptable variable is accessed.""" context = 'vault' _default_message = "Attempt to use undecryptable variable." class VaultExceptionMarker(ExceptionMarker): """A `Marker` value that represents an error accessing a vaulted value during templating.""" __slots__ = ('_marker_undecryptable_ciphertext', '_marker_event') def __init__(self, ciphertext: str, event: _messages.Event) -> None: super().__init__(hint='A vault exception marker was tripped.') self._marker_undecryptable_ciphertext = ciphertext self._marker_event = event def _as_exception(self) -> Exception: return UndecryptableVaultError( obj=self._marker_undecryptable_ciphertext, event=self._marker_event, ) def _disarm(self) -> str: return self._marker_undecryptable_ciphertext def get_first_marker_arg(args: c.Sequence, kwargs: dict[str, t.Any]) -> Marker | None: """Utility method to inspect plugin args and return the first `Marker` encountered, otherwise `None`.""" # CAUTION: This function is exposed in public API as ansible.template.get_first_marker_arg. return next(iter_marker_args(args, kwargs), None) def iter_marker_args(args: c.Sequence, kwargs: dict[str, t.Any]) -> t.Generator[Marker]: """Utility method to iterate plugin args and yield any `Marker` encountered.""" for arg in itertools.chain(args, kwargs.values()): if isinstance(arg, Marker): yield arg class JinjaCallContext(NotifiableAccessContextBase): """ An audit context that wraps all Jinja (template/filter/test/lookup/method/function) calls. While active, calls `trip()` on managed access of `Marker` objects unless the callee declares an understanding of markers. """ _mask = True def __init__(self, accept_lazy_markers: bool) -> None: self._type_interest = frozenset() if accept_lazy_markers else frozenset(Marker._concrete_subclasses) def _notify(self, o: Marker) -> t.NoReturn: o.trip() def validate_arg_type(name: str, value: t.Any, allowed_type_or_types: type | tuple[type, ...], /) -> None: """Validate the type of the given argument while preserving context for Marker values.""" # DTFIX-FUTURE: find a home for this as a general-purpose utliity method and expose it after some API review if isinstance(value, allowed_type_or_types): return if isinstance(allowed_type_or_types, type): arg_type_description = repr(native_type_name(allowed_type_or_types)) else: arg_type_description = ' or '.join(repr(native_type_name(item)) for item in allowed_type_or_types) if isinstance(value, Marker): try: value.trip() except Exception as ex: raise AnsibleTypeError(f"The {name!r} argument must be of type {arg_type_description}.", obj=value) from ex raise AnsibleTypeError(f"The {name!r} argument must be of type {arg_type_description}, not {native_type_name(value)!r}.", obj=value) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_jinja_patches.py0000644000000000000000000000260415017704211025171 0ustar00rootroot"""Runtime patches for Jinja bugs affecting Ansible.""" from __future__ import annotations import jinja2 import jinja2.utils def _patch_jinja_undefined_slots() -> None: """ Fix the broken __slots__ on Jinja's Undefined and StrictUndefined if they're missing in the current version. This will no longer be necessary once the fix is included in the minimum supported Jinja version. See: https://github.com/pallets/jinja/issues/2025 """ if not hasattr(jinja2.Undefined, '__slots__'): jinja2.Undefined.__slots__ = ( "_undefined_hint", "_undefined_obj", "_undefined_name", "_undefined_exception", ) if not hasattr(jinja2.StrictUndefined, '__slots__'): jinja2.StrictUndefined.__slots__ = () def _patch_jinja_missing_type() -> None: """ Fix the `jinja2.utils.missing` type to support pickling while remaining a singleton. This will no longer be necessary once the fix is included in the minimum supported Jinja version. See: https://github.com/pallets/jinja/issues/2027 """ if getattr(jinja2.utils.missing, '__reduce__')() != 'missing': def __reduce__(*_args): return 'missing' type(jinja2.utils.missing).__reduce__ = __reduce__ def _patch_jinja() -> None: """Apply Jinja2 patches.""" _patch_jinja_undefined_slots() _patch_jinja_missing_type() ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_jinja_plugins.py0000644000000000000000000003727415017704211025236 0ustar00rootroot"""Jinja template plugins (filters, tests, lookups) and custom global functions.""" from __future__ import annotations import collections.abc as c import dataclasses import datetime import functools import inspect import re import typing as t from jinja2 import defaults from ansible.module_utils._internal._ambient_context import AmbientContextBase from ansible.module_utils.common.collections import is_sequence from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible._internal._datatag._tags import TrustedAsTemplate from ansible.plugins import AnsibleJinja2Plugin from ansible.plugins.loader import lookup_loader, Jinja2Loader from ansible.plugins.lookup import LookupBase from ansible.utils.display import Display from ._datatag import _JinjaConstTemplate from ._errors import AnsibleTemplatePluginRuntimeError, AnsibleTemplatePluginLoadError, AnsibleTemplatePluginNotFoundError from ._jinja_common import MarkerError, _TemplateConfig, get_first_marker_arg, Marker, JinjaCallContext from ._lazy_containers import lazify_container_kwargs, lazify_container_args, lazify_container, _AnsibleLazyTemplateMixin from ._utils import LazyOptions, TemplateContext _display = Display() _TCallable = t.TypeVar("_TCallable", bound=t.Callable) _ITERATOR_TYPES: t.Final = (c.Iterator, c.ItemsView, c.KeysView, c.ValuesView, range) class JinjaPluginIntercept(c.MutableMapping): """ Simulated dict class that loads Jinja2Plugins at request otherwise all plugins would need to be loaded a priori. NOTE: plugin_loader still loads all 'builtin/legacy' at start so only collection plugins are really at request. """ def __init__(self, jinja_builtins: c.Mapping[str, AnsibleJinja2Plugin], plugin_loader: Jinja2Loader): super(JinjaPluginIntercept, self).__init__() self._plugin_loader = plugin_loader self._jinja_builtins = jinja_builtins self._wrapped_funcs: dict[str, t.Callable] = {} def _wrap_and_set_func(self, instance: AnsibleJinja2Plugin) -> t.Callable: if self._plugin_loader.type == 'filter': plugin_func = self._wrap_filter(instance) else: plugin_func = self._wrap_test(instance) self._wrapped_funcs[instance._load_name] = plugin_func return plugin_func def __getitem__(self, key: str) -> t.Callable: instance: AnsibleJinja2Plugin | None = None plugin_func: t.Callable[..., t.Any] | None if plugin_func := self._wrapped_funcs.get(key): return plugin_func try: instance = self._plugin_loader.get(key) except KeyError: # The plugin name was invalid or no plugin was found by that name. pass except Exception as ex: # An unexpected exception occurred. raise AnsibleTemplatePluginLoadError(self._plugin_loader.type, key) from ex if not instance: try: instance = self._jinja_builtins[key] except KeyError: raise AnsibleTemplatePluginNotFoundError(self._plugin_loader.type, key) from None plugin_func = self._wrap_and_set_func(instance) return plugin_func def __setitem__(self, key: str, value: t.Callable) -> None: self._wrap_and_set_func(self._plugin_loader._wrap_func(key, key, value)) def __delitem__(self, key): raise NotImplementedError() def __contains__(self, item: t.Any) -> bool: try: self.__getitem__(item) except AnsibleTemplatePluginLoadError: return True except AnsibleTemplatePluginNotFoundError: return False return True def __iter__(self): raise NotImplementedError() # dynamic container def __len__(self): raise NotImplementedError() # dynamic container @staticmethod def _invoke_plugin(instance: AnsibleJinja2Plugin, *args, **kwargs) -> t.Any: if not instance.accept_args_markers: if (first_marker := get_first_marker_arg(args, kwargs)) is not None: return first_marker try: with JinjaCallContext(accept_lazy_markers=instance.accept_lazy_markers): return instance.j2_function(*lazify_container_args(args), **lazify_container_kwargs(kwargs)) except MarkerError as ex: return ex.source except Exception as ex: raise AnsibleTemplatePluginRuntimeError(instance.plugin_type, instance.ansible_name) from ex # DTFIX-FUTURE: which name to use? use plugin info? def _wrap_test(self, instance: AnsibleJinja2Plugin) -> t.Callable: """Intercept point for all test plugins to ensure that args are properly templated/lazified.""" @functools.wraps(instance.j2_function) def wrapper(*args, **kwargs) -> bool | Marker: result = self._invoke_plugin(instance, *args, **kwargs) if not isinstance(result, bool): template = TemplateContext.current().template_value _display.deprecated( msg=f"The test plugin {instance.ansible_name!r} returned a non-boolean result of type {type(result)!r}. " "Test plugins must have a boolean result.", obj=template, version="2.23", ) result = bool(result) return result return wrapper def _wrap_filter(self, instance: AnsibleJinja2Plugin) -> t.Callable: """Intercept point for all filter plugins to ensure that args are properly templated/lazified.""" @functools.wraps(instance.j2_function) def wrapper(*args, **kwargs) -> t.Any: result = self._invoke_plugin(instance, *args, **kwargs) result = _wrap_plugin_output(result) return result return wrapper class _DirectCall: """Functions/methods marked `_DirectCall` bypass Jinja Environment checks for `Marker`.""" _marker_attr: str = "_directcall" @classmethod def mark(cls, src: _TCallable) -> _TCallable: setattr(src, cls._marker_attr, True) return src @classmethod def is_marked(cls, value: t.Callable) -> bool: return callable(value) and getattr(value, "_directcall", False) @_DirectCall.mark def _query(plugin_name: str, /, *args, **kwargs) -> t.Any: """wrapper for lookup, force wantlist true""" kwargs['wantlist'] = True return _invoke_lookup(plugin_name=plugin_name, lookup_terms=list(args), lookup_kwargs=kwargs) @_DirectCall.mark def _lookup(plugin_name: str, /, *args, **kwargs) -> t.Any: # convert the args tuple to a list, since some plugins make a poor assumption that `run.args` is a list return _invoke_lookup(plugin_name=plugin_name, lookup_terms=list(args), lookup_kwargs=kwargs) @dataclasses.dataclass class _LookupContext(AmbientContextBase): """Ambient context that wraps lookup execution, providing information about how it was invoked.""" invoked_as_with: bool @_DirectCall.mark def _invoke_lookup(*, plugin_name: str, lookup_terms: list, lookup_kwargs: dict[str, t.Any], invoked_as_with: bool = False) -> t.Any: templar = TemplateContext.current().templar from ansible import template as _template try: instance: LookupBase | None = lookup_loader.get(plugin_name, loader=templar._loader, templar=_template.Templar._from_template_engine(templar)) except Exception as ex: raise AnsibleTemplatePluginLoadError('lookup', plugin_name) from ex if instance is None: raise AnsibleTemplatePluginNotFoundError('lookup', plugin_name) # if the lookup doesn't understand `Marker` and there's at least one in the top level, short-circuit by returning the first one we found if not instance.accept_args_markers and (first_marker := get_first_marker_arg(lookup_terms, lookup_kwargs)) is not None: return first_marker # don't pass these through to the lookup wantlist = lookup_kwargs.pop('wantlist', False) errors = lookup_kwargs.pop('errors', 'strict') with JinjaCallContext(accept_lazy_markers=instance.accept_lazy_markers): try: if _TemplateConfig.allow_embedded_templates: # for backwards compat, only trust constant templates in lookup terms with JinjaCallContext(accept_lazy_markers=True): # Force lazy marker support on for this call; the plugin's understanding is irrelevant, as is any existing context, since this backward # compat code always understands markers. lookup_terms = [templar.template(value) for value in _trust_jinja_constants(lookup_terms)] # since embedded template support is enabled, repeat the check for `Marker` on lookup_terms, since a template may render as a `Marker` if not instance.accept_args_markers and (first_marker := get_first_marker_arg(lookup_terms, {})) is not None: return first_marker else: lookup_terms = AnsibleTagHelper.tag_copy(lookup_terms, (lazify_container(value) for value in lookup_terms), value_type=list) with _LookupContext(invoked_as_with=invoked_as_with): # The lookup context currently only supports the internal use-case where `first_found` requires extra info when invoked via `with_first_found`. # The context may be public API in the future, but for now, other plugins should not implement this kind of dynamic behavior, # though we're stuck with it for backward compatibility on `first_found`. lookup_res = instance.run(lookup_terms, variables=templar.available_variables, **lazify_container_kwargs(lookup_kwargs)) # DTFIX-FUTURE: Consider allowing/requiring lookup plugins to declare how their result should be handled. # Currently, there are multiple behaviors that are less than ideal and poorly documented (or not at all): # * When `errors=warn` or `errors=ignore` the result is `None` unless `wantlist=True`, in which case the result is `[]`. # * The user must specify `wantlist=True` to receive the plugin return value unmodified. # A plugin can achieve similar results by wrapping its result in a list -- unless of course the user specifies `wantlist=True`. # * When `wantlist=True` is specified, the result is not guaranteed to be a list as the option implies (except on plugin error). # * Sequences are munged unless the user specifies `wantlist=True`: # * len() == 0 - Return an empty sequence. # * len() == 1 - Return the only element in the sequence. # * len() >= 2 when all elements are `str` - Return all the values joined into a single comma separated string. # * len() >= 2 when at least one element is not `str` - Return the sequence as-is. if not is_sequence(lookup_res): # DTFIX-FUTURE: deprecate return types which are not a list # previously non-Sequence return types were deprecated and then became an error in 2.18 # however, the deprecation message (and this error) mention `list` specifically rather than `Sequence` # letting non-list values through will trigger variable type checking warnings/errors raise TypeError(f'returned {type(lookup_res)} instead of {list}') except MarkerError as ex: return ex.source except Exception as ex: # DTFIX-FUTURE: convert this to the new error/warn/ignore context manager if errors == 'warn': _display.error_as_warning( msg=f'An error occurred while running the lookup plugin {plugin_name!r}.', exception=ex, ) elif errors == 'ignore': _display.display(f'An error of type {type(ex)} occurred while running the lookup plugin {plugin_name!r}: {ex}', log_only=True) else: raise AnsibleTemplatePluginRuntimeError('lookup', plugin_name) from ex return [] if wantlist else None if not wantlist and lookup_res: # when wantlist=False the lookup result is either partially delaizified (single element) or fully delaizified (multiple elements) if len(lookup_res) == 1: lookup_res = lookup_res[0] else: try: lookup_res = ",".join(lookup_res) # for backwards compatibility, attempt to join `ran` into single string except TypeError: pass # for backwards compatibility, return `ran` as-is when the sequence contains non-string values return _wrap_plugin_output(lookup_res) def _now(utc=False, fmt=None): """Jinja2 global function (now) to return current datetime, potentially formatted via strftime.""" if utc: now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) else: now = datetime.datetime.now() if fmt: return now.strftime(fmt) return now def _jinja_const_template_warning(value: object, is_conditional: bool) -> None: """Issue a warning regarding embedded template usage.""" help_text = "Use inline expressions, for example: " if is_conditional: help_text += """`when: "{{ a_var }}" == 42` becomes `when: a_var == 42`""" else: help_text += """`msg: "{{ lookup('env', '{{ a_var }}') }}"` becomes `msg: "{{ lookup('env', a_var) }}"`""" # deprecated: description='disable embedded templates by default and deprecate the feature' core_version='2.23' _display.warning( msg="Jinja constant strings should not contain embedded templates. This feature will be disabled by default in ansible-core 2.23.", obj=value, help_text=help_text, ) def _trust_jinja_constants(o: t.Any) -> t.Any: """ Recursively apply TrustedAsTemplate to values tagged with _JinjaConstTemplate and remove the tag. Only container types emitted by the Jinja compiler are checked, since others do not contain constants. This is used to provide backwards compatibility with historical lookup behavior for positional arguments. """ if _JinjaConstTemplate.is_tagged_on(o): _jinja_const_template_warning(o, is_conditional=False) return TrustedAsTemplate().tag(_JinjaConstTemplate.untag(o)) o_type = type(o) if o_type is dict: return {k: _trust_jinja_constants(v) for k, v in o.items()} if o_type in (list, tuple): return o_type(_trust_jinja_constants(v) for v in o) return o def _wrap_plugin_output(o: t.Any) -> t.Any: """Utility method to ensure that iterators/generators returned from a plugins are consumed.""" if isinstance(o, _ITERATOR_TYPES): o = list(o) return _AnsibleLazyTemplateMixin._try_create(o, LazyOptions.SKIP_TEMPLATES) _PLUGIN_SOURCES = dict( filter=defaults.DEFAULT_FILTERS, test=defaults.DEFAULT_TESTS, ) def _get_builtin_short_description(plugin: object) -> str: """ Make a reasonable effort to break a function docstring down to a single sentence. We can't use the full docstring due to embedded formatting, particularly RST. This isn't intended to be perfect, just good enough until we can write our own docs for these. """ value = re.split(r'(\.|!|\s\(|:\s)', inspect.getdoc(plugin), 1)[0].replace('\n', ' ') if value: value += '.' return value def get_jinja_builtin_plugin_descriptions(plugin_type: str) -> dict[str, str]: """Returns a dictionary of Jinja builtin plugin names and their short descriptions.""" return {f'ansible.builtin.{name}': _get_builtin_short_description(plugin) for name, plugin in _PLUGIN_SOURCES[plugin_type].items() if name.isidentifier()} ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_lazy_containers.py0000644000000000000000000006502715017704211025603 0ustar00rootrootfrom __future__ import annotations import copy import dataclasses import functools import types import typing as t from jinja2.environment import TemplateModule from ansible.module_utils._internal._datatag import ( AnsibleTagHelper, AnsibleTaggedObject, _AnsibleTaggedDict, _AnsibleTaggedList, _AnsibleTaggedTuple, _NO_INSTANCE_STORAGE, _try_get_internal_tags_mapping, ) from ansible.utils.sentinel import Sentinel from ansible.errors import AnsibleVariableTypeError from ansible._internal._errors._handler import Skippable from ansible.vars.hostvars import HostVarsVars, HostVars from ._access import AnsibleAccessContext from ._jinja_common import Marker, _TemplateConfig from ._utils import TemplateContext, PASS_THROUGH_SCALAR_VAR_TYPES, LazyOptions if t.TYPE_CHECKING: from ._engine import TemplateEngine _KNOWN_TYPES: t.Final[set[type]] = ( { HostVars, # example: hostvars HostVarsVars, # example: hostvars.localhost | select type, # example: range(20) | list # triggered on retrieval of `range` type from globals range, # example: range(20) | list # triggered when returning a `range` instance from a call types.FunctionType, # example: undef() | default("blah") types.MethodType, # example: ansible_facts.get | type_debug functools.partial, type(''.startswith), # example: inventory_hostname.upper | type_debug # using `startswith` to resolve `builtin_function_or_method` TemplateModule, # example: '{% import "importme.j2" as im %}{{ im | type_debug }}' } | set(PASS_THROUGH_SCALAR_VAR_TYPES) | set(Marker._concrete_subclasses) ) """ These types are known to the templating system. In addition to the statically defined types, additional types will be added at runtime. When enabled in config, this set will be used to determine if an encountered type should trigger a warning or error. """ def register_known_types(*args: type) -> None: """Register a type with the template engine so it will not trigger warnings or errors when encountered.""" _KNOWN_TYPES.update(args) class UnsupportedConstructionMethodError(RuntimeError): """Error raised when attempting to construct a lazy container with unsupported arguments.""" def __init__(self): super().__init__("Direct construction of lazy containers is not supported.") @t.final @dataclasses.dataclass(frozen=True, slots=True) class _LazyValue: """Wrapper around values to indicate lazy behavior has not yet been applied.""" value: t.Any @t.final @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class _LazyValueSource: """Intermediate value source for lazy-eligible collection copy operations.""" source: t.Iterable templar: TemplateEngine lazy_options: LazyOptions @t.final class _NoKeySentinel(Sentinel): """Sentinel used to indicate a requested key was not found.""" # There are several operations performed by lazy containers, with some variation between types. # # Columns: D=dict, L=list, T=tuple # Cells: l=lazy (upon access), n=non-lazy (__init__/__new__) # # D L T Feature Description # - - - ----------- --------------------------------------------------------------- # l l n propagation when container items which are containers become lazy instances # l l n transform when transforms are applied to container items # l l n templating when templating is performed on container items # l l l access when access calls are performed on container items class _AnsibleLazyTemplateMixin: __slots__ = _NO_INSTANCE_STORAGE _dispatch_types: t.ClassVar[dict[type, type[_AnsibleLazyTemplateMixin]]] = {} # populated by __init_subclass__ _container_types: t.ClassVar[set[type]] = set() # populated by __init_subclass__ _native_type: t.ClassVar[type] # from AnsibleTaggedObject _SLOTS: t.Final = ( '_templar', '_lazy_options', ) _templar: TemplateEngine _lazy_options: LazyOptions def __init_subclass__(cls, **kwargs) -> None: tagged_type = cls.__mro__[1] native_type = tagged_type.__mro__[1] for check_type in (tagged_type, native_type): if conflicting_type := cls._dispatch_types.get(check_type): raise TypeError(f"Lazy mixin {cls.__name__!r} type {check_type.__name__!r} conflicts with {conflicting_type.__name__!r}.") cls._dispatch_types[native_type] = cls cls._dispatch_types[tagged_type] = cls cls._container_types.add(native_type) cls._empty_tags_as_native = False # never revert to the native type when no tags remain register_known_types(cls) def __init__(self, contents: t.Iterable | _LazyValueSource) -> None: if isinstance(contents, _LazyValueSource): self._templar = contents.templar self._lazy_options = contents.lazy_options elif isinstance(contents, _AnsibleLazyTemplateMixin): self._templar = contents._templar self._lazy_options = contents._lazy_options else: raise UnsupportedConstructionMethodError() def __reduce_ex__(self, protocol): raise NotImplementedError("Pickling of Ansible lazy objects is not permitted.") @staticmethod def _try_create(item: t.Any, lazy_options: LazyOptions = LazyOptions.DEFAULT) -> t.Any: """ If `item` is a container type which supports lazy access and/or templating, return a lazy wrapped version -- otherwise return it as-is. When returning as-is, a warning or error may be generated for unknown types. The `lazy_options.skip_templates` argument should be set to `True` when `item` is sourced from a plugin instead of Ansible variable storage. This provides backwards compatibility and reduces lazy overhead, as plugins do not normally introduce templates. If a plugin needs to introduce templates, the plugin is responsible for invoking the templar and returning the result. """ item_type = type(item) # Try to use exact type match first to determine which wrapper (if any) to apply; isinstance checks # are extremely expensive, so try to avoid them for our commonly-supported types. if (dispatcher := _AnsibleLazyTemplateMixin._dispatch_types.get(item_type)) is not None: # Create a generator that yields the elements of `item` wrapped in a `_LazyValue` wrapper. # The wrapper is used to signal to the lazy container that the value must be processed before being returned. # Values added to the lazy container later through other means will be returned as-is, without any special processing. lazy_values = dispatcher._lazy_values(item, lazy_options) tags_mapping = _try_get_internal_tags_mapping(item) value = t.cast(AnsibleTaggedObject, dispatcher)._instance_factory(lazy_values, tags_mapping) return value with Skippable, _TemplateConfig.unknown_type_encountered_handler.handle(AnsibleVariableTypeError, skip_on_ignore=True): if item_type not in _KNOWN_TYPES: raise AnsibleVariableTypeError( message=f"Encountered unknown type {item_type.__name__!r} during template operation.", help_text="Use supported types to avoid unexpected behavior.", obj=TemplateContext.current().template_value, ) return item def _is_not_lazy_combine_candidate(self, other: object) -> bool: """Returns `True` if `other` cannot be lazily combined with the current instance due to differing templar/options, otherwise returns `False`.""" return isinstance(other, _AnsibleLazyTemplateMixin) and (self._templar is not other._templar or self._lazy_options != other._lazy_options) def _non_lazy_copy(self) -> t.Collection: """ Return a non-lazy copy of this collection. Any remaining lazy wrapped values will be unwrapped without further processing. Tags on this instance will be preserved on the returned copy. """ raise NotImplementedError() # pragma: nocover @staticmethod def _lazy_values(values: t.Any, lazy_options: LazyOptions) -> _LazyValueSource: """ Return an iterable that wraps each of the given elements in a lazy wrapper. Only elements wrapped this way will receive lazy processing when retrieved from the collection. """ # DTFIX-FUTURE: check relative performance of method-local vs stored generator expressions on implementations of this method raise NotImplementedError() # pragma: nocover def _proxy_or_render_lazy_value(self, key: t.Any, value: t.Any) -> t.Any: """ Ensure that the value is lazy-proxied or rendered, and if a key is provided, replace the original value with the result. """ if type(value) is not _LazyValue: # pylint: disable=unidiomatic-typecheck if self._lazy_options.access: AnsibleAccessContext.current().access(value) return value original_value = value.value if self._lazy_options.access: AnsibleAccessContext.current().access(original_value) new_value = self._templar.template(original_value, lazy_options=self._lazy_options) if new_value is not original_value and self._lazy_options.access: AnsibleAccessContext.current().access(new_value) if key is not _NoKeySentinel: self._native_type.__setitem__(self, key, new_value) # type: ignore # pylint: disable=unnecessary-dunder-call return new_value @t.final # consumers of lazy collections rely heavily on the concrete types being final class _AnsibleLazyTemplateDict(_AnsibleTaggedDict, _AnsibleLazyTemplateMixin): __slots__ = _AnsibleLazyTemplateMixin._SLOTS def __init__(self, contents: t.Iterable | _LazyValueSource, /, **kwargs) -> None: _AnsibleLazyTemplateMixin.__init__(self, contents) if isinstance(contents, _AnsibleLazyTemplateDict): super().__init__(dict.items(contents), **kwargs) elif isinstance(contents, _LazyValueSource): super().__init__(contents.source, **kwargs) else: raise UnsupportedConstructionMethodError() def get(self, key: t.Any, default: t.Any = None) -> t.Any: if (value := super().get(key, _NoKeySentinel)) is _NoKeySentinel: return default return self._proxy_or_render_lazy_value(key, value) def __getitem__(self, key: t.Any, /) -> t.Any: return self._proxy_or_render_lazy_value(key, super().__getitem__(key)) def __str__(self): return str(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical) def __repr__(self): return repr(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical) def __iter__(self): # We're using the base implementation, but must override `__iter__` to skip `dict` fast-path copy, which would bypass lazy behavior. # See: https://github.com/python/cpython/blob/ffcc450a9b8b6927549b501eff7ac14abc238448/Objects/dictobject.c#L3861-L3864 return super().__iter__() def setdefault(self, key, default=None, /) -> t.Any: if (value := self.get(key, _NoKeySentinel)) is not _NoKeySentinel: return value super().__setitem__(key, default) return default def items(self): for key, value in super().items(): yield key, self._proxy_or_render_lazy_value(key, value) def values(self): for _key, value in self.items(): yield value def pop(self, key, default=_NoKeySentinel, /) -> t.Any: if (value := super().get(key, _NoKeySentinel)) is _NoKeySentinel: if default is _NoKeySentinel: raise KeyError(key) return default value = self._proxy_or_render_lazy_value(_NoKeySentinel, value) del self[key] return value def popitem(self) -> t.Any: try: key = next(reversed(self)) except StopIteration: raise KeyError("popitem(): dictionary is empty") value = self._proxy_or_render_lazy_value(_NoKeySentinel, self[key]) del self[key] return key, value def _native_copy(self) -> dict: return dict(self.items()) @staticmethod def _item_source(value: dict) -> dict | _LazyValueSource: if isinstance(value, _AnsibleLazyTemplateDict): return _LazyValueSource(source=dict.items(value), templar=value._templar, lazy_options=value._lazy_options) return value def _yield_non_lazy_dict_items(self) -> t.Iterator[tuple[str, t.Any]]: """ Delegate to the base collection items iterator to yield the raw contents. As of Python 3.13, generator functions are significantly faster than inline generator expressions. """ for k, v in dict.items(self): yield k, v.value if type(v) is _LazyValue else v # pylint: disable=unidiomatic-typecheck def _non_lazy_copy(self) -> dict: return AnsibleTagHelper.tag_copy(self, self._yield_non_lazy_dict_items(), value_type=dict) @staticmethod def _lazy_values(values: dict, lazy_options: LazyOptions) -> _LazyValueSource: return _LazyValueSource(source=((k, _LazyValue(v)) for k, v in values.items()), templar=TemplateContext.current().templar, lazy_options=lazy_options) @staticmethod def _proxy_or_render_other(other: t.Any | None) -> None: """Call `_proxy_or_render_lazy_values` if `other` is a lazy dict. Used internally by comparison methods.""" if type(other) is _AnsibleLazyTemplateDict: # pylint: disable=unidiomatic-typecheck other._proxy_or_render_lazy_values() def _proxy_or_render_lazy_values(self) -> None: """Ensure all `_LazyValue` wrapped values have been processed.""" for _unused in self.values(): pass def __eq__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__eq__(other) def __ne__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__ne__(other) def __or__(self, other): # DTFIX-FUTURE: support preservation of laziness when possible like we do for list # Both sides end up going through _proxy_or_render_lazy_value, so there's no Templar preservation needed. # In the future this could be made more lazy when both Templar instances are the same, or if per-value Templar tracking was used. return super().__or__(other) def __ror__(self, other): # DTFIX-FUTURE: support preservation of laziness when possible like we do for list # Both sides end up going through _proxy_or_render_lazy_value, so there's no Templar preservation needed. # In the future this could be made more lazy when both Templar instances are the same, or if per-value Templar tracking was used. return super().__ror__(other) def __deepcopy__(self, memo): return _AnsibleLazyTemplateDict( _LazyValueSource( source=((copy.deepcopy(k), copy.deepcopy(v)) for k, v in super().items()), templar=copy.deepcopy(self._templar), lazy_options=copy.deepcopy(self._lazy_options), ) ) @t.final # consumers of lazy collections rely heavily on the concrete types being final class _AnsibleLazyTemplateList(_AnsibleTaggedList, _AnsibleLazyTemplateMixin): __slots__ = _AnsibleLazyTemplateMixin._SLOTS def __init__(self, contents: t.Iterable | _LazyValueSource, /) -> None: _AnsibleLazyTemplateMixin.__init__(self, contents) if isinstance(contents, _AnsibleLazyTemplateList): super().__init__(list.__iter__(contents)) elif isinstance(contents, _LazyValueSource): super().__init__(contents.source) else: raise UnsupportedConstructionMethodError() def __getitem__(self, key: t.SupportsIndex | slice, /) -> t.Any: if type(key) is slice: # pylint: disable=unidiomatic-typecheck return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__getitem__(key), templar=self._templar, lazy_options=self._lazy_options)) return self._proxy_or_render_lazy_value(key, super().__getitem__(key)) def __iter__(self): for key, value in enumerate(super().__iter__()): yield self._proxy_or_render_lazy_value(key, value) def pop(self, idx: t.SupportsIndex = -1, /) -> t.Any: if not self: raise IndexError('pop from empty list') try: value = self[idx] except IndexError: raise IndexError('pop index out of range') value = self._proxy_or_render_lazy_value(_NoKeySentinel, value) del self[idx] return value def __str__(self): return str(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical) def __repr__(self): return repr(self.copy()._native_copy()) # inefficient, but avoids mutating the current instance (to make debugging practical) @staticmethod def _item_source(value: list) -> list | _LazyValueSource: if isinstance(value, _AnsibleLazyTemplateList): return _LazyValueSource(source=list.__iter__(value), templar=value._templar, lazy_options=value._lazy_options) return value def _yield_non_lazy_list_items(self): """ Delegate to the base collection iterator to yield the raw contents. As of Python 3.13, generator functions are significantly faster than inline generator expressions. """ for v in list.__iter__(self): yield v.value if type(v) is _LazyValue else v # pylint: disable=unidiomatic-typecheck def _non_lazy_copy(self) -> list: return AnsibleTagHelper.tag_copy(self, self._yield_non_lazy_list_items(), value_type=list) @staticmethod def _lazy_values(values: list, lazy_options: LazyOptions) -> _LazyValueSource: return _LazyValueSource(source=(_LazyValue(v) for v in values), templar=TemplateContext.current().templar, lazy_options=lazy_options) @staticmethod def _proxy_or_render_other(other: t.Any | None) -> None: """Call `_proxy_or_render_lazy_values` if `other` is a lazy list. Used internally by comparison methods.""" if type(other) is _AnsibleLazyTemplateList: # pylint: disable=unidiomatic-typecheck other._proxy_or_render_lazy_values() def _proxy_or_render_lazy_values(self) -> None: """Ensure all `_LazyValue` wrapped values have been processed.""" for _unused in self: pass def __eq__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__eq__(other) def __ne__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__ne__(other) def __gt__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__gt__(other) def __ge__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__ge__(other) def __lt__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__lt__(other) def __le__(self, other): self._proxy_or_render_lazy_values() self._proxy_or_render_other(other) return super().__le__(other) def __contains__(self, item): self._proxy_or_render_lazy_values() return super().__contains__(item) def __reversed__(self): for idx in range(self.__len__() - 1, -1, -1): yield self[idx] def __add__(self, other): if self._is_not_lazy_combine_candidate(other): # When other is lazy with a different templar/options, it cannot be lazily combined with self and a plain list must be returned. # If other is a list, de-lazify both, otherwise just let the operation fail. if isinstance(other, _AnsibleLazyTemplateList): self._proxy_or_render_lazy_values() other._proxy_or_render_lazy_values() return super().__add__(other) # For all other cases, the new list inherits our templar and all values stay lazy. # We use list.__add__ to avoid implementing all its error behavior. return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__add__(other), templar=self._templar, lazy_options=self._lazy_options)) def __radd__(self, other): if not (other_add := getattr(other, '__add__', None)): raise TypeError(f'unsupported operand type(s) for +: {type(other).__name__!r} and {type(self).__name__!r}') from None return _AnsibleLazyTemplateList(_LazyValueSource(source=other_add(self), templar=self._templar, lazy_options=self._lazy_options)) def __mul__(self, other): return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__mul__(other), templar=self._templar, lazy_options=self._lazy_options)) def __rmul__(self, other): return _AnsibleLazyTemplateList(_LazyValueSource(source=super().__rmul__(other), templar=self._templar, lazy_options=self._lazy_options)) def index(self, *args, **kwargs) -> int: self._proxy_or_render_lazy_values() return super().index(*args, **kwargs) def remove(self, *args, **kwargs) -> None: self._proxy_or_render_lazy_values() super().remove(*args, **kwargs) def sort(self, *args, **kwargs) -> None: self._proxy_or_render_lazy_values() super().sort(*args, **kwargs) def __deepcopy__(self, memo): return _AnsibleLazyTemplateList( _LazyValueSource( source=(copy.deepcopy(v) for v in super().__iter__()), templar=copy.deepcopy(self._templar), lazy_options=copy.deepcopy(self._lazy_options), ) ) @t.final # consumers of lazy collections rely heavily on the concrete types being final class _AnsibleLazyAccessTuple(_AnsibleTaggedTuple, _AnsibleLazyTemplateMixin): """ A tagged tuple subclass that provides only managed access for existing lazy values. Since tuples are immutable, they cannot support lazy templating (which would change the tuple's value as templates were resolved). When this type is created, each value in the source tuple is lazified: * template strings are templated immediately (possibly resulting in lazy containers) * non-tuple containers are lazy-wrapped * tuples are immediately recursively lazy-wrapped * transformations are applied immediately The resulting object provides only managed access to its values (e.g., deprecation warnings, tripwires), and propagates to new lazy containers created as a results of managed access. """ # DTFIX5: ensure we have tests that explicitly verify this behavior # nonempty __slots__ not supported for subtype of 'tuple' def __new__(cls, contents: t.Iterable | _LazyValueSource, /) -> t.Self: if isinstance(contents, _AnsibleLazyAccessTuple): return super().__new__(cls, tuple.__iter__(contents)) if isinstance(contents, _LazyValueSource): return super().__new__(cls, contents.source) raise UnsupportedConstructionMethodError() def __init__(self, contents: t.Iterable | _LazyValueSource, /) -> None: _AnsibleLazyTemplateMixin.__init__(self, contents) def __getitem__(self, key: t.SupportsIndex | slice, /) -> t.Any: if type(key) is slice: # pylint: disable=unidiomatic-typecheck return _AnsibleLazyAccessTuple(super().__getitem__(key)) value = super().__getitem__(key) if self._lazy_options.access: AnsibleAccessContext.current().access(value) return value @staticmethod def _item_source(value: tuple) -> tuple | _LazyValueSource: if isinstance(value, _AnsibleLazyAccessTuple): return _LazyValueSource(source=tuple.__iter__(value), templar=value._templar, lazy_options=value._lazy_options) return value @staticmethod def _lazy_values(values: t.Any, lazy_options: LazyOptions) -> _LazyValueSource: templar = TemplateContext.current().templar return _LazyValueSource(source=(templar.template(value, lazy_options=lazy_options) for value in values), templar=templar, lazy_options=lazy_options) def _non_lazy_copy(self) -> tuple: return AnsibleTagHelper.tag_copy(self, self, value_type=tuple) def __deepcopy__(self, memo): return _AnsibleLazyAccessTuple( _LazyValueSource( source=(copy.deepcopy(v) for v in super().__iter__()), templar=copy.deepcopy(self._templar), lazy_options=copy.deepcopy(self._lazy_options), ) ) def lazify_container(value: t.Any) -> t.Any: """ If the given value is a supported container type, return its lazy version, otherwise return the value as-is. This is used to ensure that managed access and templating occur on args and kwargs to a callable, even if they were sourced from Jinja constants. Since both variable access and plugin output are already lazified, this mostly affects Jinja constant containers. However, plugins that directly invoke other plugins (e.g., `Environment.call_filter`) are another potential source of non-lazy containers. In these cases, templating will occur for trusted templates automatically upon access. Sets, tuples, and dictionary keys cannot be lazy, since their correct operation requires hashability and equality. These properties are mutually exclusive with the following lazy features: - managed access on encrypted strings - may raise errors on both operations when decryption fails - managed access on markers - must raise errors on both operations - templating - mutates values That leaves non-raising managed access as the only remaining feature, which is insufficient to warrant lazy support. """ return _AnsibleLazyTemplateMixin._try_create(value) def lazify_container_args(item: tuple) -> tuple: """Return the given args with values converted to lazy containers as needed.""" return tuple(lazify_container(value) for value in item) def lazify_container_kwargs(item: dict[str, t.Any]) -> dict[str, t.Any]: """Return the given kwargs with values converted to lazy containers as needed.""" return {key: lazify_container(value) for key, value in item.items()} ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_marker_behaviors.py0000644000000000000000000000655715017704211025725 0ustar00rootroot"""Handling of `Marker` values.""" from __future__ import annotations import abc import contextlib import dataclasses import itertools import typing as t from ansible.utils.display import Display from ._jinja_common import Marker class MarkerBehavior(metaclass=abc.ABCMeta): """Base class to support custom handling of `Marker` values encountered during concatenation or finalization.""" @abc.abstractmethod def handle_marker(self, value: Marker) -> t.Any: """Handle the given `Marker` value.""" class FailingMarkerBehavior(MarkerBehavior): """ The default behavior when encountering a `Marker` value during concatenation or finalization. This always raises the template-internal `MarkerError` exception. """ def handle_marker(self, value: Marker) -> t.Any: value.trip() # FAIL_ON_MARKER_BEHAVIOR # _DETONATE_MARKER_BEHAVIOR - internal singleton since it's the default and nobody should need to reference it, or make it an actual singleton FAIL_ON_UNDEFINED: t.Final = FailingMarkerBehavior() # no sense in making many instances... @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class _MarkerTracker: """A numbered occurrence of a `Marker` value for later conversion to a warning.""" number: int value: Marker class ReplacingMarkerBehavior(MarkerBehavior): """All `Marker` values are replaced with a numbered string placeholder and the message from the value.""" def __init__(self) -> None: self._trackers: list[_MarkerTracker] = [] def record_marker(self, value: Marker) -> t.Any: """Assign a sequence number to the given value and record it for later generation of warnings.""" number = len(self._trackers) + 1 self._trackers.append(_MarkerTracker(number=number, value=value)) return number def emit_warnings(self) -> None: """Emit warning messages caused by Marker values, aggregated by unique template.""" display = Display() grouped_templates = itertools.groupby(self._trackers, key=lambda tracker: tracker.value._marker_template_source) for template, items in grouped_templates: item_list = list(items) msg = f'Encountered {len(item_list)} template error{"s" if len(item_list) > 1 else ""}.' for item in item_list: msg += f'\nerror {item.number} - {item.value._as_message()}' display.warning(msg=msg, obj=template) @classmethod @contextlib.contextmanager def warning_context(cls) -> t.Generator[t.Self, None, None]: """Collect warnings for `Marker` values and emit warnings when the context exits.""" instance = cls() try: yield instance finally: instance.emit_warnings() def handle_marker(self, value: Marker) -> t.Any: number = self.record_marker(value) return f"<< error {number} - {value._as_message()} >>" class RoutingMarkerBehavior(MarkerBehavior): """Routes instances of Marker (by type reference) to another MarkerBehavior, defaulting to FailingMarkerBehavior.""" def __init__(self, dispatch_table: dict[type[Marker], MarkerBehavior]) -> None: self._dispatch_table = dispatch_table def handle_marker(self, value: Marker) -> t.Any: behavior = self._dispatch_table.get(type(value), FAIL_ON_UNDEFINED) return behavior.handle_marker(value) ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_transform.py0000644000000000000000000000503515017704211024403 0ustar00rootroot"""Runtime projections to provide template/var-visible views of objects that are not natively allowed in Ansible's type system.""" from __future__ import annotations import dataclasses import typing as t from ansible.module_utils._internal import _traceback, _event_utils, _messages from ansible.parsing.vault import EncryptedString, VaultHelper from ansible.utils.display import Display from ._jinja_common import VaultExceptionMarker from .._errors import _captured, _error_factory from .. import _event_formatting display = Display() def plugin_info(value: _messages.PluginInfo) -> dict[str, str]: """Render PluginInfo as a dictionary.""" return dataclasses.asdict(value) def error_summary(value: _messages.ErrorSummary) -> str: """Render ErrorSummary as a formatted traceback for backward-compatibility with pre-2.19 TaskResult.exception.""" if _traceback._is_traceback_enabled(_traceback.TracebackEvent.ERROR): return _event_formatting.format_event_traceback(value.event) return '(traceback unavailable)' def warning_summary(value: _messages.WarningSummary) -> str: """Render WarningSummary as a simple message string for backward-compatibility with pre-2.19 TaskResult.warnings.""" return _event_utils.format_event_brief_message(value.event) def deprecation_summary(value: _messages.DeprecationSummary) -> dict[str, t.Any]: """Render DeprecationSummary as dict values for backward-compatibility with pre-2.19 TaskResult.deprecations.""" transformed = _event_utils.deprecation_as_dict(value) transformed.update(deprecator=value.deprecator) return transformed def encrypted_string(value: EncryptedString) -> str | VaultExceptionMarker: """Decrypt an encrypted string and return its value, or a VaultExceptionMarker if decryption fails.""" try: return value._decrypt() except Exception as ex: return VaultExceptionMarker( ciphertext=VaultHelper.get_ciphertext(value, with_tags=True), event=_error_factory.ControllerEventFactory.from_exception(ex, _traceback.is_traceback_enabled(_traceback.TracebackEvent.ERROR)), ) _type_transform_mapping: dict[type, t.Callable[[t.Any], t.Any]] = { _captured.CapturedErrorSummary: error_summary, _messages.PluginInfo: plugin_info, _messages.ErrorSummary: error_summary, _messages.WarningSummary: warning_summary, _messages.DeprecationSummary: deprecation_summary, EncryptedString: encrypted_string, } """This mapping is consulted by `Templar.template` to provide custom views of some objects.""" ansible_core-2.19.0b5/lib/ansible/_internal/_templating/_utils.py0000644000000000000000000000717715017704211023541 0ustar00rootrootfrom __future__ import annotations import dataclasses import typing as t from ansible.module_utils._internal import _ambient_context, _datatag if t.TYPE_CHECKING: from ._engine import TemplateEngine, TemplateOptions @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class LazyOptions: """Templating options that apply to lazy containers, which are inherited by descendent lazy containers.""" DEFAULT: t.ClassVar[t.Self] """A shared instance with the default options to minimize instance creation for arg defaults.""" SKIP_TEMPLATES: t.ClassVar[t.Self] """A shared instance with only `template=False` set to minimize instance creation for arg defaults.""" SKIP_TEMPLATES_AND_ACCESS: t.ClassVar[t.Self] """A shared instance with both `template=False` and `access=False` set to minimize instance creation for arg defaults.""" template: bool = True """Enable/disable templating.""" access: bool = True """Enable/disables access calls.""" unmask_type_names: frozenset[str] = frozenset() """Disables template transformations for the provided type names.""" LazyOptions.DEFAULT = LazyOptions() LazyOptions.SKIP_TEMPLATES = LazyOptions(template=False) LazyOptions.SKIP_TEMPLATES_AND_ACCESS = LazyOptions(template=False, access=False) class TemplateContext(_ambient_context.AmbientContextBase): def __init__( self, *, template_value: t.Any, templar: TemplateEngine, options: TemplateOptions, stop_on_template: bool = False, _render_jinja_const_template: bool = False, ): self._template_value = template_value self._templar = templar self._options = options self._stop_on_template = stop_on_template self._parent_ctx = TemplateContext.current(optional=True) self._render_jinja_const_template = _render_jinja_const_template @property def is_top_level(self) -> bool: return not self._parent_ctx @property def template_value(self) -> t.Any: return self._template_value @property def templar(self) -> TemplateEngine: return self._templar @property def options(self) -> TemplateOptions: return self._options @property def stop_on_template(self) -> bool: return self._stop_on_template class _OmitType: """ A placeholder singleton used to dynamically omit items from a dict/list/tuple/set when the value is `Omit`. The `Omit` singleton is accessible from all Ansible templating contexts via the Jinja global name `omit`. The `Omit` placeholder value will be visible to Jinja plugins during templating. Jinja plugins requiring omit behavior are responsible for handling encountered `Omit` values. `Omit` values remaining in template results will be automatically dropped during template finalization. When a finalized template renders to a scalar `Omit`, `AnsibleValueOmittedError` will be raised. Passing a value other than `Omit` for `value_for_omit` to the `template` call allows that value to be substituted instead of raising. """ __slots__ = () def __new__(cls): return Omit def __repr__(self): return "<>" Omit = object.__new__(_OmitType) _datatag._untaggable_types.add(_OmitType) # DTFIX5: review these type sets to ensure they're not overly permissive/dynamic IGNORE_SCALAR_VAR_TYPES = {value for value in _datatag._ANSIBLE_ALLOWED_SCALAR_VAR_TYPES if not issubclass(value, str)} PASS_THROUGH_SCALAR_VAR_TYPES = _datatag._ANSIBLE_ALLOWED_SCALAR_VAR_TYPES | { _OmitType, # allow pass through of omit for later handling after top-level finalize completes } ansible_core-2.19.0b5/lib/ansible/_internal/_testing.py0000644000000000000000000000147115017704211021542 0ustar00rootroot""" Testing utilities for use in integration tests, not unit tests or non-test code. Provides better error behavior than Python's `assert` statement. """ from __future__ import annotations import contextlib import typing as t class _Checker: @staticmethod def check(value: object, msg: str | None = 'Value is not truthy.') -> None: """Raise an `AssertionError` if the given `value` is not truthy.""" if not value: raise AssertionError(msg) @contextlib.contextmanager def hard_fail_context(msg: str) -> t.Generator[_Checker]: """Enter a context which converts all exceptions to `BaseException` and provides a `Checker` instance for making assertions.""" try: yield _Checker() except BaseException as ex: raise BaseException(f"Hard failure: {msg}") from ex ansible_core-2.19.0b5/lib/ansible/_internal/_wrapt.py0000644000000000000000000011211315017704211021216 0ustar00rootroot# Copyright (c) 2013-2023, Graham Dumpleton # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # copied from https://github.com/GrahamDumpleton/wrapt/blob/1.15.0/src/wrapt/wrappers.py # LOCAL PATCHES: # - disabled optional relative import of the _wrappers C extension; we shouldn't need it from __future__ import annotations # The following makes it easier for us to script updates of the bundled code _BUNDLED_METADATA = {"pypi_name": "wrapt", "version": "1.15.0"} import os import sys import functools import operator import weakref import inspect PY2 = sys.version_info[0] == 2 if PY2: string_types = basestring, else: string_types = str, def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" return meta("NewBase", bases, {}) class _ObjectProxyMethods(object): # We use properties to override the values of __module__ and # __doc__. If we add these in ObjectProxy, the derived class # __dict__ will still be setup to have string variants of these # attributes and the rules of descriptors means that they appear to # take precedence over the properties in the base class. To avoid # that, we copy the properties into the derived class type itself # via a meta class. In that way the properties will always take # precedence. @property def __module__(self): return self.__wrapped__.__module__ @__module__.setter def __module__(self, value): self.__wrapped__.__module__ = value @property def __doc__(self): return self.__wrapped__.__doc__ @__doc__.setter def __doc__(self, value): self.__wrapped__.__doc__ = value # We similar use a property for __dict__. We need __dict__ to be # explicit to ensure that vars() works as expected. @property def __dict__(self): return self.__wrapped__.__dict__ # Need to also propagate the special __weakref__ attribute for case # where decorating classes which will define this. If do not define # it and use a function like inspect.getmembers() on a decorator # class it will fail. This can't be in the derived classes. @property def __weakref__(self): return self.__wrapped__.__weakref__ class _ObjectProxyMetaType(type): def __new__(cls, name, bases, dictionary): # Copy our special properties into the class so that they # always take precedence over attributes of the same name added # during construction of a derived class. This is to save # duplicating the implementation for them in all derived classes. dictionary.update(vars(_ObjectProxyMethods)) return type.__new__(cls, name, bases, dictionary) class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): __slots__ = '__wrapped__' def __init__(self, wrapped): object.__setattr__(self, '__wrapped__', wrapped) # Python 3.2+ has the __qualname__ attribute, but it does not # allow it to be overridden using a property and it must instead # be an actual string object instead. try: object.__setattr__(self, '__qualname__', wrapped.__qualname__) except AttributeError: pass # Python 3.10 onwards also does not allow itself to be overridden # using a property and it must instead be set explicitly. try: object.__setattr__(self, '__annotations__', wrapped.__annotations__) except AttributeError: pass @property def __name__(self): return self.__wrapped__.__name__ @__name__.setter def __name__(self, value): self.__wrapped__.__name__ = value @property def __class__(self): return self.__wrapped__.__class__ @__class__.setter def __class__(self, value): self.__wrapped__.__class__ = value def __dir__(self): return dir(self.__wrapped__) def __str__(self): return str(self.__wrapped__) if not PY2: def __bytes__(self): return bytes(self.__wrapped__) def __repr__(self): return '<{} at 0x{:x} for {} at 0x{:x}>'.format( type(self).__name__, id(self), type(self.__wrapped__).__name__, id(self.__wrapped__)) def __reversed__(self): return reversed(self.__wrapped__) if not PY2: def __round__(self): return round(self.__wrapped__) if sys.hexversion >= 0x03070000: def __mro_entries__(self, bases): return (self.__wrapped__,) def __lt__(self, other): return self.__wrapped__ < other def __le__(self, other): return self.__wrapped__ <= other def __eq__(self, other): return self.__wrapped__ == other def __ne__(self, other): return self.__wrapped__ != other def __gt__(self, other): return self.__wrapped__ > other def __ge__(self, other): return self.__wrapped__ >= other def __hash__(self): return hash(self.__wrapped__) def __nonzero__(self): return bool(self.__wrapped__) def __bool__(self): return bool(self.__wrapped__) def __setattr__(self, name, value): if name.startswith('_self_'): object.__setattr__(self, name, value) elif name == '__wrapped__': object.__setattr__(self, name, value) try: object.__delattr__(self, '__qualname__') except AttributeError: pass try: object.__setattr__(self, '__qualname__', value.__qualname__) except AttributeError: pass try: object.__delattr__(self, '__annotations__') except AttributeError: pass try: object.__setattr__(self, '__annotations__', value.__annotations__) except AttributeError: pass elif name == '__qualname__': setattr(self.__wrapped__, name, value) object.__setattr__(self, name, value) elif name == '__annotations__': setattr(self.__wrapped__, name, value) object.__setattr__(self, name, value) elif hasattr(type(self), name): object.__setattr__(self, name, value) else: setattr(self.__wrapped__, name, value) def __getattr__(self, name): # If we are being to lookup '__wrapped__' then the # '__init__()' method cannot have been called. if name == '__wrapped__': raise ValueError('wrapper has not been initialised') return getattr(self.__wrapped__, name) def __delattr__(self, name): if name.startswith('_self_'): object.__delattr__(self, name) elif name == '__wrapped__': raise TypeError('__wrapped__ must be an object') elif name == '__qualname__': object.__delattr__(self, name) delattr(self.__wrapped__, name) elif hasattr(type(self), name): object.__delattr__(self, name) else: delattr(self.__wrapped__, name) def __add__(self, other): return self.__wrapped__ + other def __sub__(self, other): return self.__wrapped__ - other def __mul__(self, other): return self.__wrapped__ * other def __div__(self, other): return operator.div(self.__wrapped__, other) def __truediv__(self, other): return operator.truediv(self.__wrapped__, other) def __floordiv__(self, other): return self.__wrapped__ // other def __mod__(self, other): return self.__wrapped__ % other def __divmod__(self, other): return divmod(self.__wrapped__, other) def __pow__(self, other, *args): return pow(self.__wrapped__, other, *args) def __lshift__(self, other): return self.__wrapped__ << other def __rshift__(self, other): return self.__wrapped__ >> other def __and__(self, other): return self.__wrapped__ & other def __xor__(self, other): return self.__wrapped__ ^ other def __or__(self, other): return self.__wrapped__ | other def __radd__(self, other): return other + self.__wrapped__ def __rsub__(self, other): return other - self.__wrapped__ def __rmul__(self, other): return other * self.__wrapped__ def __rdiv__(self, other): return operator.div(other, self.__wrapped__) def __rtruediv__(self, other): return operator.truediv(other, self.__wrapped__) def __rfloordiv__(self, other): return other // self.__wrapped__ def __rmod__(self, other): return other % self.__wrapped__ def __rdivmod__(self, other): return divmod(other, self.__wrapped__) def __rpow__(self, other, *args): return pow(other, self.__wrapped__, *args) def __rlshift__(self, other): return other << self.__wrapped__ def __rrshift__(self, other): return other >> self.__wrapped__ def __rand__(self, other): return other & self.__wrapped__ def __rxor__(self, other): return other ^ self.__wrapped__ def __ror__(self, other): return other | self.__wrapped__ def __iadd__(self, other): self.__wrapped__ += other return self def __isub__(self, other): self.__wrapped__ -= other return self def __imul__(self, other): self.__wrapped__ *= other return self def __idiv__(self, other): self.__wrapped__ = operator.idiv(self.__wrapped__, other) return self def __itruediv__(self, other): self.__wrapped__ = operator.itruediv(self.__wrapped__, other) return self def __ifloordiv__(self, other): self.__wrapped__ //= other return self def __imod__(self, other): self.__wrapped__ %= other return self def __ipow__(self, other): self.__wrapped__ **= other return self def __ilshift__(self, other): self.__wrapped__ <<= other return self def __irshift__(self, other): self.__wrapped__ >>= other return self def __iand__(self, other): self.__wrapped__ &= other return self def __ixor__(self, other): self.__wrapped__ ^= other return self def __ior__(self, other): self.__wrapped__ |= other return self def __neg__(self): return -self.__wrapped__ def __pos__(self): return +self.__wrapped__ def __abs__(self): return abs(self.__wrapped__) def __invert__(self): return ~self.__wrapped__ def __int__(self): return int(self.__wrapped__) def __long__(self): return long(self.__wrapped__) def __float__(self): return float(self.__wrapped__) def __complex__(self): return complex(self.__wrapped__) def __oct__(self): return oct(self.__wrapped__) def __hex__(self): return hex(self.__wrapped__) def __index__(self): return operator.index(self.__wrapped__) def __len__(self): return len(self.__wrapped__) def __contains__(self, value): return value in self.__wrapped__ def __getitem__(self, key): return self.__wrapped__[key] def __setitem__(self, key, value): self.__wrapped__[key] = value def __delitem__(self, key): del self.__wrapped__[key] def __getslice__(self, i, j): return self.__wrapped__[i:j] def __setslice__(self, i, j, value): self.__wrapped__[i:j] = value def __delslice__(self, i, j): del self.__wrapped__[i:j] def __enter__(self): return self.__wrapped__.__enter__() def __exit__(self, *args, **kwargs): return self.__wrapped__.__exit__(*args, **kwargs) def __iter__(self): return iter(self.__wrapped__) def __copy__(self): raise NotImplementedError('object proxy must define __copy__()') def __deepcopy__(self, memo): raise NotImplementedError('object proxy must define __deepcopy__()') def __reduce__(self): raise NotImplementedError( 'object proxy must define __reduce_ex__()') def __reduce_ex__(self, protocol): raise NotImplementedError( 'object proxy must define __reduce_ex__()') class CallableObjectProxy(ObjectProxy): def __call__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) return self.__wrapped__(*args, **kwargs) class PartialCallableObjectProxy(ObjectProxy): def __init__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) if len(args) < 1: raise TypeError('partial type takes at least one argument') wrapped, args = args[0], args[1:] if not callable(wrapped): raise TypeError('the first argument must be callable') super(PartialCallableObjectProxy, self).__init__(wrapped) self._self_args = args self._self_kwargs = kwargs def __call__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) _args = self._self_args + args _kwargs = dict(self._self_kwargs) _kwargs.update(kwargs) return self.__wrapped__(*_args, **_kwargs) class _FunctionWrapperBase(ObjectProxy): __slots__ = ('_self_instance', '_self_wrapper', '_self_enabled', '_self_binding', '_self_parent') def __init__(self, wrapped, instance, wrapper, enabled=None, binding='function', parent=None): super(_FunctionWrapperBase, self).__init__(wrapped) object.__setattr__(self, '_self_instance', instance) object.__setattr__(self, '_self_wrapper', wrapper) object.__setattr__(self, '_self_enabled', enabled) object.__setattr__(self, '_self_binding', binding) object.__setattr__(self, '_self_parent', parent) def __get__(self, instance, owner): # This method is actually doing double duty for both unbound and # bound derived wrapper classes. It should possibly be broken up # and the distinct functionality moved into the derived classes. # Can't do that straight away due to some legacy code which is # relying on it being here in this base class. # # The distinguishing attribute which determines whether we are # being called in an unbound or bound wrapper is the parent # attribute. If binding has never occurred, then the parent will # be None. # # First therefore, is if we are called in an unbound wrapper. In # this case we perform the binding. # # We have one special case to worry about here. This is where we # are decorating a nested class. In this case the wrapped class # would not have a __get__() method to call. In that case we # simply return self. # # Note that we otherwise still do binding even if instance is # None and accessing an unbound instance method from a class. # This is because we need to be able to later detect that # specific case as we will need to extract the instance from the # first argument of those passed in. if self._self_parent is None: if not inspect.isclass(self.__wrapped__): descriptor = self.__wrapped__.__get__(instance, owner) return self.__bound_function_wrapper__(descriptor, instance, self._self_wrapper, self._self_enabled, self._self_binding, self) return self # Now we have the case of binding occurring a second time on what # was already a bound function. In this case we would usually # return ourselves again. This mirrors what Python does. # # The special case this time is where we were originally bound # with an instance of None and we were likely an instance # method. In that case we rebind against the original wrapped # function from the parent again. if self._self_instance is None and self._self_binding == 'function': descriptor = self._self_parent.__wrapped__.__get__( instance, owner) return self._self_parent.__bound_function_wrapper__( descriptor, instance, self._self_wrapper, self._self_enabled, self._self_binding, self._self_parent) return self def __call__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) # If enabled has been specified, then evaluate it at this point # and if the wrapper is not to be executed, then simply return # the bound function rather than a bound wrapper for the bound # function. When evaluating enabled, if it is callable we call # it, otherwise we evaluate it as a boolean. if self._self_enabled is not None: if callable(self._self_enabled): if not self._self_enabled(): return self.__wrapped__(*args, **kwargs) elif not self._self_enabled: return self.__wrapped__(*args, **kwargs) # This can occur where initial function wrapper was applied to # a function that was already bound to an instance. In that case # we want to extract the instance from the function and use it. if self._self_binding in ('function', 'classmethod'): if self._self_instance is None: instance = getattr(self.__wrapped__, '__self__', None) if instance is not None: return self._self_wrapper(self.__wrapped__, instance, args, kwargs) # This is generally invoked when the wrapped function is being # called as a normal function and is not bound to a class as an # instance method. This is also invoked in the case where the # wrapped function was a method, but this wrapper was in turn # wrapped using the staticmethod decorator. return self._self_wrapper(self.__wrapped__, self._self_instance, args, kwargs) def __set_name__(self, owner, name): # This is a special method use to supply information to # descriptors about what the name of variable in a class # definition is. Not wanting to add this to ObjectProxy as not # sure of broader implications of doing that. Thus restrict to # FunctionWrapper used by decorators. if hasattr(self.__wrapped__, "__set_name__"): self.__wrapped__.__set_name__(owner, name) def __instancecheck__(self, instance): # This is a special method used by isinstance() to make checks # instance of the `__wrapped__`. return isinstance(instance, self.__wrapped__) def __subclasscheck__(self, subclass): # This is a special method used by issubclass() to make checks # about inheritance of classes. We need to upwrap any object # proxy. Not wanting to add this to ObjectProxy as not sure of # broader implications of doing that. Thus restrict to # FunctionWrapper used by decorators. if hasattr(subclass, "__wrapped__"): return issubclass(subclass.__wrapped__, self.__wrapped__) else: return issubclass(subclass, self.__wrapped__) class BoundFunctionWrapper(_FunctionWrapperBase): def __call__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) # If enabled has been specified, then evaluate it at this point # and if the wrapper is not to be executed, then simply return # the bound function rather than a bound wrapper for the bound # function. When evaluating enabled, if it is callable we call # it, otherwise we evaluate it as a boolean. if self._self_enabled is not None: if callable(self._self_enabled): if not self._self_enabled(): return self.__wrapped__(*args, **kwargs) elif not self._self_enabled: return self.__wrapped__(*args, **kwargs) # We need to do things different depending on whether we are # likely wrapping an instance method vs a static method or class # method. if self._self_binding == 'function': if self._self_instance is None: # This situation can occur where someone is calling the # instancemethod via the class type and passing the instance # as the first argument. We need to shift the args before # making the call to the wrapper and effectively bind the # instance to the wrapped function using a partial so the # wrapper doesn't see anything as being different. if not args: raise TypeError('missing 1 required positional argument') instance, args = args[0], args[1:] wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) return self._self_wrapper(wrapped, instance, args, kwargs) return self._self_wrapper(self.__wrapped__, self._self_instance, args, kwargs) else: # As in this case we would be dealing with a classmethod or # staticmethod, then _self_instance will only tell us whether # when calling the classmethod or staticmethod they did it via an # instance of the class it is bound to and not the case where # done by the class type itself. We thus ignore _self_instance # and use the __self__ attribute of the bound function instead. # For a classmethod, this means instance will be the class type # and for a staticmethod it will be None. This is probably the # more useful thing we can pass through even though we loose # knowledge of whether they were called on the instance vs the # class type, as it reflects what they have available in the # decoratored function. instance = getattr(self.__wrapped__, '__self__', None) return self._self_wrapper(self.__wrapped__, instance, args, kwargs) class FunctionWrapper(_FunctionWrapperBase): __bound_function_wrapper__ = BoundFunctionWrapper def __init__(self, wrapped, wrapper, enabled=None): # What it is we are wrapping here could be anything. We need to # try and detect specific cases though. In particular, we need # to detect when we are given something that is a method of a # class. Further, we need to know when it is likely an instance # method, as opposed to a class or static method. This can # become problematic though as there isn't strictly a fool proof # method of knowing. # # The situations we could encounter when wrapping a method are: # # 1. The wrapper is being applied as part of a decorator which # is a part of the class definition. In this case what we are # given is the raw unbound function, classmethod or staticmethod # wrapper objects. # # The problem here is that we will not know we are being applied # in the context of the class being set up. This becomes # important later for the case of an instance method, because in # that case we just see it as a raw function and can't # distinguish it from wrapping a normal function outside of # a class context. # # 2. The wrapper is being applied when performing monkey # patching of the class type afterwards and the method to be # wrapped was retrieved direct from the __dict__ of the class # type. This is effectively the same as (1) above. # # 3. The wrapper is being applied when performing monkey # patching of the class type afterwards and the method to be # wrapped was retrieved from the class type. In this case # binding will have been performed where the instance against # which the method is bound will be None at that point. # # This case is a problem because we can no longer tell if the # method was a static method, plus if using Python3, we cannot # tell if it was an instance method as the concept of an # unnbound method no longer exists. # # 4. The wrapper is being applied when performing monkey # patching of an instance of a class. In this case binding will # have been perfomed where the instance was not None. # # This case is a problem because we can no longer tell if the # method was a static method. # # Overall, the best we can do is look at the original type of the # object which was wrapped prior to any binding being done and # see if it is an instance of classmethod or staticmethod. In # the case where other decorators are between us and them, if # they do not propagate the __class__ attribute so that the # isinstance() checks works, then likely this will do the wrong # thing where classmethod and staticmethod are used. # # Since it is likely to be very rare that anyone even puts # decorators around classmethod and staticmethod, likelihood of # that being an issue is very small, so we accept it and suggest # that those other decorators be fixed. It is also only an issue # if a decorator wants to actually do things with the arguments. # # As to not being able to identify static methods properly, we # just hope that that isn't something people are going to want # to wrap, or if they do suggest they do it the correct way by # ensuring that it is decorated in the class definition itself, # or patch it in the __dict__ of the class type. # # So to get the best outcome we can, whenever we aren't sure what # it is, we label it as a 'function'. If it was already bound and # that is rebound later, we assume that it will be an instance # method and try an cope with the possibility that the 'self' # argument it being passed as an explicit argument and shuffle # the arguments around to extract 'self' for use as the instance. if isinstance(wrapped, classmethod): binding = 'classmethod' elif isinstance(wrapped, staticmethod): binding = 'staticmethod' elif hasattr(wrapped, '__self__'): if inspect.isclass(wrapped.__self__): binding = 'classmethod' else: binding = 'function' else: binding = 'function' super(FunctionWrapper, self).__init__(wrapped, None, wrapper, enabled, binding) # disabled support for native extension; we likely don't need it # try: # if not os.environ.get('WRAPT_DISABLE_EXTENSIONS'): # from ._wrappers import (ObjectProxy, CallableObjectProxy, # PartialCallableObjectProxy, FunctionWrapper, # BoundFunctionWrapper, _FunctionWrapperBase) # except ImportError: # pass # Helper functions for applying wrappers to existing functions. def resolve_path(module, name): if isinstance(module, string_types): __import__(module) module = sys.modules[module] parent = module path = name.split('.') attribute = path[0] # We can't just always use getattr() because in doing # that on a class it will cause binding to occur which # will complicate things later and cause some things not # to work. For the case of a class we therefore access # the __dict__ directly. To cope though with the wrong # class being given to us, or a method being moved into # a base class, we need to walk the class hierarchy to # work out exactly which __dict__ the method was defined # in, as accessing it from __dict__ will fail if it was # not actually on the class given. Fallback to using # getattr() if we can't find it. If it truly doesn't # exist, then that will fail. def lookup_attribute(parent, attribute): if inspect.isclass(parent): for cls in inspect.getmro(parent): if attribute in vars(cls): return vars(cls)[attribute] else: return getattr(parent, attribute) else: return getattr(parent, attribute) original = lookup_attribute(parent, attribute) for attribute in path[1:]: parent = original original = lookup_attribute(parent, attribute) return (parent, attribute, original) def apply_patch(parent, attribute, replacement): setattr(parent, attribute, replacement) def wrap_object(module, name, factory, args=(), kwargs={}): (parent, attribute, original) = resolve_path(module, name) wrapper = factory(original, *args, **kwargs) apply_patch(parent, attribute, wrapper) return wrapper # Function for applying a proxy object to an attribute of a class # instance. The wrapper works by defining an attribute of the same name # on the class which is a descriptor and which intercepts access to the # instance attribute. Note that this cannot be used on attributes which # are themselves defined by a property object. class AttributeWrapper(object): def __init__(self, attribute, factory, args, kwargs): self.attribute = attribute self.factory = factory self.args = args self.kwargs = kwargs def __get__(self, instance, owner): value = instance.__dict__[self.attribute] return self.factory(value, *self.args, **self.kwargs) def __set__(self, instance, value): instance.__dict__[self.attribute] = value def __delete__(self, instance): del instance.__dict__[self.attribute] def wrap_object_attribute(module, name, factory, args=(), kwargs={}): path, attribute = name.rsplit('.', 1) parent = resolve_path(module, path)[2] wrapper = AttributeWrapper(attribute, factory, args, kwargs) apply_patch(parent, attribute, wrapper) return wrapper # Functions for creating a simple decorator using a FunctionWrapper, # plus short cut functions for applying wrappers to functions. These are # for use when doing monkey patching. For a more featured way of # creating decorators see the decorator decorator instead. def function_wrapper(wrapper): def _wrapper(wrapped, instance, args, kwargs): target_wrapped = args[0] if instance is None: target_wrapper = wrapper elif inspect.isclass(instance): target_wrapper = wrapper.__get__(None, instance) else: target_wrapper = wrapper.__get__(instance, type(instance)) return FunctionWrapper(target_wrapped, target_wrapper) return FunctionWrapper(wrapper, _wrapper) def wrap_function_wrapper(module, name, wrapper): return wrap_object(module, name, FunctionWrapper, (wrapper,)) def patch_function_wrapper(module, name): def _wrapper(wrapper): return wrap_object(module, name, FunctionWrapper, (wrapper,)) return _wrapper def transient_function_wrapper(module, name): def _decorator(wrapper): def _wrapper(wrapped, instance, args, kwargs): target_wrapped = args[0] if instance is None: target_wrapper = wrapper elif inspect.isclass(instance): target_wrapper = wrapper.__get__(None, instance) else: target_wrapper = wrapper.__get__(instance, type(instance)) def _execute(wrapped, instance, args, kwargs): (parent, attribute, original) = resolve_path(module, name) replacement = FunctionWrapper(original, target_wrapper) setattr(parent, attribute, replacement) try: return wrapped(*args, **kwargs) finally: setattr(parent, attribute, original) return FunctionWrapper(target_wrapped, _execute) return FunctionWrapper(wrapper, _wrapper) return _decorator # A weak function proxy. This will work on instance methods, class # methods, static methods and regular functions. Special treatment is # needed for the method types because the bound method is effectively a # transient object and applying a weak reference to one will immediately # result in it being destroyed and the weakref callback called. The weak # reference is therefore applied to the instance the method is bound to # and the original function. The function is then rebound at the point # of a call via the weak function proxy. def _weak_function_proxy_callback(ref, proxy, callback): if proxy._self_expired: return proxy._self_expired = True # This could raise an exception. We let it propagate back and let # the weakref.proxy() deal with it, at which point it generally # prints out a short error message direct to stderr and keeps going. if callback is not None: callback(proxy) class WeakFunctionProxy(ObjectProxy): __slots__ = ('_self_expired', '_self_instance') def __init__(self, wrapped, callback=None): # We need to determine if the wrapped function is actually a # bound method. In the case of a bound method, we need to keep a # reference to the original unbound function and the instance. # This is necessary because if we hold a reference to the bound # function, it will be the only reference and given it is a # temporary object, it will almost immediately expire and # the weakref callback triggered. So what is done is that we # hold a reference to the instance and unbound function and # when called bind the function to the instance once again and # then call it. Note that we avoid using a nested function for # the callback here so as not to cause any odd reference cycles. _callback = callback and functools.partial( _weak_function_proxy_callback, proxy=self, callback=callback) self._self_expired = False if isinstance(wrapped, _FunctionWrapperBase): self._self_instance = weakref.ref(wrapped._self_instance, _callback) if wrapped._self_parent is not None: super(WeakFunctionProxy, self).__init__( weakref.proxy(wrapped._self_parent, _callback)) else: super(WeakFunctionProxy, self).__init__( weakref.proxy(wrapped, _callback)) return try: self._self_instance = weakref.ref(wrapped.__self__, _callback) super(WeakFunctionProxy, self).__init__( weakref.proxy(wrapped.__func__, _callback)) except AttributeError: self._self_instance = None super(WeakFunctionProxy, self).__init__( weakref.proxy(wrapped, _callback)) def __call__(*args, **kwargs): def _unpack_self(self, *args): return self, args self, args = _unpack_self(*args) # We perform a boolean check here on the instance and wrapped # function as that will trigger the reference error prior to # calling if the reference had expired. instance = self._self_instance and self._self_instance() function = self.__wrapped__ and self.__wrapped__ # If the wrapped function was originally a bound function, for # which we retained a reference to the instance and the unbound # function we need to rebind the function and then call it. If # not just called the wrapped function. if instance is None: return self.__wrapped__(*args, **kwargs) return function.__get__(instance, type(instance))(*args, **kwargs)ansible_core-2.19.0b5/lib/ansible/_internal/_yaml/0000755000000000000000000000000015017704211020452 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_yaml/__init__.py0000644000000000000000000000000015017704211022551 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/_yaml/_constructor.py0000644000000000000000000002304615017704211023555 0ustar00rootrootfrom __future__ import annotations import abc import copy import typing as t from yaml import Node from yaml.constructor import SafeConstructor from yaml.resolver import BaseResolver from ansible import constants as C from ansible.module_utils.common.text.converters import to_text from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible._internal._datatag._tags import Origin, TrustedAsTemplate from ansible.parsing.vault import EncryptedString from ansible.utils.display import Display from ._errors import AnsibleConstructorError display = Display() _TRUSTED_AS_TEMPLATE: t.Final[TrustedAsTemplate] = TrustedAsTemplate() class _BaseConstructor(SafeConstructor, metaclass=abc.ABCMeta): """Base class for Ansible YAML constructors.""" @classmethod @abc.abstractmethod def _register_constructors(cls) -> None: """Method used to register constructors to derived types during class initialization.""" def __init_subclass__(cls, **kwargs) -> None: """Initialization for derived types.""" cls._register_constructors() class AnsibleInstrumentedConstructor(_BaseConstructor): """Ansible constructor which supports Ansible custom behavior such as `Origin` tagging, but no Ansible-specific YAML tags.""" name: t.Any # provided by the YAML parser, which retrieves it from the stream def __init__(self, origin: Origin, trusted_as_template: bool) -> None: if not origin.line_num: origin = origin.replace(line_num=1) self._origin = origin self._trusted_as_template = trusted_as_template self._duplicate_key_mode = C.config.get_config_value('DUPLICATE_YAML_DICT_KEY') super().__init__() @property def trusted_as_template(self) -> bool: return self._trusted_as_template def construct_yaml_map(self, node): data = self._node_position_info(node).tag({}) # always an ordered dictionary on py3.7+ yield data value = self.construct_mapping(node) data.update(value) def construct_mapping(self, node, deep=False): # Delegate to built-in implementation to construct the mapping. # This is done before checking for duplicates to leverage existing error checking on the input node. mapping = super().construct_mapping(node, deep) keys = set() # Now that the node is known to be a valid mapping, handle any duplicate keys. for key_node, _value_node in node.value: if (key := self.construct_object(key_node, deep=deep)) in keys: msg = f'Found duplicate mapping key {key!r}.' if self._duplicate_key_mode == 'error': raise AnsibleConstructorError(problem=msg, problem_mark=key_node.start_mark) if self._duplicate_key_mode == 'warn': display.warning(msg=msg, obj=key, help_text='Using last defined value only.') keys.add(key) return mapping def construct_yaml_int(self, node): value = super().construct_yaml_int(node) return self._node_position_info(node).tag(value) def construct_yaml_float(self, node): value = super().construct_yaml_float(node) return self._node_position_info(node).tag(value) def construct_yaml_timestamp(self, node): value = super().construct_yaml_timestamp(node) return self._node_position_info(node).tag(value) def construct_yaml_omap(self, node): origin = self._node_position_info(node) display.deprecated( msg='Use of the YAML `!!omap` tag is deprecated.', version='2.23', obj=origin, help_text='Use a standard mapping instead, as key order is always preserved.', ) items = list(super().construct_yaml_omap(node))[0] items = [origin.tag(item) for item in items] yield origin.tag(items) def construct_yaml_pairs(self, node): origin = self._node_position_info(node) display.deprecated( msg='Use of the YAML `!!pairs` tag is deprecated.', version='2.23', obj=origin, help_text='Use a standard mapping instead.', ) items = list(super().construct_yaml_pairs(node))[0] items = [origin.tag(item) for item in items] yield origin.tag(items) def construct_yaml_str(self, node): # Override the default string handling function # to always return unicode objects # DTFIX-FUTURE: is this to_text conversion still necessary under Py3? value = to_text(self.construct_scalar(node)) tags = [self._node_position_info(node)] if self.trusted_as_template: # NB: since we're not context aware, this will happily add trust to dictionary keys; this is actually necessary for # certain backward compat scenarios, though might be accomplished in other ways if we wanted to avoid trusting keys in # the general scenario tags.append(_TRUSTED_AS_TEMPLATE) return AnsibleTagHelper.tag(value, tags) def construct_yaml_binary(self, node): value = super().construct_yaml_binary(node) return AnsibleTagHelper.tag(value, self._node_position_info(node)) def construct_yaml_set(self, node): data = AnsibleTagHelper.tag(set(), self._node_position_info(node)) yield data value = self.construct_mapping(node) data.update(value) def construct_yaml_seq(self, node): data = self._node_position_info(node).tag([]) yield data data.extend(self.construct_sequence(node)) def _resolve_and_construct_object(self, node): # use a copied node to avoid mutating existing node and tripping the recursion check in construct_object copied_node = copy.copy(node) # repeat implicit resolution process to determine the proper tag for the value in the unsafe node copied_node.tag = t.cast(BaseResolver, self).resolve(type(node), node.value, (True, False)) # re-entrant call using the correct tag # non-deferred construction of hierarchical nodes so the result is a fully realized object, and so our stateful unsafe propagation behavior works return self.construct_object(copied_node, deep=True) def _node_position_info(self, node) -> Origin: # the line number where the previous token has ended (plus empty lines) # Add one so that the first line is line 1 rather than line 0 return self._origin.replace(line_num=node.start_mark.line + self._origin.line_num, col_num=node.start_mark.column + 1) @classmethod def _register_constructors(cls) -> None: constructors: dict[str, t.Callable] = { 'tag:yaml.org,2002:binary': cls.construct_yaml_binary, 'tag:yaml.org,2002:float': cls.construct_yaml_float, 'tag:yaml.org,2002:int': cls.construct_yaml_int, 'tag:yaml.org,2002:map': cls.construct_yaml_map, 'tag:yaml.org,2002:omap': cls.construct_yaml_omap, 'tag:yaml.org,2002:pairs': cls.construct_yaml_pairs, 'tag:yaml.org,2002:python/dict': cls.construct_yaml_map, 'tag:yaml.org,2002:python/unicode': cls.construct_yaml_str, 'tag:yaml.org,2002:seq': cls.construct_yaml_seq, 'tag:yaml.org,2002:set': cls.construct_yaml_set, 'tag:yaml.org,2002:str': cls.construct_yaml_str, 'tag:yaml.org,2002:timestamp': cls.construct_yaml_timestamp, } for tag, constructor in constructors.items(): cls.add_constructor(tag, constructor) class AnsibleConstructor(AnsibleInstrumentedConstructor): """Ansible constructor which supports Ansible custom behavior such as `Origin` tagging, as well as Ansible-specific YAML tags.""" def __init__(self, origin: Origin, trusted_as_template: bool) -> None: self._unsafe_depth = 0 # volatile state var used during recursive construction of a value tagged unsafe super().__init__(origin=origin, trusted_as_template=trusted_as_template) @property def trusted_as_template(self) -> bool: return self._trusted_as_template and not self._unsafe_depth def construct_yaml_unsafe(self, node): self._unsafe_depth += 1 try: return self._resolve_and_construct_object(node) finally: self._unsafe_depth -= 1 def construct_yaml_vault(self, node: Node) -> EncryptedString: ciphertext = self._resolve_and_construct_object(node) if not isinstance(ciphertext, str): raise AnsibleConstructorError(problem=f"the {node.tag!r} tag requires a string value", problem_mark=node.start_mark) encrypted_string = AnsibleTagHelper.tag_copy(ciphertext, EncryptedString(ciphertext=AnsibleTagHelper.untag(ciphertext))) return encrypted_string def construct_yaml_vault_encrypted(self, node: Node) -> EncryptedString: origin = self._node_position_info(node) display.deprecated( msg='Use of the YAML `!vault-encrypted` tag is deprecated.', version='2.23', obj=origin, help_text='Use the `!vault` tag instead.', ) return self.construct_yaml_vault(node) @classmethod def _register_constructors(cls) -> None: super()._register_constructors() constructors: dict[str, t.Callable] = { '!unsafe': cls.construct_yaml_unsafe, '!vault': cls.construct_yaml_vault, '!vault-encrypted': cls.construct_yaml_vault_encrypted, } for tag, constructor in constructors.items(): cls.add_constructor(tag, constructor) ansible_core-2.19.0b5/lib/ansible/_internal/_yaml/_dumper.py0000644000000000000000000000471715017704211022470 0ustar00rootrootfrom __future__ import annotations import abc import collections.abc as c import typing as t from yaml.representer import SafeRepresenter from ansible.module_utils._internal._datatag import AnsibleTaggedObject, Tripwire, AnsibleTagHelper from ansible.parsing.vault import VaultHelper from ansible.module_utils.common.yaml import HAS_LIBYAML if HAS_LIBYAML: from yaml.cyaml import CSafeDumper as SafeDumper else: from yaml import SafeDumper # type: ignore[assignment] class _BaseDumper(SafeDumper, metaclass=abc.ABCMeta): """Base class for Ansible YAML dumpers.""" @classmethod @abc.abstractmethod def _register_representers(cls) -> None: """Method used to register representers to derived types during class initialization.""" def __init_subclass__(cls, **kwargs) -> None: """Initialization for derived types.""" cls._register_representers() class AnsibleDumper(_BaseDumper): """A simple stub class that allows us to add representers for our custom types.""" # DTFIX0: need a better way to handle serialization controls during YAML dumping def __init__(self, *args, dump_vault_tags: bool | None = None, **kwargs): super().__init__(*args, **kwargs) self._dump_vault_tags = dump_vault_tags @classmethod def _register_representers(cls) -> None: cls.add_multi_representer(AnsibleTaggedObject, cls.represent_ansible_tagged_object) cls.add_multi_representer(Tripwire, cls.represent_tripwire) cls.add_multi_representer(c.Mapping, SafeRepresenter.represent_dict) cls.add_multi_representer(c.Sequence, SafeRepresenter.represent_list) def represent_ansible_tagged_object(self, data): if self._dump_vault_tags is not False and (ciphertext := VaultHelper.get_ciphertext(data, with_tags=False)): # deprecated: description='enable the deprecation warning below' core_version='2.23' # if self._dump_vault_tags is None: # Display().deprecated( # msg="Implicit YAML dumping of vaulted value ciphertext is deprecated. Set `dump_vault_tags` to explicitly specify the desired behavior", # version="2.27", # ) return self.represent_scalar('!vault', ciphertext, style='|') return self.represent_data(AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings def represent_tripwire(self, data: Tripwire) -> t.NoReturn: data.trip() ansible_core-2.19.0b5/lib/ansible/_internal/_yaml/_errors.py0000644000000000000000000001716515017704211022511 0ustar00rootrootfrom __future__ import annotations import re import typing as t from yaml import MarkedYAMLError from yaml.constructor import ConstructorError from ansible._internal._errors import _error_utils from ansible.errors import AnsibleParserError from ansible._internal._datatag._tags import Origin class AnsibleConstructorError(ConstructorError): """Ansible-specific ConstructorError used to bypass exception analysis during wrapping in AnsibleYAMLParserError.""" class AnsibleYAMLParserError(AnsibleParserError): """YAML-specific parsing failure wrapping an exception raised by the YAML parser.""" _default_message = 'YAML parsing failed.' _include_cause_message = False # hide the underlying cause message, it's included by `handle_exception` as needed _formatted_source_context_value: str | None = None @property def _formatted_source_context(self) -> str | None: return self._formatted_source_context_value @classmethod def handle_exception(cls, exception: Exception, origin: Origin) -> t.NoReturn: if isinstance(exception, MarkedYAMLError): origin = origin.replace(line_num=exception.problem_mark.line + 1, col_num=exception.problem_mark.column + 1) source_context = _error_utils.SourceContext.from_origin(origin) target_line = source_context.target_line or '' # for these cases, we don't need to distinguish between None and empty string message: str | None = None help_text = None # FIXME: Do all this by walking the parsed YAML doc stream. Using regexes is a dead-end; YAML's just too flexible to not have a # raft of false-positives and corner cases. If we directly consume either the YAML parse stream or override the YAML composer, we can # better catch these things without worrying about duplicating YAML's scalar parsing logic around quoting/escaping. At first, we can # replace the regex logic below with tiny special-purpose parse consumers to catch specific issues, but ideally, we could do a lot of this # inline with the actual doc parse, since our rules are a lot more strict than YAML's (eg, no support for non-scalar keys), and a lot of the # problem cases where that comes into play are around expression quoting and Jinja {{ syntax looking like weird YAML values we don't support. # Some common examples, where -> is "what YAML actually sees": # foo: {{ bar }} -> {"foo": {{"bar": None}: None}} - a mapping with a mapping as its key (legal YAML, but not legal Python/Ansible) # # - copy: src=foo.txt # kv syntax (kv could be on following line(s), too- implicit multi-line block scalar) # dest: bar.txt # orphaned mapping, since the value of `copy` is the scalar "src=foo.txt" # # - msg == "Error: 'dude' was not found" # unquoted scalar has a : in it -> {'msg == "Error"': 'dude'} [ was not found" ] is garbage orphan scalar # noinspection PyUnboundLocalVariable if not isinstance(exception, MarkedYAMLError): pass # unexpected exception, don't use special analysis of exception elif isinstance(exception, AnsibleConstructorError): pass # raised internally by ansible code, don't use special analysis of exception # Check for tabs. # There may be cases where there is a valid tab in a line that has other errors. # That's OK, users should "fix" their tab usage anyway -- at which point later error handling logic will hopefully find the real issue. elif (tab_idx := target_line.find('\t')) >= 0: source_context = _error_utils.SourceContext.from_origin(origin.replace(col_num=tab_idx + 1)) message = "Tabs are usually invalid in YAML." # Check for unquoted templates. elif match := re.search(r'^\s*(?:-\s+)*(?:[\w\s]+:\s+)?(?P\{\{.*}})', target_line): source_context = _error_utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1)) message = 'This may be an issue with missing quotes around a template block.' # FIXME: Use the captured value to show the actual fix required. help_text = """ For example: raw: {{ some_var }} Should be: raw: "{{ some_var }}" """ # Check for common unquoted colon mistakes. elif ( # ignore lines starting with only whitespace and a colon not target_line.lstrip().startswith(':') # find the value after list/dict preamble and (value_match := re.search(r'^\s*(?:-\s+)*(?:[\w\s\[\]{}]+:\s+)?(?P.*)$', target_line)) # ignore properly quoted values and (target_fragment := _replace_quoted_value(value_match.group('value'))) # look for an unquoted colon in the value and (colon_match := re.search(r':($| )', target_fragment)) ): source_context = _error_utils.SourceContext.from_origin(origin.replace(col_num=value_match.start('value') + colon_match.start() + 1)) message = 'Colons in unquoted values must be followed by a non-space character.' # FIXME: Use the captured value to show the actual fix required. help_text = """ For example: raw: echo 'name: ansible' Should be: raw: "echo 'name: ansible'" """ # Check for common quoting mistakes. elif match := re.search(r'^\s*(?:-\s+)*(?:[\w\s]+:\s+)?(?P[\"\'].*?\s*)$', target_line): suspected_value = match.group('value') first, last = suspected_value[0], suspected_value[-1] if first != last: # "foo" in bar source_context = _error_utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1)) message = 'Values starting with a quote must end with the same quote.' # FIXME: Use the captured value to show the actual fix required, and use that same logic to improve the origin further. help_text = """ For example: raw: "foo" in bar Should be: raw: '"foo" in bar' """ elif first == last and target_line.count(first) > 2: # "foo" and "bar" source_context = _error_utils.SourceContext.from_origin(origin.replace(col_num=match.start('value') + 1)) message = 'Values starting with a quote must end with the same quote, and not contain that quote.' # FIXME: Use the captured value to show the actual fix required, and use that same logic to improve the origin further. help_text = """ For example: raw: "foo" in "bar" Should be: raw: '"foo" in "bar"' """ if not message: if isinstance(exception, MarkedYAMLError): # marked YAML error, pull out the useful messages while omitting the noise message = ' '.join(filter(None, (exception.context, exception.problem, exception.note))) message = message.strip() message = f'{message[0].upper()}{message[1:]}' if not message.endswith('.'): message += '.' else: # unexpected error, use the exception message (normally hidden by overriding include_cause_message) message = str(exception) message = re.sub(r'\s+', ' ', message).strip() error = cls(message, obj=source_context.origin) error._formatted_source_context_value = str(source_context) error._help_text = help_text raise error from exception def _replace_quoted_value(value: str, replacement='.') -> str: return re.sub(r"""^\s*('[^']*'|"[^"]*")\s*$""", lambda match: replacement * len(match.group(0)), value) ansible_core-2.19.0b5/lib/ansible/_internal/_yaml/_loader.py0000644000000000000000000000460415017704211022435 0ustar00rootrootfrom __future__ import annotations import io as _io from yaml.resolver import Resolver from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible.module_utils.common.yaml import HAS_LIBYAML from ansible._internal._datatag import _tags from ._constructor import AnsibleConstructor, AnsibleInstrumentedConstructor if HAS_LIBYAML: from yaml.cyaml import CParser class _YamlParser(CParser): def __init__(self, stream: str | bytes | _io.IOBase) -> None: if isinstance(stream, (str, bytes)): stream = AnsibleTagHelper.untag(stream) # PyYAML + libyaml barfs on str/bytes subclasses CParser.__init__(self, stream) self.name = getattr(stream, 'name', None) # provide feature parity with the Python implementation (yaml.reader.Reader provides name) else: from yaml.composer import Composer from yaml.reader import Reader from yaml.scanner import Scanner from yaml.parser import Parser class _YamlParser(Reader, Scanner, Parser, Composer): # type: ignore[no-redef] def __init__(self, stream: str | bytes | _io.IOBase) -> None: Reader.__init__(self, stream) Scanner.__init__(self) Parser.__init__(self) Composer.__init__(self) class AnsibleInstrumentedLoader(_YamlParser, AnsibleInstrumentedConstructor, Resolver): """Ansible YAML loader which supports Ansible custom behavior such as `Origin` tagging, but no Ansible-specific YAML tags.""" def __init__(self, stream: str | bytes | _io.IOBase) -> None: _YamlParser.__init__(self, stream) AnsibleInstrumentedConstructor.__init__( self, origin=_tags.Origin.get_or_create_tag(stream, self.name), trusted_as_template=_tags.TrustedAsTemplate.is_tagged_on(stream), ) Resolver.__init__(self) class AnsibleLoader(_YamlParser, AnsibleConstructor, Resolver): """Ansible loader which supports Ansible custom behavior such as `Origin` tagging, as well as Ansible-specific YAML tags.""" def __init__(self, stream: str | bytes | _io.IOBase) -> None: _YamlParser.__init__(self, stream) AnsibleConstructor.__init__( self, origin=_tags.Origin.get_or_create_tag(stream, self.name), trusted_as_template=_tags.TrustedAsTemplate.is_tagged_on(stream), ) Resolver.__init__(self) ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/0000755000000000000000000000000015017704211023364 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/0000755000000000000000000000000015017704211025001 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/0000755000000000000000000000000015017704211027520 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/README.md0000644000000000000000000000114415017704211030777 0ustar00rootroot"Protomatter - an unstable substance which every ethical scientist in the galaxy has denounced as dangerously unpredictable." "But it was the only way to solve certain problems..." This Ansible Collection is embedded within ansible-core. It contains plugins useful for ansible-core's own integration tests. They have been made available, completely unsupported, in case they prove useful for debugging and troubleshooting purposes. > CAUTION: This collection is not supported, and may be changed or removed in any version without prior notice. Use of these plugins outside ansible-core is highly discouraged. ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/0000755000000000000000000000000015017704211031201 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/0000755000000000000000000000000015017704211032456 5ustar00rootroot././@PaxHeader0000000000000000000000000000016600000000000010220 xustar00118 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/0000644000000000000000000000267515017704211032472 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible.module_utils.common.validation import _check_type_str_no_conversion, _check_type_list_strict from ansible.plugins.action import ActionBase from ansible._internal._templating._engine import TemplateEngine from ansible._internal._templating._marker_behaviors import ReplacingMarkerBehavior class ActionModule(ActionBase): TRANSFERS_FILES = False _requires_connection = False @classmethod def finalize_task_arg(cls, name: str, value: t.Any, templar: TemplateEngine, context: t.Any) -> t.Any: if name == 'expression': return value return super().finalize_task_arg(name, value, templar, context) def run(self, tmp=None, task_vars=None): # accepts a list of literal expressions (no templating), evaluates with no failure on undefined, returns all results _vr, args = self.validate_argument_spec( argument_spec=dict( expression=dict(type=_check_type_list_strict, elements=_check_type_str_no_conversion, required=True), ), ) with ReplacingMarkerBehavior.warning_context() as replacing_behavior: templar = self._templar._engine.extend(marker_behavior=replacing_behavior) return dict( _ansible_verbose_always=True, expression_result=[templar.evaluate_expression(expression) for expression in args['expression']], ) ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000755000000000000000000000000015017704211032466 5ustar00rootroot././@PaxHeader0000000000000000000000000000017400000000000010217 xustar00124 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000103115017704211032463 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible._internal._datatag._tags import TrustedAsTemplate def apply_trust(value: object) -> object: """ Filter that returns a tagged copy of the input string with TrustedAsTemplate. Containers and other non-string values are returned unmodified. """ return TrustedAsTemplate().tag(value) if isinstance(value, str) else value class FilterModule: @staticmethod def filters() -> dict[str, t.Callable]: return dict(apply_trust=apply_trust) ././@PaxHeader0000000000000000000000000000017400000000000010217 xustar00124 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000072215017704211032471 0ustar00rootrootfrom __future__ import annotations import dataclasses import typing as t def dump_object(value: t.Any) -> object: """Internal filter to convert objects not supported by JSON to types which are.""" if dataclasses.is_dataclass(value): return dataclasses.asdict(value) # type: ignore[arg-type] return value class FilterModule(object): @staticmethod def filters() -> dict[str, t.Callable]: return dict(dump_object=dump_object) ././@PaxHeader0000000000000000000000000000017100000000000010214 xustar00121 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000073015017704211032470 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible._internal._templating._engine import _finalize_template_result, FinalizeMode def finalize(value: t.Any) -> t.Any: """Perform an explicit top-level template finalize operation on the supplied value.""" return _finalize_template_result(value, mode=FinalizeMode.TOP_LEVEL) class FilterModule: @staticmethod def filters() -> dict[str, t.Callable]: return dict(finalize=finalize) ././@PaxHeader0000000000000000000000000000016700000000000010221 xustar00119 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000065515017704211032476 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible._internal._datatag._tags import Origin def origin(value: object) -> str | None: """Return the origin of the value, if any, otherwise `None`.""" origin_tag = Origin.get_tag(value) return str(origin_tag) if origin_tag else None class FilterModule: @staticmethod def filters() -> dict[str, t.Callable]: return dict(origin=origin) ././@PaxHeader0000000000000000000000000000020400000000000010211 xustar00132 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000105015017704211032464 0ustar00rootrootfrom __future__ import annotations import ast from ansible.errors import AnsibleTypeError def python_literal_eval(value: object, ignore_errors=False) -> object: try: if isinstance(value, str): return ast.literal_eval(value) raise AnsibleTypeError("The `value` to eval must be a string.", obj=value) except Exception: if ignore_errors: return value raise class FilterModule(object): @staticmethod def filters(): return dict(python_literal_eval=python_literal_eval) ././@PaxHeader0000000000000000000000000000020500000000000010212 xustar00133 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000264515017704211032477 0ustar00rootrootDOCUMENTATION: name: python_literal_eval version_added: "2.19" short_description: evaluate a Python literal expression string description: - Evaluates the input string as a Python literal expression, returning the resulting data structure. - Previous versions of Ansible applied this behavior to all template results in non-native Jinja mode. - This filter provides a way to emulate the previous behavior. notes: - Directly calls Python's C(ast.literal_eval). positional: _input options: _input: description: Python literal string expression. type: str required: true ignore_errors: description: Whether to silently ignore all errors resulting from the literal_eval operation. If true, the input is silently returned unmodified when an error occurs. type: bool default: false EXAMPLES: | - name: evaluate an expression comprised only of Python literals assert: that: (another_var | ansible._protomatter.python_literal_eval)[1] == 2 # in 2.19 and later, the explicit python_literal_eval emulates the old templating behavior vars: another_var: "{{ some_var }}" # in 2.18 and earlier, indirection through templating caused implicit literal_eval, converting the value to a list some_var: "[1, 2]" # a value that looks like a Python list literal embedded in a string RETURN: _value: description: Resulting data structure. type: raw ././@PaxHeader0000000000000000000000000000017200000000000010215 xustar00122 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000071615017704211032474 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible.module_utils._internal._datatag import AnsibleTagHelper def tag_names(value: object) -> list[str]: """Return a list of tag type names (if any) present on the given object.""" return sorted(tag_type.__name__ for tag_type in AnsibleTagHelper.tag_types(value)) class FilterModule: @staticmethod def filters() -> dict[str, t.Callable]: return dict(tag_names=tag_names) ././@PaxHeader0000000000000000000000000000017200000000000010215 xustar00122 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000071115017704211032467 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible.template import accept_args_markers @accept_args_markers def true_type(obj: object) -> str: """Internal filter to show the true type name of the given object, not just the base type name like the `debug` filter.""" return obj.__class__.__name__ class FilterModule(object): @staticmethod def filters() -> dict[str, t.Callable]: return dict(true_type=true_type) ././@PaxHeader0000000000000000000000000000016700000000000010221 xustar00119 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/0000644000000000000000000000332115017704211032467 0ustar00rootrootfrom __future__ import annotations import copy import dataclasses import typing as t from ansible._internal._templating._jinja_common import validate_arg_type from ansible._internal._templating._lazy_containers import _AnsibleLazyTemplateMixin from ansible._internal._templating._transform import _type_transform_mapping from ansible.errors import AnsibleError def unmask(value: object, type_names: str | list[str]) -> object: """ Internal filter to suppress automatic type transformation in Jinja (e.g., WarningSummary, DeprecationSummary, ErrorSummary). Lazy collection caching is in play - the first attempt to access a value in a given lazy container must be with unmasking in place, or the transformed value will already be cached. """ validate_arg_type("type_names", type_names, (str, list)) if isinstance(type_names, str): check_type_names = [type_names] else: check_type_names = type_names valid_type_names = {key.__name__ for key in _type_transform_mapping} invalid_type_names = [type_name for type_name in check_type_names if type_name not in valid_type_names] if invalid_type_names: raise AnsibleError(f'Unknown type name(s): {", ".join(invalid_type_names)}', obj=type_names) result: object if isinstance(value, _AnsibleLazyTemplateMixin): result = copy.copy(value) result._lazy_options = dataclasses.replace( result._lazy_options, unmask_type_names=result._lazy_options.unmask_type_names | frozenset(check_type_names), ) else: result = value return result class FilterModule(object): @staticmethod def filters() -> dict[str, t.Callable]: return dict(unmask=unmask) ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/0000755000000000000000000000000015017704211032512 5ustar00rootroot././@PaxHeader0000000000000000000000000000016700000000000010221 xustar00119 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/0000644000000000000000000000146215017704211032517 0ustar00rootrootfrom __future__ import annotations from ansible.plugins.lookup import LookupBase class LookupModule(LookupBase): """Specialized config lookup that applies data transformations on values that config cannot.""" def run(self, terms, variables=None, **kwargs): if not terms or not (config_name := terms[0]): raise ValueError("config name is required") match config_name: case 'DISPLAY_TRACEBACK': # since config can't expand this yet, we need the post-processed version from ansible.module_utils._internal._traceback import traceback_for return traceback_for() # DTFIX-FUTURE: plumb through normal config fallback case _: raise ValueError(f"Unknown config name {config_name!r}.") ././@PaxHeader0000000000000000000000000000017000000000000010213 xustar00120 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/0000644000000000000000000000003615017704211032513 0ustar00rootrootDOCUMENTATION: name: config ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/0000755000000000000000000000000015017704211032160 5ustar00rootroot././@PaxHeader0000000000000000000000000000016500000000000010217 xustar00117 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/ta0000644000000000000000000000047715017704211032517 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible.module_utils._internal import _datatag def tagged(value: t.Any) -> bool: return bool(_datatag.AnsibleTagHelper.tag_types(value)) class TestModule: @staticmethod def tests() -> dict[str, t.Callable]: return dict(tagged=tagged) ././@PaxHeader0000000000000000000000000000016600000000000010220 xustar00118 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/ta0000644000000000000000000000073315017704211032512 0ustar00rootrootDOCUMENTATION: name: tagged author: Ansible Core version_added: "2.19" short_description: does the value have a data tag description: - Check if the provided value has a data tag. options: _input: description: A value. type: raw EXAMPLES: | is_data_tagged: "{{ my_variable is ansible._protomatter.tagged }}" RETURN: _value: description: Returns C(True) if the value has one or more data tags, otherwise C(False). type: boolean ././@PaxHeader0000000000000000000000000000017200000000000010215 xustar00122 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/ta0000644000000000000000000000070515017704211032511 0ustar00rootrootfrom __future__ import annotations import typing as t from ansible.module_utils._internal import _datatag def tagged_with(value: t.Any, tag_name: str) -> bool: if tag_type := _datatag._known_tag_type_map.get(tag_name): return tag_type.is_tagged_on(value) raise ValueError(f"Unknown tag name {tag_name!r}.") class TestModule: @staticmethod def tests() -> dict[str, t.Callable]: return dict(tagged_with=tagged_with) ././@PaxHeader0000000000000000000000000000017300000000000010216 xustar00123 path=ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml ansible_core-2.19.0b5/lib/ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/ta0000644000000000000000000000101015017704211032477 0ustar00rootrootDOCUMENTATION: name: tagged_with author: Ansible Core version_added: "2.19" short_description: does the value have the specified data tag description: - Check if the provided value has the specified data tag. options: _input: description: A value. type: raw EXAMPLES: | is_data_tagged: "{{ my_variable is ansible._protomatter.tagged_with('Origin') }}" RETURN: _value: description: Returns C(True) if the value has the specified data tag, otherwise C(False). type: boolean ansible_core-2.19.0b5/lib/ansible/_vendor/0000755000000000000000000000000015017704211017032 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/_vendor/__init__.py0000644000000000000000000000376115017704211021152 0ustar00rootroot# (c) 2020 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import os import pkgutil import sys import warnings # This package exists to host vendored top-level Python packages for downstream packaging. Any Python packages # installed beneath this one will be masked from the Ansible loader, and available from the front of sys.path. # It is expected that the vendored packages will be loaded very early, so a warning will be fired on import of # the top-level ansible package if any packages beneath this are already loaded at that point. # # Python packages may be installed here during downstream packaging using something like: # pip install --upgrade -t (path to this dir) cryptography pyyaml packaging jinja2 # mask vendored content below this package from being accessed as an ansible subpackage __path__ = [] def _ensure_vendored_path_entry(): """ Ensure that any downstream-bundled content beneath this package is available at the top of sys.path """ # patch our vendored dir onto sys.path vendored_path_entry = os.path.dirname(__file__) vendored_module_names = set(m[1] for m in pkgutil.iter_modules([vendored_path_entry], '')) # m[1] == m.name if vendored_module_names: # patch us early to load vendored deps transparently if vendored_path_entry in sys.path: # handle reload case by removing the existing entry, wherever it might be sys.path.remove(vendored_path_entry) sys.path.insert(0, vendored_path_entry) already_loaded_vendored_modules = set(sys.modules.keys()).intersection(vendored_module_names) if already_loaded_vendored_modules: warnings.warn('One or more Python packages bundled by this ansible-core distribution were already ' 'loaded ({0}). This may result in undefined behavior.'.format(', '.join(sorted(already_loaded_vendored_modules)))) _ensure_vendored_path_entry() ansible_core-2.19.0b5/lib/ansible/cli/0000755000000000000000000000000015017704211016145 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/cli/__init__.py0000644000000000000000000006643215017704211020271 0ustar00rootroot# Copyright: (c) 2012-2014, Michael DeHaan # Copyright: (c) 2016, Toshio Kuratomi # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import locale import os import sys # We overload the ``ansible`` adhoc command to provide the functionality for # ``SSH_ASKPASS``. This code is here, and not in ``adhoc.py`` to bypass # unnecessary code. The program provided to ``SSH_ASKPASS`` can only be invoked # as a singular command, ``python -m`` doesn't work for that use case, and we # aren't adding a new entrypoint at this time. Assume that if we are executing # and there is only a single item in argv plus the executable, and the env var # is set we are in ``SSH_ASKPASS`` mode if 1 <= len(sys.argv) <= 2 and os.path.basename(sys.argv[0]) == "ansible" and os.getenv('_ANSIBLE_SSH_ASKPASS_SHM'): from ansible.cli import _ssh_askpass _ssh_askpass.main() # Used for determining if the system is running a new enough python version # and should only restrict on our documented minimum versions if sys.version_info < (3, 11): raise SystemExit( 'ERROR: Ansible requires Python 3.11 or newer on the controller. ' 'Current version: %s' % ''.join(sys.version.splitlines()) ) def check_blocking_io(): """Check stdin/stdout/stderr to make sure they are using blocking IO.""" handles = [] for handle in (sys.stdin, sys.stdout, sys.stderr): # noinspection PyBroadException try: fd = handle.fileno() except Exception: continue # not a real file handle, such as during the import sanity test if not os.get_blocking(fd): handles.append(getattr(handle, 'name', None) or '#%s' % fd) if handles: raise SystemExit('ERROR: Ansible requires blocking IO on stdin/stdout/stderr. ' 'Non-blocking file handles detected: %s' % ', '.join(_io for _io in handles)) check_blocking_io() def initialize_locale(): """Set the locale to the users default setting and ensure the locale and filesystem encoding are UTF-8. """ try: locale.setlocale(locale.LC_ALL, '') dummy, encoding = locale.getlocale() except (locale.Error, ValueError) as e: raise SystemExit( 'ERROR: Ansible could not initialize the preferred locale: %s' % e ) if not encoding or encoding.lower() not in ('utf-8', 'utf8'): raise SystemExit('ERROR: Ansible requires the locale encoding to be UTF-8; Detected %s.' % encoding) fs_enc = sys.getfilesystemencoding() if fs_enc.lower() != 'utf-8': raise SystemExit('ERROR: Ansible requires the filesystem encoding to be UTF-8; Detected %s.' % fs_enc) initialize_locale() import errno import getpass import subprocess import traceback from abc import ABC, abstractmethod from pathlib import Path from ansible import _internal # do not remove or defer; ensures controller-specific state is set early _internal.setup() from ansible.errors import AnsibleError, ExitCode try: from ansible import constants as C from ansible.utils.display import Display display = Display() except Exception as ex: if isinstance(ex, AnsibleError): ex_msg = ' '.join((ex.message, ex._help_text or '')).strip() else: ex_msg = str(ex) print(f'ERROR: {ex_msg}\n\n{"".join(traceback.format_exception(ex))}', file=sys.stderr) sys.exit(5) from ansible import context from ansible.utils import display as _display from ansible.cli.arguments import option_helpers as opt_help from ansible.inventory.manager import InventoryManager from ansible.module_utils.six import string_types from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.file import is_executable from ansible.parsing.dataloader import DataLoader from ansible.parsing.vault import PromptVaultSecret, get_file_vault_secret, VaultSecretsContext from ansible.plugins.loader import add_all_plugin_dirs, init_plugin_loader from ansible.release import __version__ from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path from ansible.utils.path import unfrackpath from ansible.vars.manager import VariableManager from ansible.module_utils._internal import _deprecator from ansible._internal._ssh import _agent_launch try: import argcomplete HAS_ARGCOMPLETE = True except ImportError: HAS_ARGCOMPLETE = False class CLI(ABC): """ code behind bin/ansible* programs """ PAGER = C.config.get_config_value('PAGER') # -F (quit-if-one-screen) -R (allow raw ansi control chars) # -S (chop long lines) -X (disable termcap init and de-init) LESS_OPTS = 'FRSX' SKIP_INVENTORY_DEFAULTS = False USES_CONNECTION = False def __init__(self, args, callback=None): """ Base init method for all command line programs """ if not args: raise ValueError('A non-empty list for args is required') self.args = args self.parser = None self.callback = callback self.show_devel_warning() def show_devel_warning(self) -> None: if C.DEVEL_WARNING and __version__.endswith('dev0'): display.warning( 'You are running the development version of Ansible. You should only run Ansible from "devel" if ' 'you are modifying the Ansible engine, or trying out features under development. This is a rapidly ' 'changing source of code and can become unstable at any point.' ) @abstractmethod def run(self): """Run the ansible command Subclasses must implement this method. It does the actual work of running an Ansible command. """ self.parse() # Initialize plugin loader after parse, so that the init code can utilize parsed arguments cli_collections_path = context.CLIARGS.get('collections_path') or [] if not is_sequence(cli_collections_path): # In some contexts ``collections_path`` is singular cli_collections_path = [cli_collections_path] init_plugin_loader(cli_collections_path) display.vv(to_text(opt_help.version(self.parser.prog))) if C.CONFIG_FILE: display.v(u"Using %s as config file" % to_text(C.CONFIG_FILE)) else: display.v(u"No config file found; using defaults") _display._report_config_warnings(_deprecator.ANSIBLE_CORE_DEPRECATOR) @staticmethod def split_vault_id(vault_id): # return (before_@, after_@) # if no @, return whole string as after_ if '@' not in vault_id: return (None, vault_id) parts = vault_id.split('@', 1) ret = tuple(parts) return ret @staticmethod def build_vault_ids(vault_ids, vault_password_files=None, ask_vault_pass=None, auto_prompt=True): vault_password_files = vault_password_files or [] vault_ids = vault_ids or [] # convert vault_password_files into vault_ids slugs for password_file in vault_password_files: id_slug = u'%s@%s' % (C.DEFAULT_VAULT_IDENTITY, password_file) # note this makes --vault-id higher precedence than --vault-password-file # if we want to intertwingle them in order probably need a cli callback to populate vault_ids # used by --vault-id and --vault-password-file vault_ids.append(id_slug) # if an action needs an encrypt password (create_new_password=True) and we dont # have other secrets setup, then automatically add a password prompt as well. # prompts cant/shouldnt work without a tty, so dont add prompt secrets if ask_vault_pass or (not vault_ids and auto_prompt): id_slug = u'%s@%s' % (C.DEFAULT_VAULT_IDENTITY, u'prompt_ask_vault_pass') vault_ids.append(id_slug) return vault_ids @staticmethod def setup_vault_secrets(loader, vault_ids, vault_password_files=None, ask_vault_pass=None, create_new_password=False, auto_prompt=True, initialize_context=True): # list of tuples vault_secrets = [] # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id) # we need to show different prompts. This is for compat with older Towers that expect a # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format. prompt_formats = {} # If there are configured default vault identities, they are considered 'first' # so we prepend them to vault_ids (from cli) here vault_password_files = vault_password_files or [] if C.DEFAULT_VAULT_PASSWORD_FILE: vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE) if create_new_password: prompt_formats['prompt'] = ['New vault password (%(vault_id)s): ', 'Confirm new vault password (%(vault_id)s): '] # 2.3 format prompts for --ask-vault-pass prompt_formats['prompt_ask_vault_pass'] = ['New Vault password: ', 'Confirm New Vault password: '] else: prompt_formats['prompt'] = ['Vault password (%(vault_id)s): '] # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$' prompt_formats['prompt_ask_vault_pass'] = ['Vault password: '] vault_ids = CLI.build_vault_ids(vault_ids, vault_password_files, ask_vault_pass, auto_prompt=auto_prompt) last_exception = found_vault_secret = None for vault_id_slug in vault_ids: vault_id_name, vault_id_value = CLI.split_vault_id(vault_id_slug) if vault_id_value in ['prompt', 'prompt_ask_vault_pass']: # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little # confusing since it will use the old format without the vault id in the prompt built_vault_id = vault_id_name or C.DEFAULT_VAULT_IDENTITY # choose the prompt based on --vault-id=prompt or --ask-vault-pass. --ask-vault-pass # always gets the old format for Tower compatibility. # ie, we used --ask-vault-pass, so we need to use the old vault password prompt # format since Tower needs to match on that format. prompted_vault_secret = PromptVaultSecret(prompt_formats=prompt_formats[vault_id_value], vault_id=built_vault_id) # a empty or invalid password from the prompt will warn and continue to the next # without erroring globally try: prompted_vault_secret.load() except AnsibleError as exc: display.warning('Error in vault password prompt (%s): %s' % (vault_id_name, exc)) raise found_vault_secret = True vault_secrets.append((built_vault_id, prompted_vault_secret)) # update loader with new secrets incrementally, so we can load a vault password # that is encrypted with a vault secret provided earlier loader.set_vault_secrets(vault_secrets) continue # assuming anything else is a password file display.vvvvv('Reading vault password file: %s' % vault_id_value) # read vault_pass from a file try: file_vault_secret = get_file_vault_secret(filename=vault_id_value, vault_id=vault_id_name, loader=loader) except AnsibleError as exc: display.warning('Error getting vault password file (%s): %s' % (vault_id_name, to_text(exc))) last_exception = exc continue try: file_vault_secret.load() except AnsibleError as exc: display.warning('Error in vault password file loading (%s): %s' % (vault_id_name, to_text(exc))) last_exception = exc continue found_vault_secret = True if vault_id_name: vault_secrets.append((vault_id_name, file_vault_secret)) else: vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, file_vault_secret)) # update loader with as-yet-known vault secrets loader.set_vault_secrets(vault_secrets) # An invalid or missing password file will error globally # if no valid vault secret was found. if last_exception and not found_vault_secret: raise last_exception if initialize_context: VaultSecretsContext.initialize(VaultSecretsContext(vault_secrets)) return vault_secrets @staticmethod def _get_secret(prompt: str) -> str: return getpass.getpass(prompt=prompt) @staticmethod def ask_passwords(): """ prompt for connection and become passwords if needed """ op = context.CLIARGS sshpass = None becomepass = None become_prompt_method = "BECOME" if C.AGNOSTIC_BECOME_PROMPT else op['become_method'].upper() try: become_prompt = "%s password: " % become_prompt_method if op['ask_pass']: sshpass = CLI._get_secret("SSH password: ") become_prompt = "%s password[defaults to SSH password]: " % become_prompt_method elif op['connection_password_file']: sshpass = CLI.get_password_from_file(op['connection_password_file']) if op['become_ask_pass']: becomepass = CLI._get_secret(become_prompt) if op['ask_pass'] and becomepass == '': becomepass = sshpass elif op['become_password_file']: becomepass = CLI.get_password_from_file(op['become_password_file']) except EOFError: pass return sshpass, becomepass def validate_conflicts(self, op, runas_opts=False, fork_opts=False): """ check for conflicting options """ if fork_opts: if op.forks < 1: self.parser.error("The number of processes (--forks) must be >= 1") return op @abstractmethod def init_parser(self, usage="", desc=None, epilog=None): """ Create an options parser for most ansible scripts Subclasses need to implement this method. They will usually call the base class's init_parser to create a basic version and then add their own options on top of that. An implementation will look something like this:: def init_parser(self): super(MyCLI, self).init_parser(usage="My Ansible CLI", inventory_opts=True) ansible.arguments.option_helpers.add_runas_options(self.parser) self.parser.add_option('--my-option', dest='my_option', action='store') """ self.parser = opt_help.create_base_parser(self.name, usage=usage, desc=desc, epilog=epilog) @abstractmethod def post_process_args(self, options): """Process the command line args Subclasses need to implement this method. This method validates and transforms the command line arguments. It can be used to check whether conflicting values were given, whether filenames exist, etc. An implementation will look something like this:: def post_process_args(self, options): options = super(MyCLI, self).post_process_args(options) if options.addition and options.subtraction: raise AnsibleOptionsError('Only one of --addition and --subtraction can be specified') if isinstance(options.listofhosts, string_types): options.listofhosts = string_types.split(',') return options """ # process tags if hasattr(options, 'tags') and not options.tags: # optparse defaults does not do what's expected # More specifically, we want `--tags` to be additive. So we cannot # simply change C.TAGS_RUN's default to ["all"] because then passing # --tags foo would cause us to have ['all', 'foo'] options.tags = ['all'] if hasattr(options, 'tags') and options.tags: tags = set() for tag_set in options.tags: for tag in tag_set.split(u','): tags.add(tag.strip()) options.tags = list(tags) # process skip_tags if hasattr(options, 'skip_tags') and options.skip_tags: skip_tags = set() for tag_set in options.skip_tags: for tag in tag_set.split(u','): skip_tags.add(tag.strip()) options.skip_tags = list(skip_tags) # Make sure path argument doesn't have a backslash if hasattr(options, 'action') and options.action in ['install', 'download'] and hasattr(options, 'args'): options.args = [path.rstrip("/") for path in options.args] # process inventory options except for CLIs that require their own processing if hasattr(options, 'inventory') and not self.SKIP_INVENTORY_DEFAULTS: if options.inventory: # should always be list if isinstance(options.inventory, string_types): options.inventory = [options.inventory] # Ensure full paths when needed options.inventory = [unfrackpath(opt, follow=False) if ',' not in opt else opt for opt in options.inventory] else: options.inventory = C.DEFAULT_HOST_LIST return options def parse(self): """Parse the command line args This method parses the command line arguments. It uses the parser stored in the self.parser attribute and saves the args and options in context.CLIARGS. Subclasses need to implement two helper methods, init_parser() and post_process_args() which are called from this function before and after parsing the arguments. """ self.init_parser() if HAS_ARGCOMPLETE: argcomplete.autocomplete(self.parser) try: options = self.parser.parse_args(self.args[1:]) except SystemExit as ex: if ex.code != 0: self.parser.exit(status=2, message=" \n%s" % self.parser.format_help()) raise options = self.post_process_args(options) context._init_global_context(options) @staticmethod def version_info(gitinfo=False): """ return full ansible version info """ if gitinfo: # expensive call, user with care ansible_version_string = opt_help.version() else: ansible_version_string = __version__ ansible_version = ansible_version_string.split()[0] ansible_versions = ansible_version.split('.') for counter in range(len(ansible_versions)): if ansible_versions[counter] == "": ansible_versions[counter] = 0 try: ansible_versions[counter] = int(ansible_versions[counter]) except Exception: pass if len(ansible_versions) < 3: for counter in range(len(ansible_versions), 3): ansible_versions.append(0) return {'string': ansible_version_string.strip(), 'full': ansible_version, 'major': ansible_versions[0], 'minor': ansible_versions[1], 'revision': ansible_versions[2]} @staticmethod def pager(text): """ find reasonable way to display text """ # this is a much simpler form of what is in pydoc.py if not sys.stdout.isatty(): display.display(text, screen_only=True) elif CLI.PAGER: if sys.platform == 'win32': display.display(text, screen_only=True) else: CLI.pager_pipe(text) else: p = subprocess.Popen('less --version', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() if p.returncode == 0: CLI.pager_pipe(text, 'less') else: display.display(text, screen_only=True) @staticmethod def pager_pipe(text): """ pipe text through a pager """ if 'less' in CLI.PAGER: os.environ['LESS'] = CLI.LESS_OPTS try: cmd = subprocess.Popen(CLI.PAGER, shell=True, stdin=subprocess.PIPE, stdout=sys.stdout) cmd.communicate(input=to_bytes(text)) except IOError: pass except KeyboardInterrupt: pass def _play_prereqs(self): # TODO: evaluate moving all of the code that touches ``AnsibleCollectionConfig`` # into ``init_plugin_loader`` so that we can specifically remove # ``AnsibleCollectionConfig.playbook_paths`` to make it immutable after instantiation options = context.CLIARGS # all needs loader loader = DataLoader() basedir = options.get('basedir', False) if basedir: loader.set_basedir(basedir) add_all_plugin_dirs(basedir) AnsibleCollectionConfig.playbook_paths = basedir default_collection = _get_collection_name_from_path(basedir) if default_collection: display.warning(u'running with default collection {0}'.format(default_collection)) AnsibleCollectionConfig.default_collection = default_collection vault_ids = list(options['vault_ids']) default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST vault_ids = default_vault_ids + vault_ids vault_secrets = CLI.setup_vault_secrets(loader, vault_ids=vault_ids, vault_password_files=list(options['vault_password_files']), ask_vault_pass=options['ask_vault_pass'], auto_prompt=False) loader.set_vault_secrets(vault_secrets) if self.USES_CONNECTION: _agent_launch.launch_ssh_agent() # create the inventory, and filter it based on the subset specified (if any) inventory = InventoryManager(loader=loader, sources=options['inventory'], cache=(not options.get('flush_cache'))) # create the variable manager, which will be shared throughout # the code, ensuring a consistent view of global variables variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False)) # flush fact cache if requested if options['flush_cache']: CLI._flush_cache(inventory, variable_manager) return loader, inventory, variable_manager @staticmethod def _flush_cache(inventory, variable_manager): variable_manager.clear_facts('localhost') for host in inventory.list_hosts(): hostname = host.get_name() variable_manager.clear_facts(hostname) @staticmethod def get_host_list(inventory, subset, pattern='all'): no_hosts = False if len(inventory.list_hosts()) == 0: # Empty inventory if C.LOCALHOST_WARNING and pattern not in C.LOCALHOST: display.warning("provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'") no_hosts = True inventory.subset(subset) hosts = inventory.list_hosts(pattern) if not hosts and no_hosts is False: raise AnsibleError("Specified inventory, host pattern and/or --limit leaves us with no hosts to target.") return hosts @staticmethod def get_password_from_file(pwd_file: str) -> str: b_pwd_file = to_bytes(pwd_file) if b_pwd_file == b'-': # ensure its read as bytes secret = sys.stdin.buffer.read() elif not os.path.exists(b_pwd_file): raise AnsibleError("The password file %s was not found" % pwd_file) elif is_executable(b_pwd_file): display.vvvv(u'The password file %s is a script.' % to_text(pwd_file)) cmd = [b_pwd_file] try: p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: raise AnsibleError("Problem occurred when trying to run the password script %s (%s)." " If this is not a script, remove the executable bit from the file." % (pwd_file, e)) stdout, stderr = p.communicate() if p.returncode != 0: raise AnsibleError("The password script %s returned an error (rc=%s): %s" % (pwd_file, p.returncode, to_text(stderr))) secret = stdout else: try: with open(b_pwd_file, "rb") as password_file: secret = password_file.read().strip() except (OSError, IOError) as e: raise AnsibleError("Could not read password file %s: %s" % (pwd_file, e)) secret = secret.strip(b'\r\n') if not secret: raise AnsibleError('Empty password was provided from file (%s)' % pwd_file) return to_text(secret) @classmethod def cli_executor(cls, args=None): if args is None: args = sys.argv try: display.debug("starting run") ansible_dir = Path(C.ANSIBLE_HOME).expanduser() try: ansible_dir.mkdir(mode=0o700) except OSError as exc: if exc.errno != errno.EEXIST: display.warning( "Failed to create the directory '%s': %s" % (ansible_dir, to_text(exc, errors='surrogate_or_replace')) ) else: display.debug("Created the '%s' directory" % ansible_dir) cli = cls(args) exit_code = cli.run() except AnsibleError as ex: display.error(ex) exit_code = ex._exit_code except KeyboardInterrupt: display.error("User interrupted execution") exit_code = ExitCode.KEYBOARD_INTERRUPT except Exception as ex: try: raise AnsibleError("Unexpected Exception, this is probably a bug.") from ex except AnsibleError as ex2: # DTFIX-FUTURE: clean this up so we're not hacking the internals- re-wrap in an AnsibleCLIUnhandledError that always shows TB, or? from ansible.module_utils._internal import _traceback _traceback._is_traceback_enabled = lambda *_args, **_kwargs: True display.error(ex2) exit_code = ExitCode.UNKNOWN_ERROR sys.exit(exit_code) ansible_core-2.19.0b5/lib/ansible/cli/_ssh_askpass.py0000644000000000000000000000252515017704211021204 0ustar00rootroot# Copyright: Contributors to the Ansible project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import json import os import re import sys import typing as t from multiprocessing.shared_memory import SharedMemory HOST_KEY_RE = re.compile( r'(The authenticity of host |differs from the key for the IP address)', ) def main() -> t.Never: try: if HOST_KEY_RE.search(sys.argv[1]): sys.stdout.buffer.write(b'no') sys.stdout.flush() sys.exit(0) except IndexError: pass kwargs: dict[str, bool] = {} if sys.version_info[:2] >= (3, 13): # deprecated: description='unneeded due to track argument for SharedMemory' python_version='3.12' kwargs['track'] = False try: shm = SharedMemory(name=os.environ['_ANSIBLE_SSH_ASKPASS_SHM'], **kwargs) except FileNotFoundError: # We must be running after the ansible fork is shutting down sys.exit(1) cfg = json.loads(shm.buf.tobytes().rstrip(b'\x00')) try: if cfg['prompt'] not in sys.argv[1]: sys.exit(1) except IndexError: sys.exit(1) sys.stdout.buffer.write(cfg['password'].encode('utf-8')) sys.stdout.flush() shm.buf[:] = b'\x00' * shm.size shm.close() sys.exit(0) ansible_core-2.19.0b5/lib/ansible/cli/adhoc.py0000755000000000000000000002030715017704211017602 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2012, Michael DeHaan # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations import json # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError from ansible.executor.task_queue_manager import TaskQueueManager from ansible.module_utils.common.text.converters import to_text from ansible.parsing.splitter import parse_kv from ansible.playbook import Playbook from ansible.playbook.play import Play from ansible._internal._datatag._tags import Origin from ansible.utils.display import Display from ansible._internal._json._profiles import _legacy display = Display() class AdHocCLI(CLI): """ is an extra-simple tool/framework/API for doing 'remote things'. this command allows you to define and run a single task 'playbook' against a set of hosts """ name = 'ansible' USES_CONNECTION = True def init_parser(self): """ create an options parser for bin/ansible """ super(AdHocCLI, self).init_parser(usage='%prog [options]', desc="Define and run a single task 'playbook' against a set of hosts", epilog="Some actions do not make sense in Ad-Hoc (include, meta, etc)") opt_help.add_runas_options(self.parser) opt_help.add_inventory_options(self.parser) opt_help.add_async_options(self.parser) opt_help.add_output_options(self.parser) opt_help.add_connect_options(self.parser) opt_help.add_check_options(self.parser) opt_help.add_runtask_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_fork_options(self.parser) opt_help.add_module_options(self.parser) opt_help.add_basedir_options(self.parser) opt_help.add_tasknoplay_options(self.parser) # options unique to ansible ad-hoc self.parser.add_argument('-a', '--args', dest='module_args', help="The action's options in space separated k=v format: -a 'opt1=val1 opt2=val2' " "or a json string: -a '{\"opt1\": \"val1\", \"opt2\": \"val2\"}'", default=C.DEFAULT_MODULE_ARGS) self.parser.add_argument('-m', '--module-name', dest='module_name', help="Name of the action to execute (default=%s)" % C.DEFAULT_MODULE_NAME, default=C.DEFAULT_MODULE_NAME) self.parser.add_argument('args', metavar='pattern', help='host pattern') def post_process_args(self, options): """Post process and validate options for bin/ansible """ options = super(AdHocCLI, self).post_process_args(options) display.verbosity = options.verbosity self.validate_conflicts(options, runas_opts=True, fork_opts=True) return options def _play_ds(self, pattern, async_val, poll): check_raw = context.CLIARGS['module_name'] in C.MODULE_REQUIRE_ARGS module_args_raw = context.CLIARGS['module_args'] module_args = None if module_args_raw and module_args_raw.startswith('{') and module_args_raw.endswith('}'): try: module_args = json.loads(module_args_raw, cls=_legacy.Decoder) except AnsibleParserError: pass if not module_args: module_args = parse_kv(module_args_raw, check_raw=check_raw) mytask = {'action': {'module': context.CLIARGS['module_name'], 'args': module_args}, 'timeout': context.CLIARGS['task_timeout']} mytask = Origin(description=f'').tag(mytask) # avoid adding to tasks that don't support it, unless set, then give user an error if context.CLIARGS['module_name'] not in C._ACTION_ALL_INCLUDE_ROLE_TASKS and any(frozenset((async_val, poll))): mytask['async_val'] = async_val mytask['poll'] = poll return dict( name="Ansible Ad-Hoc", hosts=pattern, gather_facts='no', tasks=[mytask]) def run(self): """ create and execute the single task playbook """ super(AdHocCLI, self).run() # only thing left should be host pattern pattern = to_text(context.CLIARGS['args'], errors='surrogate_or_strict') # handle password prompts sshpass = None becomepass = None (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} # get basic objects loader, inventory, variable_manager = self._play_prereqs() # get list of hosts to execute against try: hosts = self.get_host_list(inventory, context.CLIARGS['subset'], pattern) except AnsibleError: if context.CLIARGS['subset']: raise else: hosts = [] display.warning("No hosts matched, nothing to do") # just listing hosts? if context.CLIARGS['listhosts']: display.display(' hosts (%d):' % len(hosts)) for host in hosts: display.display(' %s' % host) return 0 # verify we have arguments if we know we need em if context.CLIARGS['module_name'] in C.MODULE_REQUIRE_ARGS and not context.CLIARGS['module_args']: err = "No argument passed to %s module" % context.CLIARGS['module_name'] if pattern.endswith(".yml"): err = err + ' (did you mean to run ansible-playbook?)' raise AnsibleOptionsError(err) # Avoid modules that don't work with ad-hoc if context.CLIARGS['module_name'] in C._ACTION_IMPORT_PLAYBOOK: raise AnsibleOptionsError("'%s' is not a valid action for ad-hoc commands" % context.CLIARGS['module_name']) # construct playbook objects to wrap task play_ds = self._play_ds(pattern, context.CLIARGS['seconds'], context.CLIARGS['poll_interval']) play = Play().load(play_ds, variable_manager=variable_manager, loader=loader) # used in start callback playbook = Playbook(loader) playbook._entries.append(play) playbook._file_name = '__adhoc_playbook__' if self.callback: cb = self.callback elif context.CLIARGS['one_line']: cb = 'oneline' # Respect custom 'stdout_callback' only with enabled 'bin_ansible_callbacks' elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default': cb = C.DEFAULT_STDOUT_CALLBACK else: cb = 'minimal' run_tree = False if context.CLIARGS['tree']: C.CALLBACKS_ENABLED.append('tree') C.TREE_DIR = context.CLIARGS['tree'] run_tree = True # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=run_tree, forks=context.CLIARGS['forks'], ) self._tqm.load_callbacks() self._tqm.send_callback('v2_playbook_on_start', playbook) result = self._tqm.run(play) self._tqm.send_callback('v2_playbook_on_stats', self._tqm._stats) finally: if self._tqm: self._tqm.cleanup() if loader: loader.cleanup_all_tmp_files() return result def main(args=None): AdHocCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/arguments/0000755000000000000000000000000015017704211020152 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/cli/arguments/__init__.py0000644000000000000000000000025015017704211022260 0ustar00rootroot# Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations ansible_core-2.19.0b5/lib/ansible/cli/arguments/option_helpers.py0000644000000000000000000005760715017704211023575 0ustar00rootroot# Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import copy import dataclasses import inspect import operator import argparse import os import os.path import sys import time import typing as t import yaml import ansible from ansible import constants as C from ansible._internal import _templating from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.yaml import HAS_LIBYAML, yaml_load from ansible.release import __version__ from ansible.utils.path import unfrackpath from ansible._internal._datatag._tags import TrustedAsTemplate, Origin # # Special purpose OptionParsers # class SortingHelpFormatter(argparse.HelpFormatter): def add_arguments(self, actions): actions = sorted(actions, key=operator.attrgetter('option_strings')) super(SortingHelpFormatter, self).add_arguments(actions) @dataclasses.dataclass(frozen=True, kw_only=True) class DeprecatedArgument: version: str """The Ansible version that will remove the deprecated argument.""" option: str | None = None """The specific option string that is deprecated; None applies to all options for this argument.""" def is_deprecated(self, option: str) -> bool: """Return True if the given option is deprecated, otherwise False.""" return self.option is None or option == self.option def check(self, option: str) -> None: """Display a deprecation warning if the given option is deprecated.""" if not self.is_deprecated(option): return from ansible.utils.display import Display Display().deprecated( # pylint: disable=ansible-invalid-deprecated-version msg=f'The {option!r} argument is deprecated.', version=self.version, ) class ArgumentParser(argparse.ArgumentParser): def __init__(self, *args, **kwargs) -> None: self.__actions: dict[str | None, type[argparse.Action]] = {} super().__init__(*args, **kwargs) def register(self, registry_name, value, object): """Track registration of actions so that they can be resolved later by name, without depending on the internals of ArgumentParser.""" if registry_name == 'action': self.__actions[value] = object super().register(registry_name, value, object) def _patch_argument(self, args: tuple[str, ...], kwargs: dict[str, t.Any]) -> None: """ Patch `kwargs` for an `add_argument` call using the given `args` and `kwargs`. This is used to apply tags to entire categories of CLI arguments. """ name = args[0] action = kwargs.get('action') resolved_action = self.__actions.get(action, action) # get the action by name, or use as-is (assume it's a subclass of argparse.Action) action_signature = inspect.signature(resolved_action.__init__) if action_signature.parameters.get('type'): arg_type = kwargs.get('type', str) if not callable(arg_type): raise ValueError(f'Argument {name!r} requires a callable for the {"type"!r} parameter, not {arg_type!r}.') wrapped_arg_type = _tagged_type_factory(name, arg_type) kwargs.update(type=wrapped_arg_type) def _patch_parser(self, parser): """Patch and return the given parser to intercept the `add_argument` method for further patching.""" parser_add_argument = parser.add_argument def add_argument(*ag_args, **ag_kwargs): self._patch_argument(ag_args, ag_kwargs) parser_add_argument(*ag_args, **ag_kwargs) parser.add_argument = add_argument return parser def add_subparsers(self, *args, **kwargs): sub = super().add_subparsers(*args, **kwargs) sub_add_parser = sub.add_parser def add_parser(*sub_args, **sub_kwargs): return self._patch_parser(sub_add_parser(*sub_args, **sub_kwargs)) sub.add_parser = add_parser return sub def add_argument_group(self, *args, **kwargs): return self._patch_parser(super().add_argument_group(*args, **kwargs)) def add_mutually_exclusive_group(self, *args, **kwargs): return self._patch_parser(super().add_mutually_exclusive_group(*args, **kwargs)) def add_argument(self, *args, **kwargs) -> argparse.Action: action = kwargs.get('action') help = kwargs.get('help') if help and action in {'append', 'append_const', 'count', 'extend', PrependListAction}: help = f'{help.rstrip(".")}. This argument may be specified multiple times.' kwargs['help'] = help self._patch_argument(args, kwargs) deprecated: DeprecatedArgument | None if deprecated := kwargs.pop('deprecated', None): action_type = self.__actions.get(action, action) class DeprecatedAction(action_type): # type: ignore[misc, valid-type] """A wrapper around an action which handles deprecation warnings.""" def __call__(self, parser, namespace, values, option_string=None) -> t.Any: deprecated.check(option_string) return super().__call__(parser, namespace, values, option_string) kwargs['action'] = DeprecatedAction return super().add_argument(*args, **kwargs) class AnsibleVersion(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): ansible_version = to_native(version(getattr(parser, 'prog'))) print(ansible_version) parser.exit() class UnrecognizedArgument(argparse.Action): def __init__(self, option_strings, dest, const=True, default=None, required=False, help=None, metavar=None, nargs=0): super(UnrecognizedArgument, self).__init__(option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, required=required, help=help) def __call__(self, parser, namespace, values, option_string=None): parser.error('unrecognized arguments: %s' % option_string) class PrependListAction(argparse.Action): """A near clone of ``argparse._AppendAction``, but designed to prepend list values instead of appending. """ def __init__(self, option_strings, dest, nargs=None, const=None, default=None, type=None, choices=None, required=False, help=None, metavar=None): if nargs == 0: raise ValueError('nargs for append actions must be > 0; if arg ' 'strings are not supplying the value to append, ' 'the append const action may be more appropriate') if const is not None and nargs != argparse.OPTIONAL: raise ValueError('nargs must be %r to supply const' % argparse.OPTIONAL) super(PrependListAction, self).__init__( option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, type=type, choices=choices, required=required, help=help, metavar=metavar ) def __call__(self, parser, namespace, values, option_string=None): items = copy.copy(ensure_value(namespace, self.dest, [])) items[0:0] = values setattr(namespace, self.dest, items) def ensure_value(namespace, name, value): if getattr(namespace, name, None) is None: setattr(namespace, name, value) return getattr(namespace, name) # # Callbacks to validate and normalize Options # def unfrack_path(pathsep=False, follow=True): """Turn an Option's data into a single path in Ansible locations""" def inner(value): if pathsep: return [unfrackpath(x, follow=follow) for x in value.split(os.pathsep) if x] if value == '-': return value return unfrackpath(value, follow=follow) return inner def maybe_unfrack_path(beacon): def inner(value): if value.startswith(beacon): return beacon + unfrackpath(value[1:]) return value return inner def _git_repo_info(repo_path): """ returns a string containing git branch, commit id and commit date """ result = None if os.path.exists(repo_path): # Check if the .git is a file. If it is a file, it means that we are in a submodule structure. if os.path.isfile(repo_path): try: with open(repo_path) as f: gitdir = yaml_load(f).get('gitdir') # There is a possibility the .git file to have an absolute path. if os.path.isabs(gitdir): repo_path = gitdir else: repo_path = os.path.join(repo_path[:-4], gitdir) except (IOError, AttributeError): return '' with open(os.path.join(repo_path, "HEAD")) as f: line = f.readline().rstrip("\n") if line.startswith("ref:"): branch_path = os.path.join(repo_path, line[5:]) else: branch_path = None if branch_path and os.path.exists(branch_path): branch = '/'.join(line.split('/')[2:]) with open(branch_path) as f: commit = f.readline()[:10] else: # detached HEAD commit = line[:10] branch = 'detached HEAD' branch_path = os.path.join(repo_path, "HEAD") date = time.localtime(os.stat(branch_path).st_mtime) if time.daylight == 0: offset = time.timezone else: offset = time.altzone result = "({0} {1}) last updated {2} (GMT {3:+04d})".format(branch, commit, time.strftime("%Y/%m/%d %H:%M:%S", date), int(offset / -36)) else: result = '' return result def _gitinfo(): basedir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) repo_path = os.path.join(basedir, '.git') return _git_repo_info(repo_path) def version(prog=None): """ return ansible version """ if prog: result = ["{0} [core {1}]".format(prog, __version__)] else: result = [__version__] gitinfo = _gitinfo() if gitinfo: result[0] = "{0} {1}".format(result[0], gitinfo) result.append(" config file = %s" % C.CONFIG_FILE) if C.DEFAULT_MODULE_PATH is None: cpath = "Default w/o overrides" else: cpath = C.DEFAULT_MODULE_PATH if HAS_LIBYAML: libyaml_fragment = "with libyaml" # noinspection PyBroadException try: from yaml._yaml import get_version_string libyaml_fragment += f" v{get_version_string()}" except Exception: # pylint: disable=broad-except libyaml_fragment += ", version unknown" else: libyaml_fragment = "without libyaml" result.append(" configured module search path = %s" % cpath) result.append(" ansible python module location = %s" % ':'.join(ansible.__path__)) result.append(" ansible collection location = %s" % ':'.join(C.COLLECTIONS_PATHS)) result.append(" executable location = %s" % sys.argv[0]) result.append(" python version = %s (%s)" % (''.join(sys.version.splitlines()), to_native(sys.executable))) result.append(f" jinja version = {_templating.jinja2_version}") result.append(f" pyyaml version = {yaml.__version__} ({libyaml_fragment})") return "\n".join(result) # # Functions to add pre-canned options to an OptionParser # def create_base_parser(prog, usage="", desc=None, epilog=None): """ Create an options parser for all ansible scripts """ # base opts parser = ArgumentParser( prog=prog, formatter_class=SortingHelpFormatter, epilog=epilog, description=desc, conflict_handler='resolve', ) version_help = "show program's version number, config file location, configured module search path," \ " module location, executable location and exit" parser.add_argument('--version', action=AnsibleVersion, nargs=0, help=version_help) add_verbosity_options(parser) return parser def add_verbosity_options(parser): """Add options for verbosity""" parser.add_argument('-v', '--verbose', dest='verbosity', default=C.DEFAULT_VERBOSITY, action="count", help="Causes Ansible to print more debug messages. Adding multiple -v will increase the verbosity, " "the builtin plugins currently evaluate up to -vvvvvv. A reasonable level to start is -vvv, " "connection debugging might require -vvvv.") def add_async_options(parser): """Add options for commands which can launch async tasks""" parser.add_argument('-P', '--poll', default=C.DEFAULT_POLL_INTERVAL, type=int, dest='poll_interval', help="set the poll interval if using -B (default=%s)" % C.DEFAULT_POLL_INTERVAL) parser.add_argument('-B', '--background', dest='seconds', type=int, default=0, help='run asynchronously, failing after X seconds (default=N/A)') def add_basedir_options(parser): """Add options for commands which can set a playbook basedir""" parser.add_argument('--playbook-dir', default=C.PLAYBOOK_DIR, dest='basedir', action='store', help="Since this tool does not use playbooks, use this as a substitute playbook directory. " "This sets the relative path for many features including roles/ group_vars/ etc.", type=unfrack_path()) def add_check_options(parser): """Add options for commands which can run with diagnostic information of tasks""" parser.add_argument("-C", "--check", default=False, dest='check', action='store_true', help="don't make any changes; instead, try to predict some of the changes that may occur") parser.add_argument("-D", "--diff", default=C.DIFF_ALWAYS, dest='diff', action='store_true', help="when changing (small) files and templates, show the differences in those" " files; works great with --check") def add_connect_options(parser): """Add options for commands which need to connection to other hosts""" connect_group = parser.add_argument_group("Connection Options", "control as whom and how to connect to hosts") connect_group.add_argument('--private-key', '--key-file', default=C.DEFAULT_PRIVATE_KEY_FILE, dest='private_key_file', help='use this file to authenticate the connection', type=unfrack_path()) connect_group.add_argument('-u', '--user', default=C.DEFAULT_REMOTE_USER, dest='remote_user', help='connect as this user (default=%s)' % C.DEFAULT_REMOTE_USER) connect_group.add_argument('-c', '--connection', dest='connection', default=C.DEFAULT_TRANSPORT, help="connection type to use (default=%s)" % C.DEFAULT_TRANSPORT) connect_group.add_argument('-T', '--timeout', default=None, type=int, dest='timeout', help="override the connection timeout in seconds (default depends on connection)") # ssh only connect_group.add_argument('--ssh-common-args', default=None, dest='ssh_common_args', help="specify common arguments to pass to sftp/scp/ssh (e.g. ProxyCommand)") connect_group.add_argument('--sftp-extra-args', default=None, dest='sftp_extra_args', help="specify extra arguments to pass to sftp only (e.g. -f, -l)") connect_group.add_argument('--scp-extra-args', default=None, dest='scp_extra_args', help="specify extra arguments to pass to scp only (e.g. -l)") connect_group.add_argument('--ssh-extra-args', default=None, dest='ssh_extra_args', help="specify extra arguments to pass to ssh only (e.g. -R)") parser.add_argument_group(connect_group) connect_password_group = parser.add_mutually_exclusive_group() connect_password_group.add_argument('-k', '--ask-pass', default=C.DEFAULT_ASK_PASS, dest='ask_pass', action='store_true', help='ask for connection password') connect_password_group.add_argument('--connection-password-file', '--conn-pass-file', default=C.CONNECTION_PASSWORD_FILE, dest='connection_password_file', help="Connection password file", type=unfrack_path(), action='store') parser.add_argument_group(connect_password_group) def add_fork_options(parser): """Add options for commands that can fork worker processes""" parser.add_argument('-f', '--forks', dest='forks', default=C.DEFAULT_FORKS, type=int, help="specify number of parallel processes to use (default=%s)" % C.DEFAULT_FORKS) def add_inventory_options(parser): """Add options for commands that utilize inventory""" parser.add_argument('-i', '--inventory', '--inventory-file', dest='inventory', action="append", help="specify inventory host path or comma separated host list", deprecated=DeprecatedArgument(version='2.23', option='--inventory-file')) parser.add_argument('--list-hosts', dest='listhosts', action='store_true', help='outputs a list of matching hosts; does not execute anything else') parser.add_argument('-l', '--limit', default=C.DEFAULT_SUBSET, dest='subset', help='further limit selected hosts to an additional pattern') parser.add_argument('--flush-cache', dest='flush_cache', action='store_true', help="clear the fact cache for every host in inventory") def add_meta_options(parser): """Add options for commands which can launch meta tasks from the command line""" parser.add_argument('--force-handlers', default=C.DEFAULT_FORCE_HANDLERS, dest='force_handlers', action='store_true', help="run handlers even if a task fails") def add_module_options(parser): """Add options for commands that load modules""" module_path = C.config.get_configuration_definition('DEFAULT_MODULE_PATH').get('default', '') parser.add_argument('-M', '--module-path', dest='module_path', default=None, help="prepend colon-separated path(s) to module library (default=%s)" % module_path, type=unfrack_path(pathsep=True), action=PrependListAction) def add_output_options(parser): """Add options for commands which can change their output""" parser.add_argument('-o', '--one-line', dest='one_line', action='store_true', help='condense output', deprecated=DeprecatedArgument(version='2.23')) parser.add_argument('-t', '--tree', dest='tree', default=None, help='log output to this directory', deprecated=DeprecatedArgument(version='2.23')) def add_runas_options(parser): """ Add options for commands which can run tasks as another user Note that this includes the options from add_runas_prompt_options(). Only one of these functions should be used. """ runas_group = parser.add_argument_group("Privilege Escalation Options", "control how and which user you become as on target hosts") # consolidated privilege escalation (become) runas_group.add_argument("-b", "--become", default=C.DEFAULT_BECOME, action="store_true", dest='become', help="run operations with become (does not imply password prompting)") runas_group.add_argument('--become-method', dest='become_method', default=C.DEFAULT_BECOME_METHOD, help='privilege escalation method to use (default=%s)' % C.DEFAULT_BECOME_METHOD + ', use `ansible-doc -t become -l` to list valid choices.') runas_group.add_argument('--become-user', default=None, dest='become_user', type=str, help='run operations as this user (default=%s)' % C.DEFAULT_BECOME_USER) parser.add_argument_group(runas_group) add_runas_prompt_options(parser) def add_runas_prompt_options(parser, runas_group=None): """ Add options for commands which need to prompt for privilege escalation credentials Note that add_runas_options() includes these options already. Only one of the two functions should be used. """ if runas_group is not None: parser.add_argument_group(runas_group) runas_pass_group = parser.add_mutually_exclusive_group() runas_pass_group.add_argument('-K', '--ask-become-pass', dest='become_ask_pass', action='store_true', default=C.DEFAULT_BECOME_ASK_PASS, help='ask for privilege escalation password') runas_pass_group.add_argument('--become-password-file', '--become-pass-file', default=C.BECOME_PASSWORD_FILE, dest='become_password_file', help="Become password file", type=unfrack_path(), action='store') parser.add_argument_group(runas_pass_group) def add_runtask_options(parser): """Add options for commands that run a task""" parser.add_argument('-e', '--extra-vars', dest="extra_vars", action="append", type=maybe_unfrack_path('@'), help="set additional variables as key=value or YAML/JSON, if filename prepend with @", default=[]) def add_tasknoplay_options(parser): """Add options for commands that run a task w/o a defined play""" parser.add_argument('--task-timeout', type=int, dest="task_timeout", action="store", default=C.TASK_TIMEOUT, help="set task timeout limit in seconds, must be positive integer.") def add_subset_options(parser): """Add options for commands which can run a subset of tasks""" parser.add_argument('-t', '--tags', dest='tags', default=C.TAGS_RUN, action='append', help="only run plays and tasks tagged with these values") parser.add_argument('--skip-tags', dest='skip_tags', default=C.TAGS_SKIP, action='append', help="only run plays and tasks whose tags do not match these values") def add_vault_options(parser): """Add options for loading vault files""" parser.add_argument('--vault-id', default=[], dest='vault_ids', action='append', type=str, help='the vault identity to use') base_group = parser.add_mutually_exclusive_group() base_group.add_argument('-J', '--ask-vault-password', '--ask-vault-pass', default=C.DEFAULT_ASK_VAULT_PASS, dest='ask_vault_pass', action='store_true', help='ask for vault password') base_group.add_argument('--vault-password-file', '--vault-pass-file', default=[], dest='vault_password_files', help="vault password file", type=unfrack_path(follow=False), action='append') def _tagged_type_factory(name: str, func: t.Callable[[str], object], /) -> t.Callable[[str], object]: """ Return a callable that wraps the given function. The result of the wrapped function will be tagged with Origin. It will also be tagged with TrustedAsTemplate if it is equal to the original input string. """ def tag_value(value: str) -> object: result = func(value) if result is value or func is str: # Values which are not mutated are automatically trusted for templating. # The `is` reference equality is critically important, as other types may only alter the tags, so object equality is # not sufficient to prevent them being tagged as trusted when they should not. # Explicitly include all usages using the `str` type factory since it strips tags. result = TrustedAsTemplate().tag(result) if not (origin := Origin.get_tag(value)): origin = Origin(description=f'') return origin.tag(result) tag_value._name = name # simplify debugging by attaching the argument name to the function return tag_value ansible_core-2.19.0b5/lib/ansible/cli/config.py0000755000000000000000000006767715017704211020016 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2017, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import os import shlex import sys import yaml from collections.abc import Mapping from ansible import context import ansible.plugins.loader as plugin_loader from ansible import constants as C from ansible.cli.arguments import option_helpers as opt_help from ansible.config.manager import ConfigManager from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRequiredOptionError from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes from ansible._internal import _json from ansible.module_utils.six import string_types from ansible.parsing.quoting import is_quoted from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.utils.color import stringc from ansible.utils.display import Display from ansible.utils.path import unfrackpath display = Display() _IGNORE_CHANGED = frozenset({'_terms', '_input'}) def yaml_dump(data, default_flow_style=False, default_style=None): return yaml.dump(data, Dumper=AnsibleDumper, default_flow_style=default_flow_style, default_style=default_style) def yaml_short(data): return yaml_dump(data, default_flow_style=True, default_style="''") def get_constants(): """ helper method to ensure we can template based on existing constants """ if not hasattr(get_constants, 'cvars'): get_constants.cvars = {k: getattr(C, k) for k in dir(C) if not k.startswith('__')} return get_constants.cvars def _ansible_env_vars(varname): """ return true or false depending if variable name is possibly a 'configurable' ansible env variable """ return all( [ varname.startswith("ANSIBLE_"), not varname.startswith(("ANSIBLE_TEST_", "ANSIBLE_LINT_")), varname not in ("ANSIBLE_CONFIG", "ANSIBLE_DEV_HOME"), ] ) def _get_evar_list(settings): data = [] for setting in settings: if 'env' in settings[setting] and settings[setting]['env']: for varname in settings[setting]['env']: data.append(varname.get('name')) return data def _get_ini_entries(settings): data = {} for setting in settings: if 'ini' in settings[setting] and settings[setting]['ini']: for kv in settings[setting]['ini']: if not kv['section'] in data: data[kv['section']] = set() data[kv['section']].add(kv['key']) return data class ConfigCLI(CLI): """ Config command line class """ name = 'ansible-config' def __init__(self, args, callback=None): self.config_file = None self.config = None super(ConfigCLI, self).__init__(args, callback) def init_parser(self): super(ConfigCLI, self).init_parser( desc="View ansible configuration.", ) common = opt_help.ArgumentParser(add_help=False) opt_help.add_verbosity_options(common) common.add_argument('-c', '--config', dest='config_file', help="path to configuration file, defaults to first file found in precedence.") common.add_argument("-t", "--type", action="store", default='base', dest='type', choices=['all', 'base'] + list(C.CONFIGURABLE_PLUGINS), help="Filter down to a specific plugin type.") common.add_argument('args', help='Specific plugin to target, requires type of plugin to be set', nargs='*') subparsers = self.parser.add_subparsers(dest='action') subparsers.required = True list_parser = subparsers.add_parser('list', help='Print all config options', parents=[common]) list_parser.set_defaults(func=self.execute_list) list_parser.add_argument('--format', '-f', dest='format', action='store', choices=['json', 'yaml'], default='yaml', help='Output format for list') dump_parser = subparsers.add_parser('dump', help='Dump configuration', parents=[common]) dump_parser.set_defaults(func=self.execute_dump) dump_parser.add_argument('--only-changed', '--changed-only', dest='only_changed', action='store_true', help="Only show configurations that have changed from the default") dump_parser.add_argument('--format', '-f', dest='format', action='store', choices=['json', 'yaml', 'display'], default='display', help='Output format for dump') view_parser = subparsers.add_parser('view', help='View configuration file', parents=[common]) view_parser.set_defaults(func=self.execute_view) init_parser = subparsers.add_parser('init', help='Create initial configuration', parents=[common]) init_parser.set_defaults(func=self.execute_init) init_parser.add_argument('--format', '-f', dest='format', action='store', choices=['ini', 'env', 'vars'], default='ini', help='Output format for init') init_parser.add_argument('--disabled', dest='commented', action='store_true', default=False, help='Prefixes all entries with a comment character to disable them') validate_parser = subparsers.add_parser('validate', help='Validate the configuration file and environment variables. ' 'By default it only checks the base settings without accounting for plugins (see -t).', parents=[common]) validate_parser.set_defaults(func=self.execute_validate) validate_parser.add_argument('--format', '-f', dest='format', action='store', choices=['ini', 'env'] , default='ini', help='Output format for init') def post_process_args(self, options): options = super(ConfigCLI, self).post_process_args(options) display.verbosity = options.verbosity return options def run(self): super(ConfigCLI, self).run() # initialize each galaxy server's options from known listed servers self._galaxy_servers = [s for s in C.GALAXY_SERVER_LIST or [] if s] # clean list, reused later here C.config.load_galaxy_server_defs(self._galaxy_servers) if context.CLIARGS['config_file']: self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False) b_config = to_bytes(self.config_file) if os.path.exists(b_config) and os.access(b_config, os.R_OK): self.config = ConfigManager(self.config_file) else: raise AnsibleOptionsError('The provided configuration file is missing or not accessible: %s' % to_native(self.config_file)) else: self.config = C.config self.config_file = self.config._config_file if self.config_file: try: if not os.path.exists(self.config_file): raise AnsibleOptionsError("%s does not exist or is not accessible" % (self.config_file)) elif not os.path.isfile(self.config_file): raise AnsibleOptionsError("%s is not a valid file" % (self.config_file)) os.environ['ANSIBLE_CONFIG'] = to_native(self.config_file) except Exception: if context.CLIARGS['action'] in ['view']: raise elif context.CLIARGS['action'] == 'view': raise AnsibleError('Invalid or no config file was supplied') # run the requested action context.CLIARGS['func']() def execute_view(self): """ Displays the current config file """ try: with open(self.config_file, 'rb') as f: self.pager(to_text(f.read(), errors='surrogate_or_strict')) except Exception as e: raise AnsibleError("Failed to open config file: %s" % to_native(e)) def _list_plugin_settings(self, ptype, plugins=None): entries = {} loader = getattr(plugin_loader, '%s_loader' % ptype) # build list if plugins: plugin_cs = [] for plugin in plugins: p = loader.get(plugin, class_only=True) if p is None: display.warning("Skipping %s as we could not find matching plugin" % plugin) else: plugin_cs.append(p) else: plugin_cs = loader.all(class_only=True) # iterate over class instances for plugin in plugin_cs: finalname = name = plugin._load_name if name.startswith('_'): # alias or deprecated if os.path.islink(plugin._original_path): continue else: finalname = name.replace('_', '', 1) + ' (DEPRECATED)' entries[finalname] = self.config.get_configuration_definitions(ptype, name) return entries def _list_entries_from_args(self): """ build a dict with the list requested configs """ config_entries = {} if context.CLIARGS['type'] in ('base', 'all'): # this dumps main/common configs config_entries = self.config.get_configuration_definitions(ignore_private=True) # for base and all, we include galaxy servers config_entries['GALAXY_SERVERS'] = {} for server in self._galaxy_servers: config_entries['GALAXY_SERVERS'][server] = self.config.get_configuration_definitions('galaxy_server', server) if context.CLIARGS['type'] != 'base': config_entries['PLUGINS'] = {} if context.CLIARGS['type'] == 'all': # now each plugin type for ptype in C.CONFIGURABLE_PLUGINS: config_entries['PLUGINS'][ptype.upper()] = self._list_plugin_settings(ptype) elif context.CLIARGS['type'] != 'base': # only for requested types config_entries['PLUGINS'][context.CLIARGS['type']] = self._list_plugin_settings(context.CLIARGS['type'], context.CLIARGS['args']) return config_entries def execute_list(self): """ list and output available configs """ config_entries = self._list_entries_from_args() if context.CLIARGS['format'] == 'yaml': output = yaml_dump(config_entries) elif context.CLIARGS['format'] == 'json': output = _json.json_dumps_formatted(config_entries) self.pager(to_text(output, errors='surrogate_or_strict')) def _get_settings_vars(self, settings, subkey): data = [] if context.CLIARGS['commented']: prefix = '#' else: prefix = '' for setting in settings: if not settings[setting].get('description'): continue default = self.config.template_default(settings[setting].get('default', ''), get_constants()) if subkey == 'env': stype = settings[setting].get('type', '') if stype == 'boolean': if default: default = '1' else: default = '0' elif default: if stype == 'list': if not isinstance(default, string_types): # python lists are not valid env ones try: default = ', '.join(default) except Exception as e: # list of other stuff default = '%s' % to_native(default) if isinstance(default, string_types) and not is_quoted(default): default = shlex.quote(default) elif default is None: default = '' if subkey in settings[setting] and settings[setting][subkey]: entry = settings[setting][subkey][-1]['name'] if isinstance(settings[setting]['description'], string_types): desc = settings[setting]['description'] else: desc = '\n#'.join(settings[setting]['description']) name = settings[setting].get('name', setting) data.append('# %s(%s): %s' % (name, settings[setting].get('type', 'string'), desc)) # TODO: might need quoting and value coercion depending on type if subkey == 'env': if entry.startswith('_ANSIBLE_'): continue data.append('%s%s=%s' % (prefix, entry, default)) elif subkey == 'vars': if entry.startswith('_ansible_'): continue data.append(prefix + '%s: %s' % (entry, to_text(yaml_short(default), errors='surrogate_or_strict'))) data.append('') return data def _get_settings_ini(self, settings, seen): sections = {} for o in sorted(settings.keys()): opt = settings[o] if not isinstance(opt, Mapping): # recursed into one of the few settings that is a mapping, now hitting it's strings continue if not opt.get('description'): # its a plugin new_sections = self._get_settings_ini(opt, seen) for s in new_sections: if s in sections: sections[s].extend(new_sections[s]) else: sections[s] = new_sections[s] continue if isinstance(opt['description'], string_types): desc = '# (%s) %s' % (opt.get('type', 'string'), opt['description']) else: desc = "# (%s) " % opt.get('type', 'string') desc += "\n# ".join(opt['description']) if 'ini' in opt and opt['ini']: entry = opt['ini'][-1] if entry['section'] not in seen: seen[entry['section']] = [] if entry['section'] not in sections: sections[entry['section']] = [] # avoid dupes if entry['key'] not in seen[entry['section']]: seen[entry['section']].append(entry['key']) default = self.config.template_default(opt.get('default', ''), get_constants()) if opt.get('type', '') == 'list' and not isinstance(default, string_types): # python lists are not valid ini ones default = ', '.join(default) elif default is None: default = '' if context.CLIARGS.get('commented', False): entry['key'] = ';%s' % entry['key'] key = desc + '\n%s=%s' % (entry['key'], default) sections[entry['section']].append(key) return sections def execute_init(self): """Create initial configuration""" seen = {} data = [] config_entries = self._list_entries_from_args() plugin_types = config_entries.pop('PLUGINS', None) if context.CLIARGS['format'] == 'ini': sections = self._get_settings_ini(config_entries, seen) if plugin_types: for ptype in plugin_types: plugin_sections = self._get_settings_ini(plugin_types[ptype], seen) for s in plugin_sections: if s in sections: sections[s].extend(plugin_sections[s]) else: sections[s] = plugin_sections[s] if sections: for section in sections.keys(): data.append('[%s]' % section) for key in sections[section]: data.append(key) data.append('') data.append('') elif context.CLIARGS['format'] in ('env', 'vars'): # TODO: add yaml once that config option is added data = self._get_settings_vars(config_entries, context.CLIARGS['format']) if plugin_types: for ptype in plugin_types: for plugin in plugin_types[ptype].keys(): data.extend(self._get_settings_vars(plugin_types[ptype][plugin], context.CLIARGS['format'])) self.pager(to_text('\n'.join(data), errors='surrogate_or_strict')) def _render_settings(self, config): entries = [] for setting in sorted(config): changed = (config[setting]['origin'] not in ('default', 'REQUIRED') and setting not in _IGNORE_CHANGED) if context.CLIARGS['format'] == 'display': if isinstance(config[setting], dict): # proceed normally value = config[setting]['value'] if config[setting]['origin'] == 'default' or setting in _IGNORE_CHANGED: color = 'green' value = self.config.template_default(value, get_constants()) elif config[setting]['origin'] == 'REQUIRED': # should include '_terms', '_input', etc color = 'red' else: color = 'yellow' msg = "%s(%s) = %s" % (setting, config[setting]['origin'], value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) entry = stringc(msg, color) else: entry = {} for key in config[setting].keys(): if key == 'type': continue entry[key] = config[setting][key] if not context.CLIARGS['only_changed'] or changed: entries.append(entry) return entries def _get_global_configs(self): # Add base config = self.config.get_configuration_definitions(ignore_private=True) # convert to settings settings = {} for setting in config.keys(): v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, variables=get_constants()) settings[setting] = { 'name': setting, 'value': v, 'origin': o, 'type': None } return self._render_settings(settings) def _get_plugin_configs(self, ptype, plugins): # prep loading loader = getattr(plugin_loader, '%s_loader' % ptype) # accumulators output = [] config_entries = {} # build list if plugins: plugin_cs = [] for plugin in plugins: p = loader.get(plugin, class_only=True) if p is None: display.warning("Skipping %s as we could not find matching plugin" % plugin) else: plugin_cs.append(loader.get(plugin, class_only=True)) else: plugin_cs = loader.all(class_only=True) for plugin in plugin_cs: # in case of deprecation they diverge finalname = name = plugin._load_name if name.startswith('_'): if os.path.islink(plugin._original_path): # skip alias continue # deprecated, but use 'nice name' finalname = name.replace('_', '', 1) + ' (DEPRECATED)' # default entries per plugin config_entries[finalname] = self.config.get_configuration_definitions(ptype, name) try: # populate config entries by loading plugin dump = loader.get(name, class_only=True) except Exception as e: display.warning('Skipping "%s" %s plugin, as we cannot load plugin to check config due to : %s' % (name, ptype, to_native(e))) continue # actually get the values for setting in config_entries[finalname].keys(): try: v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, plugin_type=ptype, plugin_name=name, variables=get_constants()) except AnsibleRequiredOptionError: v = None o = 'REQUIRED' if v is None and o is None: # not all cases will be error o = 'REQUIRED' config_entries[finalname][setting] = { 'name': setting, 'value': v, 'origin': o, 'type': None } # pretty please! results = self._render_settings(config_entries[finalname]) if results: if context.CLIARGS['format'] == 'display': # avoid header for empty lists (only changed!) output.append('\n%s:\n%s' % (finalname, '_' * len(finalname))) output.extend(results) else: output.append({finalname: results}) return output def _get_galaxy_server_configs(self): output = [] # add galaxy servers for server in self._galaxy_servers: server_config = {} s_config = self.config.get_configuration_definitions('galaxy_server', server) for setting in s_config.keys(): try: v, o = C.config.get_config_value_and_origin(setting, plugin_type='galaxy_server', plugin_name=server, cfile=self.config_file) except AnsibleError as e: if s_config[setting].get('required', False): v = None o = 'REQUIRED' else: raise e if v is None and o is None: # not all cases will be error o = 'REQUIRED' server_config[setting] = { 'name': setting, 'value': v, 'origin': o, 'type': None } if context.CLIARGS['format'] == 'display': if not context.CLIARGS['only_changed'] or server_config: equals = '=' * len(server) output.append(f'\n{server}\n{equals}') output.extend(self._render_settings(server_config)) else: output.append({server: server_config}) return output def execute_dump(self): """ Shows the current settings, merges ansible.cfg if specified """ output = [] if context.CLIARGS['type'] in ('base', 'all'): # deal with base output = self._get_global_configs() # add galaxy servers server_config_list = self._get_galaxy_server_configs() if context.CLIARGS['format'] == 'display': output.append('\nGALAXY_SERVERS:\n') output.extend(server_config_list) else: configs = {} for server_config in server_config_list: server = list(server_config.keys())[0] server_reduced_config = server_config.pop(server) configs[server] = list(server_reduced_config.values()) output.append({'GALAXY_SERVERS': configs}) if context.CLIARGS['type'] == 'all': # add all plugins for ptype in C.CONFIGURABLE_PLUGINS: plugin_list = self._get_plugin_configs(ptype, context.CLIARGS['args']) if context.CLIARGS['format'] == 'display': if not context.CLIARGS['only_changed'] or plugin_list: output.append('\n%s:\n%s' % (ptype.upper(), '=' * len(ptype))) output.extend(plugin_list) else: if ptype in ('modules', 'doc_fragments'): pname = ptype.upper() else: pname = '%s_PLUGINS' % ptype.upper() output.append({pname: plugin_list}) elif context.CLIARGS['type'] != 'base': # deal with specific plugin output = self._get_plugin_configs(context.CLIARGS['type'], context.CLIARGS['args']) if context.CLIARGS['format'] == 'display': text = '\n'.join(output) if context.CLIARGS['format'] == 'yaml': text = yaml_dump(output) elif context.CLIARGS['format'] == 'json': text = _json.json_dumps_formatted(output) self.pager(to_text(text, errors='surrogate_or_strict')) def execute_validate(self): found = False config_entries = self._list_entries_from_args() plugin_types = config_entries.pop('PLUGINS', None) galaxy_servers = config_entries.pop('GALAXY_SERVERS', None) if context.CLIARGS['format'] == 'ini': if C.CONFIG_FILE is not None: # validate ini config since it is found sections = _get_ini_entries(config_entries) # Also from plugins if plugin_types: for ptype in plugin_types: for plugin in plugin_types[ptype].keys(): plugin_sections = _get_ini_entries(plugin_types[ptype][plugin]) for s in plugin_sections: if s in sections: sections[s].update(plugin_sections[s]) else: sections[s] = plugin_sections[s] if galaxy_servers: for server in galaxy_servers: server_sections = _get_ini_entries(galaxy_servers[server]) for s in server_sections: if s in sections: sections[s].update(server_sections[s]) else: sections[s] = server_sections[s] if sections: p = C.config._parsers[C.CONFIG_FILE] for s in p.sections(): # check for valid sections if s not in sections: display.error(f"Found unknown section '{s}' in '{C.CONFIG_FILE}.") found = True continue # check keys in valid sections for k in p.options(s): if k not in sections[s]: display.error(f"Found unknown key '{k}' in section '{s}' in '{C.CONFIG_FILE}.") found = True elif context.CLIARGS['format'] == 'env': # validate any 'ANSIBLE_' env vars found evars = [varname for varname in os.environ.keys() if _ansible_env_vars(varname)] if evars: data = _get_evar_list(config_entries) if plugin_types: for ptype in plugin_types: for plugin in plugin_types[ptype].keys(): data.extend(_get_evar_list(plugin_types[ptype][plugin])) for evar in evars: if evar not in data: display.error(f"Found unknown environment variable '{evar}'.") found = True # we found discrepancies! if found: sys.exit(1) # allsgood display.display("All configurations seem valid!") def main(args=None): ConfigCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/console.py0000755000000000000000000005277215017704211020201 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2014, Nandor Sivok # Copyright: (c) 2016, Redhat Inc # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import atexit import cmd import getpass import readline import os import sys from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.executor.task_queue_manager import TaskQueueManager from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.parsing.convert_bool import boolean from ansible.parsing.splitter import parse_kv from ansible.playbook.play import Play from ansible.plugins.list import list_plugins from ansible.plugins.loader import module_loader, fragment_loader from ansible.utils import plugin_docs from ansible.utils.color import stringc from ansible._internal._datatag._tags import TrustedAsTemplate from ansible.utils.display import Display display = Display() class ConsoleCLI(CLI, cmd.Cmd): """ A REPL that allows for running ad-hoc tasks against a chosen inventory from a nice shell with built-in tab completion (based on dominis' ``ansible-shell``). It supports several commands, and you can modify its configuration at runtime: - ``cd [pattern]``: change host/group (you can use host patterns eg.: ``app*.dc*:!app01*``) - ``list``: list available hosts in the current path - ``list groups``: list groups included in the current path - ``become``: toggle the become flag - ``!``: forces shell module instead of the ansible module (``!yum update -y``) - ``verbosity [num]``: set the verbosity level - ``forks [num]``: set the number of forks - ``become_user [user]``: set the become_user - ``remote_user [user]``: set the remote_user - ``become_method [method]``: set the privilege escalation method - ``check [bool]``: toggle check mode - ``diff [bool]``: toggle diff mode - ``timeout [integer]``: set the timeout of tasks in seconds (0 to disable) - ``help [command/module]``: display documentation for the command or module - ``exit``: exit ``ansible-console`` """ name = 'ansible-console' modules = [] # type: list[str] | None ARGUMENTS = {'host-pattern': 'A name of a group in the inventory, a shell-like glob ' 'selecting hosts in inventory or any combination of the two separated by commas.'} # use specific to console, but fallback to highlight for backwards compatibility NORMAL_PROMPT = C.COLOR_CONSOLE_PROMPT or C.COLOR_HIGHLIGHT USES_CONNECTION = True def __init__(self, args): super(ConsoleCLI, self).__init__(args) self.intro = 'Welcome to the ansible console. Type help or ? to list commands.\n' self.groups = [] self.hosts = [] self.pattern = None self.variable_manager = None self.loader = None self.passwords = dict() self.cwd = '*' # Defaults for these are set from the CLI in run() self.remote_user = None self.become = None self.become_user = None self.become_method = None self.check_mode = None self.diff = None self.forks = None self.task_timeout = None self.collections = None cmd.Cmd.__init__(self) def init_parser(self): super(ConsoleCLI, self).init_parser( desc="REPL console for executing Ansible tasks.", epilog="This is not a live session/connection: each task is executed in the background and returns its results." ) opt_help.add_runas_options(self.parser) opt_help.add_inventory_options(self.parser) opt_help.add_connect_options(self.parser) opt_help.add_check_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_fork_options(self.parser) opt_help.add_module_options(self.parser) opt_help.add_basedir_options(self.parser) opt_help.add_runtask_options(self.parser) opt_help.add_tasknoplay_options(self.parser) # options unique to shell self.parser.add_argument('pattern', help='host pattern', metavar='pattern', default='all', nargs='?') self.parser.add_argument('--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") def post_process_args(self, options): options = super(ConsoleCLI, self).post_process_args(options) display.verbosity = options.verbosity self.validate_conflicts(options, runas_opts=True, fork_opts=True) return options def get_names(self): return dir(self) def cmdloop(self): try: cmd.Cmd.cmdloop(self) except KeyboardInterrupt: self.cmdloop() except EOFError: self.display("[Ansible-console was exited]") self.do_exit(self) def set_prompt(self): login_user = self.remote_user or getpass.getuser() self.selected = self.inventory.list_hosts(self.cwd) prompt = "%s@%s (%d)[f:%s]" % (login_user, self.cwd, len(self.selected), self.forks) if self.become and self.become_user in [None, 'root']: prompt += "# " color = C.COLOR_ERROR else: prompt += "$ " color = self.NORMAL_PROMPT self.prompt = stringc(prompt, color, wrap_nonvisible_chars=True) def list_modules(self): return list_plugins('module', self.collections) def default(self, line, forceshell=False): """ actually runs modules """ if line.startswith("#"): return False if not self.cwd: display.error("No host found") return False # defaults module = 'shell' module_args = line if forceshell is not True: possible_module, *possible_args = line.split() if module_loader.find_plugin(possible_module): # we found module! module = possible_module if possible_args: module_args = ' '.join(possible_args) else: module_args = '' module_args = TrustedAsTemplate().tag(module_args) if self.callback: cb = self.callback elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default': cb = C.DEFAULT_STDOUT_CALLBACK else: cb = 'minimal' result = None try: check_raw = module in C._ACTION_ALLOWS_RAW_ARGS task = dict(action=dict(module=module, args=parse_kv(module_args, check_raw=check_raw)), timeout=self.task_timeout) play_ds = dict( name="Ansible Shell", hosts=self.cwd, gather_facts='no', tasks=[task], remote_user=self.remote_user, become=self.become, become_user=self.become_user, become_method=self.become_method, check_mode=self.check_mode, diff=self.diff, collections=self.collections, ) play = Play().load(play_ds, variable_manager=self.variable_manager, loader=self.loader) except Exception as e: display.error(u"Unable to build command: %s" % to_text(e)) return False try: # now create a task queue manager to execute the play self._tqm = None try: self._tqm = TaskQueueManager( inventory=self.inventory, variable_manager=self.variable_manager, loader=self.loader, passwords=self.passwords, stdout_callback=cb, run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS, run_tree=False, forks=self.forks, ) result = self._tqm.run(play) display.debug(result) finally: if self._tqm: self._tqm.cleanup() if self.loader: self.loader.cleanup_all_tmp_files() if result is None: display.error("No hosts found") return False except KeyboardInterrupt: display.error('User interrupted execution') return False except Exception as ex: display.error(ex) return False def emptyline(self): return def do_shell(self, arg): """ You can run shell commands through the shell module. eg.: shell ps uax | grep java | wc -l shell killall python shell halt -n You can use the ! to force the shell module. eg.: !ps aux | grep java | wc -l """ self.default(arg, True) def help_shell(self): display.display("You can run shell commands through the shell module.") def do_forks(self, arg): """Set the number of forks""" if arg: try: forks = int(arg) except TypeError: display.error('Invalid argument for "forks"') self.usage_forks() if forks > 0: self.forks = forks self.set_prompt() else: display.display('forks must be greater than or equal to 1') else: self.usage_forks() def help_forks(self): display.display("Set the number of forks to use per task") self.usage_forks() def usage_forks(self): display.display('Usage: forks ') do_serial = do_forks help_serial = help_forks def do_collections(self, arg): """Set list of collections for 'short name' usage""" if arg in ('', 'none'): self.collections = None elif not arg: self.usage_collections() else: collections = arg.split(',') for collection in collections: if self.collections is None: self.collections = [] self.collections.append(collection.strip()) if self.collections: display.v('Collections name search is set to: %s' % ', '.join(self.collections)) else: display.v('Collections name search is using defaults') def help_collections(self): display.display("Set the collection name search path when using short names for plugins") self.usage_collections() def usage_collections(self): display.display('Usage: collections [, ...]\n Use empty quotes or "none" to reset to default.\n') def do_verbosity(self, arg): """Set verbosity level""" if not arg: display.display('Usage: verbosity ') else: try: display.verbosity = int(arg) display.v('verbosity level set to %s' % arg) except (TypeError, ValueError) as e: display.error('The verbosity must be a valid integer: %s' % to_text(e)) def help_verbosity(self): display.display("Set the verbosity level, equivalent to -v for 1 and -vvvv for 4.") def do_cd(self, arg): """ Change active host/group. You can use hosts patterns as well eg.: cd webservers cd webservers:dbservers cd webservers:!phoenix cd webservers:&staging cd webservers:dbservers:&staging:!phoenix """ if not arg: self.cwd = '*' elif arg in '/*': self.cwd = 'all' elif self.inventory.get_hosts(arg): self.cwd = arg else: display.display("no host matched") self.set_prompt() def help_cd(self): display.display("Change active host/group. ") self.usage_cd() def usage_cd(self): display.display("Usage: cd ||") def do_list(self, arg): """List the hosts in the current group""" if not arg: for host in self.selected: display.display(host.name) elif arg == 'groups': for group in self.groups: display.display(group) else: display.error('Invalid option passed to "list"') self.help_list() def help_list(self): display.display("List the hosts in the current group or a list of groups if you add 'groups'.") def do_become(self, arg): """Toggle whether plays run with become""" if arg: self.become = boolean(arg, strict=False) display.v("become changed to %s" % self.become) self.set_prompt() else: display.display("Please specify become value, e.g. `become yes`") def help_become(self): display.display("Toggle whether the tasks are run with become") def do_remote_user(self, arg): """Given a username, set the remote user plays are run by""" if arg: self.remote_user = arg self.set_prompt() else: display.display("Please specify a remote user, e.g. `remote_user root`") def help_remote_user(self): display.display("Set the user for use as login to the remote target") def do_become_user(self, arg): """Given a username, set the user that plays are run by when using become""" if arg: self.become_user = arg else: display.display("Please specify a user, e.g. `become_user jenkins`") display.v("Current user is %s" % self.become_user) self.set_prompt() def help_become_user(self): display.display("Set the user for use with privilege escalation (which remote user attempts to 'become' when become is enabled)") def do_become_method(self, arg): """Given a become_method, set the privilege escalation method when using become""" if arg: self.become_method = arg display.v("become_method changed to %s" % self.become_method) else: display.display("Please specify a become_method, e.g. `become_method su`") display.v("Current become_method is %s" % self.become_method) def help_become_method(self): display.display("Set the privilege escalation plugin to use when become is enabled") def do_check(self, arg): """Toggle whether plays run with check mode""" if arg: self.check_mode = boolean(arg, strict=False) display.display("check mode changed to %s" % self.check_mode) else: display.display("Please specify check mode value, e.g. `check yes`") display.v("check mode is currently %s." % self.check_mode) def help_check(self): display.display("Toggle check_mode for the tasks") def do_diff(self, arg): """Toggle whether plays run with diff""" if arg: self.diff = boolean(arg, strict=False) display.display("diff mode changed to %s" % self.diff) else: display.display("Please specify a diff value , e.g. `diff yes`") display.v("diff mode is currently %s" % self.diff) def help_diff(self): display.display("Toggle diff output for the tasks") def do_timeout(self, arg): """Set the timeout""" if arg: try: timeout = int(arg) if timeout < 0: display.error('The timeout must be greater than or equal to 1, use 0 to disable') else: self.task_timeout = timeout except (TypeError, ValueError) as e: display.error('The timeout must be a valid positive integer, or 0 to disable: %s' % to_text(e)) else: self.usage_timeout() def help_timeout(self): display.display("Set task timeout in seconds") self.usage_timeout() def usage_timeout(self): display.display('Usage: timeout ') def do_exit(self, args): """Exits from the console""" sys.stdout.write('\nAnsible-console was exited.\n') return -1 def help_exit(self): display.display("LEAVE!") do_EOF = do_exit help_EOF = help_exit def helpdefault(self, module_name): if module_name: in_path = module_loader.find_plugin(module_name) if in_path: oc, a, _dummy1, _dummy2 = plugin_docs.get_docstring(in_path, fragment_loader) if oc: display.display(oc['short_description']) display.display('Parameters:') for opt in oc['options'].keys(): display.display(' ' + stringc(opt, self.NORMAL_PROMPT) + ' ' + oc['options'][opt]['description'][0]) else: display.error('No documentation found for %s.' % module_name) else: display.error('%s is not a valid command, use ? to list all valid commands.' % module_name) def help_help(self): display.warning("Don't be redundant!") def complete_cd(self, text, line, begidx, endidx): mline = line.partition(' ')[2] offs = len(mline) - len(text) if self.cwd in ('all', '*', '\\'): completions = self.hosts + self.groups else: completions = [x.name for x in self.inventory.list_hosts(self.cwd)] return [to_native(s)[offs:] for s in completions if to_native(s).startswith(to_native(mline))] def completedefault(self, text, line, begidx, endidx): if line.split()[0] in self.list_modules(): mline = line.split(' ')[-1] offs = len(mline) - len(text) completions = self.module_args(line.split()[0]) return [s[offs:] + '=' for s in completions if s.startswith(mline)] def module_args(self, module_name): in_path = module_loader.find_plugin(module_name) oc, a, _dummy1, _dummy2 = plugin_docs.get_docstring(in_path, fragment_loader, is_module=True) return list(oc['options'].keys()) def run(self): super(ConsoleCLI, self).run() sshpass = None becomepass = None # hosts self.pattern = context.CLIARGS['pattern'] self.cwd = self.pattern # Defaults from the command line self.remote_user = context.CLIARGS['remote_user'] self.become = context.CLIARGS['become'] self.become_user = context.CLIARGS['become_user'] self.become_method = context.CLIARGS['become_method'] self.check_mode = context.CLIARGS['check'] self.diff = context.CLIARGS['diff'] self.forks = context.CLIARGS['forks'] self.task_timeout = context.CLIARGS['task_timeout'] # set module path if needed if context.CLIARGS['module_path']: for path in context.CLIARGS['module_path']: if path: module_loader.add_directory(path) # dynamically add 'canonical' modules as commands, aliases could be used and dynamically loaded self.modules = self.list_modules() for module in self.modules: setattr(self, 'do_' + module, lambda arg, module=module: self.default(module + ' ' + arg)) setattr(self, 'help_' + module, lambda module=module: self.helpdefault(module)) (sshpass, becomepass) = self.ask_passwords() self.passwords = {'conn_pass': sshpass, 'become_pass': becomepass} self.loader, self.inventory, self.variable_manager = self._play_prereqs() hosts = self.get_host_list(self.inventory, context.CLIARGS['subset'], self.pattern) self.groups = self.inventory.list_groups() self.hosts = [x.name for x in hosts] # This hack is to work around readline issues on a mac: # http://stackoverflow.com/a/7116997/541202 if 'libedit' in readline.__doc__: readline.parse_and_bind("bind ^I rl_complete") else: readline.parse_and_bind("tab: complete") histfile = os.path.join(os.path.expanduser("~"), ".ansible-console_history") try: readline.read_history_file(histfile) except IOError: pass atexit.register(readline.write_history_file, histfile) self.set_prompt() self.cmdloop() def __getattr__(self, name): """ handle not found to populate dynamically a module function if module matching name exists """ attr = None if name.startswith('do_'): module = name.replace('do_', '') if module_loader.find_plugin(module): setattr(self, name, lambda arg, module=module: self.default(module + ' ' + arg)) attr = object.__getattr__(self, name) elif name.startswith('help_'): module = name.replace('help_', '') if module_loader.find_plugin(module): setattr(self, name, lambda module=module: self.helpdefault(module)) attr = object.__getattr__(self, name) if attr is None: raise AttributeError(f"{self.__class__} does not have a {name} attribute") return attr def main(args=None): ConsoleCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/doc.py0000755000000000000000000021710315017704211017273 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2014, James Tanner # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import collections.abc import importlib import pkgutil import os import os.path import re import textwrap import typing as t import yaml import ansible.plugins.loader as plugin_loader from pathlib import Path from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.collections.list import list_collection_dirs from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError, AnsiblePluginNotFound from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.yaml import yaml_dump from ansible.module_utils.six import string_types from ansible.parsing.plugin_docs import read_docstub from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.parsing.yaml.loader import AnsibleLoader from ansible._internal._yaml._loader import AnsibleInstrumentedLoader from ansible.plugins.list import _list_plugins_with_info, _PluginDocMetadata from ansible.plugins.loader import action_loader, fragment_loader from ansible.utils.collection_loader import AnsibleCollectionConfig, AnsibleCollectionRef from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path from ansible.utils.color import stringc from ansible.utils.display import Display from ansible.utils.plugin_docs import get_plugin_docs, get_docstring, get_versioned_doclink from ansible.template import trust_as_template from ansible._internal import _json from ansible._internal._templating import _jinja_plugins display = Display() TARGET_OPTIONS = C.DOCUMENTABLE_PLUGINS + ('role', 'keyword',) PB_OBJECTS = ['Play', 'Role', 'Block', 'Task', 'Handler'] PB_LOADED = {} SNIPPETS = ['inventory', 'lookup', 'module'] # hardcoded from ascii values STYLE = { 'BLINK': '\033[5m', 'BOLD': '\033[1m', 'HIDE': '\033[8m', # 'NORMAL': '\x01b[0m', # newer? 'NORMAL': '\033[0m', 'RESET': "\033[0;0m", # 'REVERSE':"\033[;7m", # newer? 'REVERSE': "\033[7m", 'UNDERLINE': '\033[4m', } # previously existing string identifiers NOCOLOR = { 'BOLD': r'*%s*', 'UNDERLINE': r'`%s`', 'MODULE': r'[%s]', 'PLUGIN': r'[%s]', } ref_style = { 'MODULE': C.COLOR_DOC_MODULE, 'REF': C.COLOR_DOC_REFERENCE, 'LINK': C.COLOR_DOC_LINK, 'DEP': C.COLOR_DOC_DEPRECATED, 'CONSTANT': C.COLOR_DOC_CONSTANT, 'PLUGIN': C.COLOR_DOC_PLUGIN, } def jdump(text): try: display.display(_json.json_dumps_formatted(text)) except TypeError as ex: raise AnsibleError('We could not convert all the documentation into JSON as there was a conversion issue.') from ex class RoleMixin(object): """A mixin containing all methods relevant to role argument specification functionality. Note: The methods for actual display of role data are not present here. """ # Potential locations of the role arg spec file in the meta subdir, with main.yml # having the lowest priority. ROLE_METADATA_FILES = ["main" + e for e in C.YAML_FILENAME_EXTENSIONS] ROLE_ARGSPEC_FILES = ['argument_specs' + e for e in C.YAML_FILENAME_EXTENSIONS] + ROLE_METADATA_FILES def _load_role_data(self, root, files, role_name, collection): """ Load and process the YAML for the first found of a set of role files :param str root: The root path to get the files from :param list files: List of candidate file names in order of precedence :param str role_name: The name of the role for which we want the argspec data. :param str collection: collection name or None in case of stand alone roles :returns: A dict that contains the data requested, empty if no data found """ if collection: meta_path = os.path.join(root, 'roles', role_name, 'meta') else: meta_path = os.path.join(root, 'meta') # Check all potential spec files path = None for specfile in files: full_path = os.path.join(meta_path, specfile) if os.path.exists(full_path): path = full_path break if path is None: return {} try: with open(path, 'r') as f: data = yaml.load(trust_as_template(f), Loader=AnsibleLoader) if data is None: data = {} except (IOError, OSError) as ex: raise AnsibleParserError(f"Could not read the role {role_name!r} (at {path}).") from ex return data def _load_metadata(self, role_name, role_path, collection): """Load the roles metadata from the source file. :param str role_name: The name of the role for which we want the argspec data. :param str role_path: Path to the role/collection root. :param str collection: collection name or None in case of stand alone roles :returns: A dict of all role meta data, except ``argument_specs`` or an empty dict """ data = self._load_role_data(role_path, self.ROLE_METADATA_FILES, role_name, collection) del data['argument_specs'] return data def _load_argspec(self, role_name, role_path, collection): """Load the role argument spec data from the source file. :param str role_name: The name of the role for which we want the argspec data. :param str role_path: Path to the role/collection root. :param str collection: collection name or None in case of stand alone roles We support two files containing the role arg spec data: either meta/main.yml or meta/argument_spec.yml. The argument_spec.yml file will take precedence over the meta/main.yml file, if it exists. Data is NOT combined between the two files. :returns: A dict of all data underneath the ``argument_specs`` top-level YAML key in the argspec data file. Empty dict is returned if there is no data. """ try: data = self._load_role_data(role_path, self.ROLE_ARGSPEC_FILES, role_name, collection) data = data.get('argument_specs', {}) except Exception as e: # we keep error info, but let caller deal with it data = {'error': 'Failed to process role (%s): %s' % (role_name, to_native(e)), 'exception': e} return data def _find_all_normal_roles(self, role_paths, name_filters=None): """Find all non-collection roles that have an argument spec file. Note that argument specs do not actually need to exist within the spec file. :param role_paths: A tuple of one or more role paths. When a role with the same name is found in multiple paths, only the first-found role is returned. :param name_filters: A tuple of one or more role names used to filter the results. :returns: A set of tuples consisting of: role name, full role path """ found = set() found_names = set() for path in role_paths: if not os.path.isdir(path): continue # Check each subdir for an argument spec file for entry in os.listdir(path): role_path = os.path.join(path, entry) # Check all potential spec files for specfile in self.ROLE_ARGSPEC_FILES: full_path = os.path.join(role_path, 'meta', specfile) if os.path.exists(full_path): if name_filters is None or entry in name_filters: # select first-found role if entry not in found_names: found_names.add(entry) # None here stands for 'colleciton', which stand alone roles dont have # makes downstream code simpler by having same structure as collection roles found.add((entry, None, role_path)) # only read first existing spec break return found def _find_all_collection_roles(self, name_filters=None, collection_filter=None): """Find all collection roles with an argument spec file. Note that argument specs do not actually need to exist within the spec file. :param name_filters: A tuple of one or more role names used to filter the results. These might be fully qualified with the collection name (e.g., community.general.roleA) or not (e.g., roleA). :param collection_filter: A list of strings containing the FQCN of a collection which will be used to limit results. This filter will take precedence over the name_filters. :returns: A set of tuples consisting of: role name, collection name, collection path """ found = set() b_colldirs = list_collection_dirs(coll_filter=collection_filter) for b_path in b_colldirs: path = to_text(b_path, errors='surrogate_or_strict') collname = _get_collection_name_from_path(b_path) roles_dir = os.path.join(path, 'roles') if os.path.exists(roles_dir): for entry in os.listdir(roles_dir): # Check all potential spec files for specfile in self.ROLE_ARGSPEC_FILES: full_path = os.path.join(roles_dir, entry, 'meta', specfile) if os.path.exists(full_path): if name_filters is None: found.add((entry, collname, path)) else: # Name filters might contain a collection FQCN or not. for fqcn in name_filters: if len(fqcn.split('.')) == 3: (ns, col, role) = fqcn.split('.') if '.'.join([ns, col]) == collname and entry == role: found.add((entry, collname, path)) elif fqcn == entry: found.add((entry, collname, path)) break return found def _build_summary(self, role, collection, meta, argspec): """Build a summary dict for a role. Returns a simplified role arg spec containing only the role entry points and their short descriptions, and the role collection name (if applicable). :param role: The simple role name. :param collection: The collection containing the role (None or empty string if N/A). :param meta: dictionary with galaxy information (None or empty string if N/A). :param argspec: The complete role argspec data dict. :returns: A tuple with the FQCN role name and a summary dict. """ if meta and meta.get('galaxy_info'): summary = meta['galaxy_info'] else: summary = {'description': 'UNDOCUMENTED'} summary['entry_points'] = {} if collection: fqcn = '.'.join([collection, role]) summary['collection'] = collection else: fqcn = role for ep in argspec.keys(): entry_spec = argspec[ep] or {} summary['entry_points'][ep] = entry_spec.get('short_description', '') return (fqcn, summary) def _build_doc(self, role, path, collection, argspec, entry_point): if collection: fqcn = '.'.join([collection, role]) else: fqcn = role doc = {} doc['path'] = path doc['collection'] = collection if 'error' in argspec: doc.update(argspec) else: doc['entry_points'] = {} for ep in argspec.keys(): if entry_point is None or ep == entry_point: entry_spec = argspec[ep] or {} doc['entry_points'][ep] = entry_spec # If we didn't add any entry points (b/c of filtering), ignore this entry. if len(doc['entry_points'].keys()) == 0: doc = None return (fqcn, doc) def _create_role_list(self, fail_on_errors=True): """Return a dict describing the listing of all roles with arg specs. :param role_paths: A tuple of one or more role paths. :returns: A dict indexed by role name, with 'collection' and 'entry_points' keys per role. Example return: results = { 'roleA': { 'collection': '', 'entry_points': { 'main': 'Short description for main' } }, 'a.b.c.roleB': { 'collection': 'a.b.c', 'entry_points': { 'main': 'Short description for main', 'alternate': 'Short description for alternate entry point' } 'x.y.z.roleB': { 'collection': 'x.y.z', 'entry_points': { 'main': 'Short description for main', } }, } """ roles_path = self._get_roles_path() collection_filter = self._get_collection_filter() if not collection_filter: roles = self._find_all_normal_roles(roles_path) else: roles = set() collroles = self._find_all_collection_roles(collection_filter=collection_filter) result = {} for role, collection, role_path in (roles | collroles): try: meta = self._load_metadata(role, role_path, collection) except Exception as e: display.vvv('No metadata for role (%s) due to: %s' % (role, to_native(e)), True) meta = {} argspec = self._load_argspec(role, role_path, collection) if 'error' in argspec: if fail_on_errors: raise argspec['exception'] else: display.warning('Skipping role (%s) due to: %s' % (role, argspec['error']), True) continue fqcn, summary = self._build_summary(role, collection, meta, argspec) result[fqcn] = summary return result def _create_role_doc(self, role_names, entry_point=None, fail_on_errors=True): """ :param role_names: A tuple of one or more role names. :param role_paths: A tuple of one or more role paths. :param entry_point: A role entry point name for filtering. :param fail_on_errors: When set to False, include errors in the JSON output instead of raising errors :returns: A dict indexed by role name, with 'collection', 'entry_points', and 'path' keys per role. """ roles_path = self._get_roles_path() roles = self._find_all_normal_roles(roles_path, name_filters=role_names) collroles = self._find_all_collection_roles(name_filters=role_names) result = {} for role, collection, role_path in (roles | collroles): argspec = self._load_argspec(role, role_path, collection) if 'error' in argspec: if fail_on_errors: raise argspec['exception'] else: display.warning('Skipping role (%s) due to: %s' % (role, argspec['error']), True) continue fqcn, doc = self._build_doc(role, role_path, collection, argspec, entry_point) if doc: result[fqcn] = doc return result def _doclink(url): # assume that if it is relative, it is for docsite, ignore rest if not url.startswith(("http", "..")): url = get_versioned_doclink(url) return url def _format(string, *args): """ add ascii formatting or delimiters """ for style in args: if style not in ref_style and style.upper() not in STYLE and style not in C.COLOR_CODES: raise KeyError("Invalid format value supplied: %s" % style) if C.ANSIBLE_NOCOLOR: # ignore most styles, but some already had 'identifier strings' if style in NOCOLOR: string = NOCOLOR[style] % string elif style in C.COLOR_CODES: string = stringc(string, style) elif style in ref_style: # assumes refs are also always colors string = stringc(string, ref_style[style]) else: # start specific style and 'end' with normal string = '%s%s%s' % (STYLE[style.upper()], string, STYLE['NORMAL']) return string class DocCLI(CLI, RoleMixin): """ displays information on modules installed in Ansible libraries. It displays a terse listing of plugins and their short descriptions, provides a printout of their DOCUMENTATION strings, and it can create a short "snippet" which can be pasted into a playbook. """ name = 'ansible-doc' # default ignore list for detailed views IGNORE = ('module', 'docuri', 'version_added', 'version_added_collection', 'short_description', 'now_date', 'plainexamples', 'returndocs', 'collection', 'plugin_name') # Warning: If you add more elements here, you also need to add it to the docsite build (in the # ansible-community/antsibull repo) _ITALIC = re.compile(r"\bI\(([^)]+)\)") _BOLD = re.compile(r"\bB\(([^)]+)\)") _MODULE = re.compile(r"\bM\(([^)]+)\)") _PLUGIN = re.compile(r"\bP\(([^#)]+)#([a-z]+)\)") _LINK = re.compile(r"\bL\(([^)]+), *([^)]+)\)") _URL = re.compile(r"\bU\(([^)]+)\)") _REF = re.compile(r"\bR\(([^)]+), *([^)]+)\)") _CONST = re.compile(r"\bC\(([^)]+)\)") _SEM_PARAMETER_STRING = r"\(((?:[^\\)]+|\\.)+)\)" _SEM_OPTION_NAME = re.compile(r"\bO" + _SEM_PARAMETER_STRING) _SEM_OPTION_VALUE = re.compile(r"\bV" + _SEM_PARAMETER_STRING) _SEM_ENV_VARIABLE = re.compile(r"\bE" + _SEM_PARAMETER_STRING) _SEM_RET_VALUE = re.compile(r"\bRV" + _SEM_PARAMETER_STRING) _RULER = re.compile(r"\bHORIZONTALLINE\b") # helper for unescaping _UNESCAPE = re.compile(r"\\(.)") _FQCN_TYPE_PREFIX_RE = re.compile(r'^([^.]+\.[^.]+\.[^#]+)#([a-z]+):(.*)$') _IGNORE_MARKER = 'ignore:' # rst specific _RST_NOTE = re.compile(r".. note::") _RST_SEEALSO = re.compile(r".. seealso::") _RST_ROLES = re.compile(r":\w+?:`") _RST_DIRECTIVES = re.compile(r".. \w+?::") def __init__(self, args): super(DocCLI, self).__init__(args) self.plugin_list = set() @staticmethod def _tty_ify_sem_simle(matcher): text = DocCLI._UNESCAPE.sub(r'\1', matcher.group(1)) return f"`{text}'" @staticmethod def _tty_ify_sem_complex(matcher): text = DocCLI._UNESCAPE.sub(r'\1', matcher.group(1)) value = None if '=' in text: text, value = text.split('=', 1) m = DocCLI._FQCN_TYPE_PREFIX_RE.match(text) if m: plugin_fqcn = m.group(1) plugin_type = m.group(2) text = m.group(3) elif text.startswith(DocCLI._IGNORE_MARKER): text = text[len(DocCLI._IGNORE_MARKER):] plugin_fqcn = plugin_type = '' else: plugin_fqcn = plugin_type = '' entrypoint = None if ':' in text: entrypoint, text = text.split(':', 1) if value is not None: text = f"{text}={value}" if plugin_fqcn and plugin_type: plugin_suffix = '' if plugin_type in ('role', 'module', 'playbook') else ' plugin' plugin = f"{plugin_type}{plugin_suffix} {plugin_fqcn}" if plugin_type == 'role' and entrypoint is not None: plugin = f"{plugin}, {entrypoint} entrypoint" return f"`{text}' (of {plugin})" return f"`{text}'" @classmethod def tty_ify(cls, text): # general formatting t = cls._ITALIC.sub(_format(r"\1", 'UNDERLINE'), text) # no ascii code for this t = cls._BOLD.sub(_format(r"\1", 'BOLD'), t) t = cls._MODULE.sub(_format(r"\1", 'MODULE'), t) # M(word) => [word] t = cls._URL.sub(r"\1", t) # U(word) => word t = cls._LINK.sub(r"\1 <\2>", t) # L(word, url) => word t = cls._PLUGIN.sub(_format("[" + r"\1" + "]", 'PLUGIN'), t) # P(word#type) => [word] t = cls._REF.sub(_format(r"\1", 'REF'), t) # R(word, sphinx-ref) => word t = cls._CONST.sub(_format(r"`\1'", 'CONSTANT'), t) t = cls._SEM_OPTION_NAME.sub(cls._tty_ify_sem_complex, t) # O(expr) t = cls._SEM_OPTION_VALUE.sub(cls._tty_ify_sem_simle, t) # V(expr) t = cls._SEM_ENV_VARIABLE.sub(cls._tty_ify_sem_simle, t) # E(expr) t = cls._SEM_RET_VALUE.sub(cls._tty_ify_sem_complex, t) # RV(expr) t = cls._RULER.sub("\n{0}\n".format("-" * 13), t) # HORIZONTALLINE => ------- # remove rst t = cls._RST_SEEALSO.sub(r"See also:", t) # seealso to See also: t = cls._RST_NOTE.sub(_format(r"Note:", 'bold'), t) # .. note:: to note: t = cls._RST_ROLES.sub(r"`", t) # remove :ref: and other tags, keep tilde to match ending one t = cls._RST_DIRECTIVES.sub(r"", t) # remove .. stuff:: in general # handle docsite refs # U(word) => word t = re.sub(cls._URL, lambda m: _format(r"%s" % _doclink(m.group(1)), 'LINK'), t) # L(word, url) => word t = re.sub(cls._LINK, lambda m: r"%s <%s>" % (m.group(1), _format(_doclink(m.group(2)), 'LINK')), t) return t def init_parser(self): coll_filter = 'A supplied argument will be used for filtering, can be a namespace or full collection name.' super(DocCLI, self).init_parser( desc="plugin documentation tool", epilog="See man pages for Ansible CLI options or website for tutorials https://docs.ansible.com" ) opt_help.add_module_options(self.parser) opt_help.add_basedir_options(self.parser) # targets self.parser.add_argument('args', nargs='*', help='Plugin', metavar='plugin') self.parser.add_argument("-t", "--type", action="store", default='module', dest='type', help='Choose which plugin type (defaults to "module"). ' 'Available plugin types are : {0}'.format(TARGET_OPTIONS), choices=TARGET_OPTIONS) # formatting self.parser.add_argument("-j", "--json", action="store_true", default=False, dest='json_format', help='Change output into json format.') # TODO: warn if not used with -t roles # role-specific options self.parser.add_argument("-r", "--roles-path", dest='roles_path', default=C.DEFAULT_ROLES_PATH, type=opt_help.unfrack_path(pathsep=True), action=opt_help.PrependListAction, help='The path to the directory containing your roles.') # exclusive modifiers exclusive = self.parser.add_mutually_exclusive_group() # TODO: warn if not used with -t roles exclusive.add_argument("-e", "--entry-point", dest="entry_point", help="Select the entry point for role(s).") # TODO: warn with --json as it is incompatible exclusive.add_argument("-s", "--snippet", action="store_true", default=False, dest='show_snippet', help='Show playbook snippet for these plugin types: %s' % ', '.join(SNIPPETS)) # TODO: warn when arg/plugin is passed exclusive.add_argument("-F", "--list_files", action="store_true", default=False, dest="list_files", help='Show plugin names and their source files without summaries (implies --list). %s' % coll_filter) exclusive.add_argument("-l", "--list", action="store_true", default=False, dest='list_dir', help='List available plugins. %s' % coll_filter) exclusive.add_argument("--metadata-dump", action="store_true", default=False, dest='dump', help='**For internal use only** Dump json metadata for all entries, ignores other options.') # generic again self.parser.add_argument("--no-fail-on-errors", action="store_true", default=False, dest='no_fail_on_errors', help='**For internal use only** Only used for --metadata-dump. ' 'Do not fail on errors. Report the error message in the JSON instead.') def post_process_args(self, options): options = super(DocCLI, self).post_process_args(options) display.verbosity = options.verbosity return options def display_plugin_list(self, results): # format for user displace = max(len(x) for x in results.keys()) linelimit = display.columns - displace - 5 text = [] deprecated = [] # format display per option if context.CLIARGS['list_files']: # list plugin file names for plugin in sorted(results.keys()): filename = to_native(results[plugin]) # handle deprecated for builtin/legacy pbreak = plugin.split('.') if pbreak[-1].startswith('_') and pbreak[0] == 'ansible' and pbreak[1] in ('builtin', 'legacy'): pbreak[-1] = pbreak[-1][1:] plugin = '.'.join(pbreak) deprecated.append("%-*s %-*.*s" % (displace, plugin, linelimit, len(filename), filename)) else: text.append("%-*s %-*.*s" % (displace, plugin, linelimit, len(filename), filename)) else: # list plugin names and short desc for plugin in sorted(results.keys()): desc = DocCLI.tty_ify(results[plugin]) if len(desc) > linelimit: desc = desc[:linelimit] + '...' pbreak = plugin.split('.') # TODO: add mark for deprecated collection plugins if pbreak[-1].startswith('_') and plugin.startswith(('ansible.builtin.', 'ansible.legacy.')): # Handle deprecated ansible.builtin plugins pbreak[-1] = pbreak[-1][1:] plugin = '.'.join(pbreak) deprecated.append("%-*s %-*.*s" % (displace, plugin, linelimit, len(desc), desc)) else: text.append("%-*s %-*.*s" % (displace, plugin, linelimit, len(desc), desc)) if len(deprecated) > 0: text.append("\nDEPRECATED:") text.extend(deprecated) # display results DocCLI.pager("\n".join(text)) def _display_available_roles(self, list_json): """Display all roles we can find with a valid argument specification. Output is: fqcn role name, entry point, short description """ roles = list(list_json.keys()) entry_point_names = set() # to find max len for role in roles: for entry_point in list_json[role]['entry_points'].keys(): entry_point_names.add(entry_point) max_role_len = 0 max_ep_len = 0 if entry_point_names: max_ep_len = max(len(x) for x in entry_point_names) linelimit = display.columns - max_role_len - max_ep_len - 5 text = [] for role in sorted(roles): if list_json[role]['entry_points']: text.append('%s:' % role) text.append(' specs:') for entry_point, desc in list_json[role]['entry_points'].items(): if len(desc) > linelimit: desc = desc[:linelimit] + '...' text.append(" %-*s: %s" % (max_ep_len, entry_point, desc)) else: text.append('%s' % role) # display results DocCLI.pager("\n".join(text)) def _display_role_doc(self, role_json): roles = list(role_json.keys()) text = [] for role in roles: try: if 'error' in role_json[role]: display.warning("Skipping role '%s' due to: %s" % (role, role_json[role]['error']), True) continue text += self.get_role_man_text(role, role_json[role]) except AnsibleError as ex: # TODO: warn and skip role? raise AnsibleParserError(f"Error extracting role docs from {role!r}.") from ex # display results DocCLI.pager("\n".join(text)) @staticmethod def _list_keywords(): return yaml.load(pkgutil.get_data('ansible', 'keyword_desc.yml'), Loader=AnsibleInstrumentedLoader) @staticmethod def _get_keywords_docs(keys): data = {} descs = DocCLI._list_keywords() for key in keys: if key.startswith('with_'): # simplify loops, dont want to handle every with_ combo keyword = 'loop' elif key == 'async': # cause async became reserved in python we had to rename internally keyword = 'async_val' else: keyword = key try: # if no desc, typeerror raised ends this block kdata = {'description': descs[key]} # get playbook objects for keyword and use first to get keyword attributes kdata['applies_to'] = [] for pobj in PB_OBJECTS: if pobj not in PB_LOADED: obj_class = 'ansible.playbook.%s' % pobj.lower() loaded_class = importlib.import_module(obj_class) PB_LOADED[pobj] = getattr(loaded_class, pobj, None) if keyword in PB_LOADED[pobj].fattributes: kdata['applies_to'].append(pobj) # we should only need these once if 'type' not in kdata: fa = PB_LOADED[pobj].fattributes.get(keyword) if getattr(fa, 'private'): kdata = {} raise KeyError kdata['type'] = getattr(fa, 'isa', 'string') if keyword.endswith('when') or keyword in ('until',): # TODO: make this a field attribute property, # would also helps with the warnings on {{}} stacking kdata['template'] = 'implicit' elif getattr(fa, 'static'): kdata['template'] = 'static' else: kdata['template'] = 'explicit' # those that require no processing for visible in ('alias', 'priority'): kdata[visible] = getattr(fa, visible) # remove None keys for k in list(kdata.keys()): if kdata[k] is None: del kdata[k] data[key] = kdata except (AttributeError, KeyError) as ex: display.error_as_warning(f'Skipping invalid keyword {key!r}.', ex) return data def _get_collection_filter(self): coll_filter = None if len(context.CLIARGS['args']) >= 1: coll_filter = context.CLIARGS['args'] for coll_name in coll_filter: if not AnsibleCollectionRef.is_valid_collection_name(coll_name): raise AnsibleError('Invalid collection name (must be of the form namespace.collection): {0}'.format(coll_name)) return coll_filter def _list_plugins(self, plugin_type, content): DocCLI._prep_loader(plugin_type) coll_filter = self._get_collection_filter() plugins = _list_plugins_with_info(plugin_type, coll_filter) # Remove the internal ansible._protomatter plugins if getting all plugins if not coll_filter: plugins = {k: v for k, v in plugins.items() if not k.startswith('ansible._protomatter.')} # get appropriate content depending on option if content == 'dir': results = self._get_plugin_list_descriptions(plugins) elif content == 'files': results = {k: v.path for k, v in plugins.items()} else: results = {k: {} for k in plugins.keys()} self.plugin_list = set() # reset for next iteration return results def _get_plugins_docs(self, plugin_type: str, names: collections.abc.Iterable[str], fail_ok: bool = False, fail_on_errors: bool = True) -> dict[str, dict]: loader = DocCLI._prep_loader(plugin_type) if plugin_type in ('filter', 'test'): jinja2_builtins = _jinja_plugins.get_jinja_builtin_plugin_descriptions(plugin_type) jinja2_builtins.update({name.split('.')[-1]: value for name, value in jinja2_builtins.items()}) # add short-named versions for lookup else: jinja2_builtins = {} # get the docs for plugins in the command line list plugin_docs = {} for plugin in names: doc: dict[str, t.Any] = {} try: doc, plainexamples, returndocs, metadata = self._get_plugin_docs_with_jinja2_builtins( plugin, plugin_type, loader, fragment_loader, jinja2_builtins, ) except AnsiblePluginNotFound as e: display.warning(to_native(e)) continue except Exception as ex: msg = "Missing documentation (or could not parse documentation)" if not fail_on_errors: plugin_docs[plugin] = {'error': f'{msg}: {ex}.'} continue msg = f"{plugin_type} {plugin} {msg}" if fail_ok: display.warning(f'{msg}: {ex}') else: raise AnsibleError(f'{msg}.') from ex if not doc: # The doc section existed but was empty if not fail_on_errors: plugin_docs[plugin] = {'error': 'No valid documentation found'} continue docs = DocCLI._combine_plugin_doc(plugin, plugin_type, doc, plainexamples, returndocs, metadata) if not fail_on_errors: # Check whether JSON serialization would break try: _json.json_dumps_formatted(docs) except Exception as ex: # pylint:disable=broad-except plugin_docs[plugin] = {'error': f'Cannot serialize documentation as JSON: {ex}'} continue plugin_docs[plugin] = docs return plugin_docs def _get_plugin_docs_with_jinja2_builtins( self, plugin_name: str, plugin_type: str, loader: t.Any, fragment_loader: t.Any, jinja_builtins: dict[str, str], ) -> tuple[dict, str | None, dict | None, dict | None]: try: return get_plugin_docs(plugin_name, plugin_type, loader, fragment_loader, (context.CLIARGS['verbosity'] > 0)) except Exception: if (desc := jinja_builtins.get(plugin_name, ...)) is not ...: short_name = plugin_name.split('.')[-1] long_name = f'ansible.builtin.{short_name}' # Dynamically build a doc stub for any Jinja2 builtin plugin we haven't # explicitly documented. doc = dict( collection='ansible.builtin', plugin_name=long_name, filename='', short_description=desc, description=[ desc, '', f"This is the Jinja builtin {plugin_type} plugin {short_name!r}.", f"See: U(https://jinja.palletsprojects.com/en/stable/templates/#jinja-{plugin_type}s.{short_name})", ], ) return doc, None, None, None raise def _get_roles_path(self): """ Add any 'roles' subdir in playbook dir to the roles search path. And as a last resort, add the playbook dir itself. Order being: - 'roles' subdir of playbook dir - DEFAULT_ROLES_PATH (default in cliargs) - playbook dir (basedir) NOTE: This matches logic in RoleDefinition._load_role_path() method. """ roles_path = context.CLIARGS['roles_path'] if context.CLIARGS['basedir'] is not None: subdir = os.path.join(context.CLIARGS['basedir'], "roles") if os.path.isdir(subdir): roles_path = (subdir,) + roles_path roles_path = roles_path + (context.CLIARGS['basedir'],) return roles_path @staticmethod def _prep_loader(plugin_type): """ return a plugint type specific loader """ loader = getattr(plugin_loader, '%s_loader' % plugin_type) # add to plugin paths from command line if context.CLIARGS['basedir'] is not None: loader.add_directory(context.CLIARGS['basedir'], with_subdir=True) if context.CLIARGS['module_path']: for path in context.CLIARGS['module_path']: if path: loader.add_directory(path) # save only top level paths for errors loader._paths = None # reset so we can use subdirs later return loader def run(self): super(DocCLI, self).run() basedir = context.CLIARGS['basedir'] plugin_type = context.CLIARGS['type'].lower() do_json = context.CLIARGS['json_format'] or context.CLIARGS['dump'] listing = context.CLIARGS['list_files'] or context.CLIARGS['list_dir'] no_fail = bool(not context.CLIARGS['no_fail_on_errors']) if context.CLIARGS['list_files']: content = 'files' elif context.CLIARGS['list_dir']: content = 'dir' else: content = None docs = {} if basedir: AnsibleCollectionConfig.playbook_paths = basedir if plugin_type not in TARGET_OPTIONS: raise AnsibleOptionsError("Unknown or undocumentable plugin type: %s" % plugin_type) if context.CLIARGS['dump']: # we always dump all types, ignore restrictions ptypes = TARGET_OPTIONS docs['all'] = {} for ptype in ptypes: if ptype == 'role': roles = self._create_role_list(fail_on_errors=no_fail) docs['all'][ptype] = self._create_role_doc(roles.keys(), context.CLIARGS['entry_point'], fail_on_errors=no_fail) elif ptype == 'keyword': names = DocCLI._list_keywords() docs['all'][ptype] = DocCLI._get_keywords_docs(names.keys()) else: plugin_names = self._list_plugins(ptype, None) docs['all'][ptype] = self._get_plugins_docs(ptype, plugin_names, fail_ok=(ptype in ('test', 'filter')), fail_on_errors=no_fail) # reset list after each type to avoid pollution elif listing: if plugin_type == 'keyword': docs = DocCLI._list_keywords() elif plugin_type == 'role': docs = self._create_role_list(fail_on_errors=False) else: docs = self._list_plugins(plugin_type, content) else: # here we require a name if len(context.CLIARGS['args']) == 0: raise AnsibleOptionsError("Missing name(s), incorrect options passed for detailed documentation.") if plugin_type == 'keyword': docs = DocCLI._get_keywords_docs(context.CLIARGS['args']) elif plugin_type == 'role': docs = self._create_role_doc(context.CLIARGS['args'], context.CLIARGS['entry_point'], fail_on_errors=no_fail) else: # display specific plugin docs docs = self._get_plugins_docs(plugin_type, context.CLIARGS['args']) # Display the docs if do_json: jdump(docs) else: text = [] if plugin_type in C.DOCUMENTABLE_PLUGINS: if listing and docs: self.display_plugin_list(docs) elif context.CLIARGS['show_snippet']: if plugin_type not in SNIPPETS: raise AnsibleError('Snippets are only available for the following plugin' ' types: %s' % ', '.join(SNIPPETS)) for plugin, doc_data in docs.items(): try: textret = DocCLI.format_snippet(plugin, plugin_type, doc_data['doc']) except ValueError as e: display.warning("Unable to construct a snippet for" " '{0}': {1}".format(plugin, to_text(e))) else: text.append(textret) else: # Some changes to how plain text docs are formatted for plugin, doc_data in docs.items(): textret = DocCLI.format_plugin_doc(plugin, plugin_type, doc_data['doc'], doc_data['examples'], doc_data['return'], doc_data['metadata']) if textret: text.append(textret) else: display.warning("No valid documentation was retrieved from '%s'" % plugin) elif plugin_type == 'role': if context.CLIARGS['list_dir'] and docs: self._display_available_roles(docs) elif docs: self._display_role_doc(docs) elif docs: text = DocCLI.tty_ify(DocCLI._dump_yaml(docs)) if text: DocCLI.pager(''.join(text)) return 0 @staticmethod def get_all_plugins_of_type(plugin_type): loader = getattr(plugin_loader, '%s_loader' % plugin_type) paths = loader._get_paths_with_context() plugins = [] for path_context in paths: plugins += _list_plugins_with_info(plugin_type).keys() return sorted(plugins) @staticmethod def get_plugin_metadata(plugin_type, plugin_name): # if the plugin lives in a non-python file (eg, win_X.ps1), require the corresponding python file for docs loader = getattr(plugin_loader, '%s_loader' % plugin_type) result = loader.find_plugin_with_context(plugin_name, mod_type='.py', ignore_deprecated=True, check_aliases=True) if not result.resolved: raise AnsibleError("unable to load {0} plugin named {1} ".format(plugin_type, plugin_name)) filename = result.plugin_resolved_path collection_name = result.plugin_resolved_collection try: doc, __, __, __ = get_docstring(filename, fragment_loader, verbose=(context.CLIARGS['verbosity'] > 0), collection_name=collection_name, plugin_type=plugin_type) except Exception as ex: raise AnsibleError(f"{plugin_type} {plugin_name} at {filename!r} has a documentation formatting error or is missing documentation.") from ex if doc is None: # Removed plugins don't have any documentation return None return dict( name=plugin_name, namespace=DocCLI.namespace_from_plugin_filepath(filename, plugin_name, loader.package_path), description=doc.get('short_description', "UNKNOWN"), version_added=doc.get('version_added', "UNKNOWN") ) @staticmethod def namespace_from_plugin_filepath(filepath, plugin_name, basedir): if not basedir.endswith('/'): basedir += '/' rel_path = filepath.replace(basedir, '') extension_free = os.path.splitext(rel_path)[0] namespace_only = extension_free.rsplit(plugin_name, 1)[0].strip('/_') clean_ns = namespace_only.replace('/', '.') if clean_ns == '': clean_ns = None return clean_ns @staticmethod def _combine_plugin_doc(plugin, plugin_type, doc, plainexamples, returndocs, metadata): # generate extra data if plugin_type == 'module': # is there corresponding action plugin? if plugin in action_loader: doc['has_action'] = True else: doc['has_action'] = False # return everything as one dictionary return {'doc': doc, 'examples': plainexamples, 'return': returndocs, 'metadata': metadata} @staticmethod def format_snippet(plugin, plugin_type, doc): """ return heavily commented plugin use to insert into play """ if plugin_type == 'inventory' and doc.get('options', {}).get('plugin'): # these do not take a yaml config that we can write a snippet for raise ValueError('The {0} inventory plugin does not take YAML type config source' ' that can be used with the "auto" plugin so a snippet cannot be' ' created.'.format(plugin)) text = [] if plugin_type == 'lookup': text = _do_lookup_snippet(doc) elif 'options' in doc: text = _do_yaml_snippet(doc) text.append('') return "\n".join(text) @staticmethod def format_plugin_doc(plugin, plugin_type, doc, plainexamples, returndocs, metadata): collection_name = doc['collection'] # TODO: do we really want this? # add_collection_to_versions_and_dates(doc, '(unknown)', is_module=(plugin_type == 'module')) # remove_current_collection_from_versions_and_dates(doc, collection_name, is_module=(plugin_type == 'module')) # remove_current_collection_from_versions_and_dates( # returndocs, collection_name, is_module=(plugin_type == 'module'), return_docs=True) # assign from other sections doc['plainexamples'] = plainexamples doc['returndocs'] = returndocs doc['metadata'] = metadata try: text = DocCLI.get_man_text(doc, collection_name, plugin_type) except Exception as ex: raise AnsibleError(f"Unable to retrieve documentation from {plugin!r}.") from ex return text def _get_plugin_list_descriptions(self, plugins: dict[str, _PluginDocMetadata]) -> dict[str, str]: descs = {} for plugin, plugin_info in plugins.items(): # TODO: move to plugin itself i.e: plugin.get_desc() doc = None docerror = None if plugin_info.path: filename = Path(to_native(plugin_info.path)) try: doc = read_docstub(filename) except Exception as e: docerror = e # plugin file was empty or had error, lets try other options if doc is None: # handle test/filters that are in file with diff name base = plugin.split('.')[-1] basefile = filename.with_name(base + filename.suffix) for extension in C.DOC_EXTENSIONS: docfile = basefile.with_suffix(extension) try: if docfile.exists(): doc = read_docstub(docfile) except Exception as e: docerror = e # Do a final fallback to see if the plugin is a shadowed Jinja2 plugin # without any explicit documentation. if doc is None and plugin_info.jinja_builtin_short_description: descs[plugin] = plugin_info.jinja_builtin_short_description continue if docerror: display.error_as_warning(f"{plugin} has a documentation formatting error.", exception=docerror) continue if not doc or not isinstance(doc, dict): desc = 'UNDOCUMENTED' else: desc = doc.get('short_description', 'INVALID SHORT DESCRIPTION').strip() descs[plugin] = desc return descs @staticmethod def print_paths(finder): """ Returns a string suitable for printing of the search path """ # Uses a list to get the order right ret = [] for i in finder._get_paths(subdirs=False): i = to_text(i, errors='surrogate_or_strict') if i not in ret: ret.append(i) return os.pathsep.join(ret) @staticmethod def _dump_yaml(struct, flow_style=False): return yaml_dump(struct, default_flow_style=flow_style, default_style="''", Dumper=AnsibleDumper).rstrip('\n') @staticmethod def _indent_lines(text, indent): return DocCLI.tty_ify('\n'.join([indent + line for line in text.split('\n')])) @staticmethod def _format_version_added(version_added, version_added_collection=None): if version_added_collection == 'ansible.builtin': version_added_collection = 'ansible-core' # In ansible-core, version_added can be 'historical' if version_added == 'historical': return 'historical' if version_added_collection: version_added = '%s of %s' % (version_added, version_added_collection) return 'version %s' % (version_added, ) @staticmethod def warp_fill(text, limit, initial_indent='', subsequent_indent='', initial_extra=0, **kwargs): result = [] for paragraph in text.split('\n\n'): wrapped = textwrap.fill(paragraph, limit, initial_indent=initial_indent + ' ' * initial_extra, subsequent_indent=subsequent_indent, break_on_hyphens=False, break_long_words=False, drop_whitespace=True, **kwargs) if initial_extra and wrapped.startswith(' ' * initial_extra): wrapped = wrapped[initial_extra:] result.append(wrapped) initial_indent = subsequent_indent initial_extra = 0 return '\n'.join(result) @staticmethod def add_fields(text, fields, limit, opt_indent, return_values=False, base_indent='', man=False): for o in sorted(fields): # Create a copy so we don't modify the original (in case YAML anchors have been used) opt = dict(fields[o]) # required is used as indicator and removed required = opt.pop('required', False) if not isinstance(required, bool): raise AnsibleError("Incorrect value for 'Required', a boolean is needed.: %s" % required) opt_leadin = ' ' key = '' if required: if C.ANSIBLE_NOCOLOR: opt_leadin = "=" key = "%s%s %s" % (base_indent, opt_leadin, _format(o, 'bold', 'red')) else: if C.ANSIBLE_NOCOLOR: opt_leadin = "-" key = "%s%s %s" % (base_indent, opt_leadin, _format(o, 'yellow')) # description is specifically formatted and can either be string or list of strings if 'description' not in opt: raise AnsibleError("All (sub-)options and return values must have a 'description' field") text.append('') # TODO: push this to top of for and sort by size, create indent on largest key? inline_indent = ' ' * max((len(opt_indent) - len(o)) - len(base_indent), 2) extra_indent = base_indent + ' ' * (len(o) + 3) sub_indent = inline_indent + extra_indent if is_sequence(opt['description']): for entry_idx, entry in enumerate(opt['description'], 1): if not isinstance(entry, string_types): raise AnsibleError("Expected string in description of %s at index %s, got %s" % (o, entry_idx, type(entry))) if entry_idx == 1: text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=inline_indent, subsequent_indent=sub_indent, initial_extra=len(extra_indent))) else: text.append(DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=sub_indent, subsequent_indent=sub_indent)) else: if not isinstance(opt['description'], string_types): raise AnsibleError("Expected string in description of %s, got %s" % (o, type(opt['description']))) text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(opt['description']), limit, initial_indent=inline_indent, subsequent_indent=sub_indent, initial_extra=len(extra_indent))) del opt['description'] suboptions = [] for subkey in ('options', 'suboptions', 'contains', 'spec'): if subkey in opt: suboptions.append((subkey, opt.pop(subkey))) if not required and not return_values and 'default' not in opt: opt['default'] = None # sanitize config items conf = {} for config in ('env', 'ini', 'yaml', 'vars', 'keyword'): if config in opt and opt[config]: # Create a copy so we don't modify the original (in case YAML anchors have been used) conf[config] = [dict(item) for item in opt.pop(config)] for ignore in DocCLI.IGNORE: for item in conf[config]: if display.verbosity > 0 and 'version_added' in item: item['added_in'] = DocCLI._format_version_added(item['version_added'], item.get('version_added_colleciton', 'ansible-core')) if ignore in item: del item[ignore] # reformat cli optoins if 'cli' in opt and opt['cli']: conf['cli'] = [] for cli in opt['cli']: if 'option' not in cli: conf['cli'].append({'name': cli['name'], 'option': '--%s' % cli['name'].replace('_', '-')}) else: conf['cli'].append(cli) del opt['cli'] # add custom header for conf if conf: text.append(DocCLI._indent_lines(DocCLI._dump_yaml({'set_via': conf}), opt_indent)) # these we handle at the end of generic option processing version_added = opt.pop('version_added', None) version_added_collection = opt.pop('version_added_collection', None) # general processing for options for k in sorted(opt): if k.startswith('_'): continue if is_sequence(opt[k]): text.append(DocCLI._indent_lines('%s: %s' % (k, DocCLI._dump_yaml(opt[k], flow_style=True)), opt_indent)) else: text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k: opt[k]}), opt_indent)) if version_added and not man: text.append("%sadded in: %s" % (opt_indent, DocCLI._format_version_added(version_added, version_added_collection))) for subkey, subdata in suboptions: text.append("%s%s:" % (opt_indent, subkey)) DocCLI.add_fields(text, subdata, limit, opt_indent + ' ', return_values, opt_indent) def get_role_man_text(self, role, role_json): """Generate text for the supplied role suitable for display. This is similar to get_man_text(), but roles are different enough that we have a separate method for formatting their display. :param role: The role name. :param role_json: The JSON for the given role as returned from _create_role_doc(). :returns: A array of text suitable for displaying to screen. """ text = [] opt_indent = " " pad = display.columns * 0.20 limit = max(display.columns - int(pad), 70) text.append("> ROLE: %s (%s)" % (_format(role, 'BOLD'), role_json.get('path'))) for entry_point in role_json['entry_points']: doc = role_json['entry_points'][entry_point] desc = '' if doc.get('short_description'): desc = "- %s" % (doc.get('short_description')) text.append('') text.append("ENTRY POINT: %s %s" % (_format(entry_point, "BOLD"), desc)) text.append('') if doc.get('description'): if isinstance(doc['description'], list): descs = doc['description'] else: descs = [doc['description']] for desc in descs: text.append("%s" % DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=opt_indent, subsequent_indent=opt_indent)) text.append('') if doc.get('options'): text.append(_format("Options", 'bold') + " (%s indicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red')) DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent) if doc.get('attributes', False): display.deprecated( f'The role {role}\'s argument spec {entry_point} contains the key "attributes", ' 'which will not be displayed by ansible-doc in the future. ' 'This was unintentionally allowed when plugin attributes were added, ' 'but the feature does not map well to role argument specs.', version='2.20', ) text.append("") text.append(_format("ATTRIBUTES:", 'bold')) for k in doc['attributes'].keys(): text.append('') text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent, subsequent_indent=opt_indent)) text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent)) del doc['attributes'] # generic elements we will handle identically for k in ('author',): if k not in doc: continue text.append('') if isinstance(doc[k], string_types): text.append('%s: %s' % (k.upper(), DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent))) elif isinstance(doc[k], (list, tuple)): text.append('%s: %s' % (k.upper(), ', '.join(doc[k]))) else: # use empty indent since this affects the start of the yaml doc, not it's keys text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k.upper(): doc[k]}), '')) if doc.get('examples', False): text.append('') text.append(_format("EXAMPLES:", 'bold')) if isinstance(doc['examples'], string_types): text.append(doc.pop('examples').strip()) else: try: text.append(yaml_dump(doc.pop('examples'), indent=2, default_flow_style=False)) except Exception as e: raise AnsibleParserError("Unable to parse examples section.") from e return text @staticmethod def get_man_text(doc, collection_name='', plugin_type=''): # Create a copy so we don't modify the original doc = dict(doc) DocCLI.IGNORE = DocCLI.IGNORE + (context.CLIARGS['type'],) opt_indent = " " base_indent = " " text = [] pad = display.columns * 0.20 limit = max(display.columns - int(pad), 70) text.append("> %s %s (%s)" % (plugin_type.upper(), _format(doc.pop('plugin_name'), 'bold'), doc.pop('filename'))) if isinstance(doc['description'], list): descs = doc.pop('description') else: descs = [doc.pop('description')] text.append('') for desc in descs: text.append(DocCLI.warp_fill(DocCLI.tty_ify(desc), limit, initial_indent=base_indent, subsequent_indent=base_indent)) if display.verbosity > 0: doc['added_in'] = DocCLI._format_version_added(doc.pop('version_added', 'historical'), doc.pop('version_added_collection', 'ansible-core')) if doc.get('deprecated', False): text.append(_format("DEPRECATED: ", 'bold', 'DEP')) if isinstance(doc['deprecated'], dict): if 'removed_at_date' not in doc['deprecated'] and 'version' in doc['deprecated'] and 'removed_in' not in doc['deprecated']: doc['deprecated']['removed_in'] = doc['deprecated']['version'] try: text.append('\t' + C.config.get_deprecated_msg_from_config(doc['deprecated'], True, collection_name=collection_name)) except KeyError as e: raise AnsibleError("Invalid deprecation documentation structure.") from e else: text.append("%s" % doc['deprecated']) del doc['deprecated'] if doc.pop('has_action', False): text.append("") text.append(_format(" * note:", 'bold') + " This module has a corresponding action plugin.") if doc.get('options', False): text.append("") text.append(_format("OPTIONS", 'bold') + " (%s indicates it is required):" % ("=" if C.ANSIBLE_NOCOLOR else 'red')) DocCLI.add_fields(text, doc.pop('options'), limit, opt_indent, man=(display.verbosity == 0)) if doc.get('attributes', False): text.append("") text.append(_format("ATTRIBUTES:", 'bold')) for k in doc['attributes'].keys(): text.append('') text.append(DocCLI.warp_fill(DocCLI.tty_ify(_format('%s:' % k, 'UNDERLINE')), limit - 6, initial_indent=opt_indent, subsequent_indent=opt_indent)) text.append(DocCLI._indent_lines(DocCLI._dump_yaml(doc['attributes'][k]), opt_indent)) del doc['attributes'] if doc.get('notes', False): text.append("") text.append(_format("NOTES:", 'bold')) for note in doc['notes']: text.append(DocCLI.warp_fill(DocCLI.tty_ify(note), limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent)) del doc['notes'] if doc.get('seealso', False): text.append("") text.append(_format("SEE ALSO:", 'bold')) for item in doc['seealso']: if 'module' in item: text.append(DocCLI.warp_fill(DocCLI.tty_ify('Module %s' % item['module']), limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent)) description = item.get('description') if description is None and item['module'].startswith('ansible.builtin.'): description = 'The official documentation on the %s module.' % item['module'] if description is not None: text.append(DocCLI.warp_fill(DocCLI.tty_ify(description), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) if item['module'].startswith('ansible.builtin.'): relative_url = 'collections/%s_module.html' % item['module'].replace('.', '/', 2) text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent)) elif 'plugin' in item and 'plugin_type' in item: plugin_suffix = ' plugin' if item['plugin_type'] not in ('module', 'role') else '' text.append(DocCLI.warp_fill(DocCLI.tty_ify('%s%s %s' % (item['plugin_type'].title(), plugin_suffix, item['plugin'])), limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent)) description = item.get('description') if description is None and item['plugin'].startswith('ansible.builtin.'): description = 'The official documentation on the %s %s%s.' % (item['plugin'], item['plugin_type'], plugin_suffix) if description is not None: text.append(DocCLI.warp_fill(DocCLI.tty_ify(description), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) if item['plugin'].startswith('ansible.builtin.'): relative_url = 'collections/%s_%s.html' % (item['plugin'].replace('.', '/', 2), item['plugin_type']) text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink(relative_url)), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent)) elif 'name' in item and 'link' in item and 'description' in item: text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['name']), limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent)) text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['link']), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) elif 'ref' in item and 'description' in item: text.append(DocCLI.warp_fill(DocCLI.tty_ify('Ansible documentation [%s]' % item['ref']), limit - 6, initial_indent=opt_indent[:-2] + "* ", subsequent_indent=opt_indent)) text.append(DocCLI.warp_fill(DocCLI.tty_ify(item['description']), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) text.append(DocCLI.warp_fill(DocCLI.tty_ify(get_versioned_doclink('/#stq=%s&stp=1' % item['ref'])), limit - 6, initial_indent=opt_indent + ' ', subsequent_indent=opt_indent + ' ')) del doc['seealso'] if doc.get('requirements', False): text.append('') req = ", ".join(doc.pop('requirements')) text.append(_format("REQUIREMENTS:", 'bold') + "%s\n" % DocCLI.warp_fill(DocCLI.tty_ify(req), limit - 16, initial_indent=" ", subsequent_indent=opt_indent)) # Generic handler for k in sorted(doc): if not doc[k] or k in DocCLI.IGNORE: continue text.append('') header = _format(k.upper(), 'bold') if isinstance(doc[k], string_types): text.append('%s: %s' % (header, DocCLI.warp_fill(DocCLI.tty_ify(doc[k]), limit - (len(k) + 2), subsequent_indent=opt_indent))) elif isinstance(doc[k], (list, tuple)): text.append('%s: %s' % (header, ', '.join(doc[k]))) else: # use empty indent since this affects the start of the yaml doc, not it's keys text.append('%s: ' % header + DocCLI._indent_lines(DocCLI._dump_yaml(doc[k]), ' ' * (len(k) + 2))) del doc[k] if doc.get('plainexamples', False): text.append('') text.append(_format("EXAMPLES:", 'bold')) if isinstance(doc['plainexamples'], string_types): text.append(doc.pop('plainexamples').strip()) else: try: text.append(yaml_dump(doc.pop('plainexamples'), indent=2, default_flow_style=False)) except Exception as ex: raise AnsibleParserError("Unable to parse examples section.") from ex if doc.get('returndocs', False): text.append('') text.append(_format("RETURN VALUES:", 'bold')) DocCLI.add_fields(text, doc.pop('returndocs'), limit, opt_indent, return_values=True, man=(display.verbosity == 0)) text.append('\n') return "\n".join(text) def _do_yaml_snippet(doc): text = [] mdesc = DocCLI.tty_ify(doc['short_description']) module = doc.get('module') if module: # this is actually a usable task! text.append("- name: %s" % (mdesc)) text.append(" %s:" % (module)) else: # just a comment, hopefully useful yaml file text.append("# %s:" % doc.get('plugin', doc.get('name'))) pad = 29 subdent = '# '.rjust(pad + 2) limit = display.columns - pad for o in sorted(doc['options'].keys()): opt = doc['options'][o] if isinstance(opt['description'], string_types): desc = DocCLI.tty_ify(opt['description']) else: desc = DocCLI.tty_ify(" ".join(opt['description'])) required = opt.get('required', False) if not isinstance(required, bool): raise ValueError("Incorrect value for 'Required', a boolean is needed: %s" % required) o = '%s:' % o if module: if required: desc = "(required) %s" % desc text.append(" %-20s # %s" % (o, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent))) else: if required: default = '(required)' else: default = opt.get('default', 'None') text.append("%s %-9s # %s" % (o, default, DocCLI.warp_fill(desc, limit, subsequent_indent=subdent, max_lines=3))) return text def _do_lookup_snippet(doc): text = [] snippet = "lookup('%s', " % doc.get('plugin', doc.get('name')) comment = [] for o in sorted(doc['options'].keys()): opt = doc['options'][o] comment.append('# %s(%s): %s' % (o, opt.get('type', 'string'), opt.get('description', ''))) if o in ('_terms', '_raw', '_list'): # these are 'list of arguments' snippet += '< %s >' % (o) continue required = opt.get('required', False) if not isinstance(required, bool): raise ValueError("Incorrect value for 'Required', a boolean is needed: %s" % required) if required: default = '' else: default = opt.get('default', 'None') if opt.get('type') in ('string', 'str'): snippet += ", %s='%s'" % (o, default) else: snippet += ', %s=%s' % (o, default) snippet += ")" if comment: text.extend(comment) text.append('') text.append(snippet) return text def main(args=None): DocCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/galaxy.py0000755000000000000000000027201615017704211020017 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2013, James Cammarata # Copyright: (c) 2018-2021, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import argparse import functools import json import os.path import pathlib import re import shutil import sys import textwrap import time import typing as t from dataclasses import dataclass from yaml.error import YAMLError import ansible.constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.galaxy import Galaxy, get_collections_galaxy_meta_info from ansible.galaxy.api import GalaxyAPI, GalaxyError from ansible.galaxy.collection import ( build_collection, download_collections, find_existing_collections, install_collections, publish_collection, validate_collection_name, validate_collection_path, verify_collections, SIGNATURE_COUNT_RE, ) from ansible.galaxy.collection.concrete_artifact_manager import ( ConcreteArtifactsManager, ) from ansible.galaxy.collection.gpg import GPG_ERROR_MAP from ansible.galaxy.dependency_resolution.dataclasses import Requirement from ansible.galaxy.role import GalaxyRole from ansible.galaxy.token import BasicAuthToken, GalaxyToken, KeycloakToken, NoTokenSentinel from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.module_utils.common.collections import is_iterable from ansible.module_utils.common.yaml import yaml_dump, yaml_load from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible._internal._datatag._tags import TrustedAsTemplate from ansible.module_utils import six from ansible.parsing.dataloader import DataLoader from ansible.playbook.role.requirement import RoleRequirement from ansible._internal._templating._engine import TemplateEngine from ansible.template import trust_as_template from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.display import Display from ansible.utils.plugin_docs import get_versioned_doclink from ansible.utils.vars import load_extra_vars display = Display() urlparse = six.moves.urllib.parse.urlparse def with_collection_artifacts_manager(wrapped_method): """Inject an artifacts manager if not passed explicitly. This decorator constructs a ConcreteArtifactsManager and maintains the related temporary directory auto-cleanup around the target method invocation. """ @functools.wraps(wrapped_method) def method_wrapper(*args, **kwargs): if 'artifacts_manager' in kwargs: return wrapped_method(*args, **kwargs) # FIXME: use validate_certs context from Galaxy servers when downloading collections # .get used here for when this is used in a non-CLI context artifacts_manager_kwargs = {'validate_certs': context.CLIARGS.get('resolved_validate_certs', True)} keyring = context.CLIARGS.get('keyring', None) if keyring is not None: artifacts_manager_kwargs.update({ 'keyring': GalaxyCLI._resolve_path(keyring), 'required_signature_count': context.CLIARGS.get('required_valid_signature_count', None), 'ignore_signature_errors': context.CLIARGS.get('ignore_gpg_errors', None), }) with ConcreteArtifactsManager.under_tmpdir( C.DEFAULT_LOCAL_TMP, **artifacts_manager_kwargs ) as concrete_artifact_cm: kwargs['artifacts_manager'] = concrete_artifact_cm return wrapped_method(*args, **kwargs) return method_wrapper def _display_header(path, h1, h2, w1=10, w2=7): display.display('\n# {0}\n{1:{cwidth}} {2:{vwidth}}\n{3} {4}\n'.format( path, h1, h2, '-' * max([len(h1), w1]), # Make sure that the number of dashes is at least the width of the header '-' * max([len(h2), w2]), cwidth=w1, vwidth=w2, )) def _display_role(gr): install_info = gr.install_info version = None if install_info: version = install_info.get("version", None) if not version: version = "(unknown version)" display.display("- %s, %s" % (gr.name, version)) def _display_collection(collection, cwidth=10, vwidth=7, min_cwidth=10, min_vwidth=7): display.display('{fqcn:{cwidth}} {version:{vwidth}}'.format( fqcn=to_text(collection.fqcn), version=collection.ver, cwidth=max(cwidth, min_cwidth), # Make sure the width isn't smaller than the header vwidth=max(vwidth, min_vwidth) )) def _get_collection_widths(collections): if not is_iterable(collections): collections = (collections, ) fqcn_set = {to_text(c.fqcn) for c in collections} version_set = {to_text(c.ver) for c in collections} fqcn_length = len(max(fqcn_set or [''], key=len)) version_length = len(max(version_set or [''], key=len)) return fqcn_length, version_length def validate_signature_count(value): match = re.match(SIGNATURE_COUNT_RE, value) if match is None: raise ValueError(f"{value} is not a valid signature count value") return value @dataclass class RoleDistributionServer: _api: t.Union[GalaxyAPI, None] api_servers: list[GalaxyAPI] @property def api(self): if self._api: return self._api for server in self.api_servers: try: if u'v1' in server.available_api_versions: self._api = server break except Exception: continue if not self._api: self._api = self.api_servers[0] return self._api class GalaxyCLI(CLI): """Command to manage Ansible roles and collections. None of the CLI tools are designed to run concurrently with themselves. Use an external scheduler and/or locking to ensure there are no clashing operations. """ name = 'ansible-galaxy' SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url") def __init__(self, args): self._raw_args = args self._implicit_role = False if len(args) > 1: # Inject role into sys.argv[1] as a backwards compatibility step if args[1] not in ['-h', '--help', '--version'] and 'role' not in args and 'collection' not in args: # TODO: Should we add a warning here and eventually deprecate the implicit role subcommand choice args.insert(1, 'role') self._implicit_role = True # since argparse doesn't allow hidden subparsers, handle dead login arg from raw args after "role" normalization if args[1:3] == ['role', 'login']: display.error( "The login command was removed in late 2020. An API key is now required to publish roles or collections " "to Galaxy. The key can be found at https://galaxy.ansible.com/me/preferences, and passed to the " "ansible-galaxy CLI via a file at {0} or (insecurely) via the `--token` " "command-line argument.".format(to_text(C.GALAXY_TOKEN_PATH))) sys.exit(1) self.api_servers = [] self.galaxy = None self.lazy_role_api = None super(GalaxyCLI, self).__init__(args) def init_parser(self): """ create an options parser for bin/ansible """ super(GalaxyCLI, self).init_parser( desc="Perform various Role and Collection related operations.", ) # Common arguments that apply to more than 1 action common = opt_help.ArgumentParser(add_help=False) common.add_argument('-s', '--server', dest='api_server', help='The Galaxy API server URL') common.add_argument('--api-version', type=int, choices=[2, 3], help=argparse.SUPPRESS) # Hidden argument that should only be used in our tests common.add_argument('--token', '--api-key', dest='api_key', help='The Ansible Galaxy API key which can be found at ' 'https://galaxy.ansible.com/me/preferences.') common.add_argument('-c', '--ignore-certs', action='store_true', dest='ignore_certs', help='Ignore SSL certificate validation errors.', default=None) # --timeout uses the default None to handle two different scenarios. # * --timeout > C.GALAXY_SERVER_TIMEOUT for non-configured servers # * --timeout > server-specific timeout > C.GALAXY_SERVER_TIMEOUT for configured servers. common.add_argument('--timeout', dest='timeout', type=int, help="The time to wait for operations against the galaxy server, defaults to 60s.") opt_help.add_verbosity_options(common) force = opt_help.ArgumentParser(add_help=False) force.add_argument('-f', '--force', dest='force', action='store_true', default=False, help='Force overwriting an existing role or collection') github = opt_help.ArgumentParser(add_help=False) github.add_argument('github_user', help='GitHub username') github.add_argument('github_repo', help='GitHub repository') offline = opt_help.ArgumentParser(add_help=False) offline.add_argument('--offline', dest='offline', default=False, action='store_true', help="Don't query the galaxy API when creating roles") default_roles_path = C.config.get_configuration_definition('DEFAULT_ROLES_PATH').get('default', '') roles_path = opt_help.ArgumentParser(add_help=False) roles_path.add_argument('-p', '--roles-path', dest='roles_path', type=opt_help.unfrack_path(pathsep=True), default=C.DEFAULT_ROLES_PATH, action=opt_help.PrependListAction, help='The path to the directory containing your roles. The default is the first ' 'writable one configured via DEFAULT_ROLES_PATH: %s ' % default_roles_path) collections_path = opt_help.ArgumentParser(add_help=False) collections_path.add_argument('-p', '--collections-path', dest='collections_path', type=opt_help.unfrack_path(pathsep=True), action=opt_help.PrependListAction, help="One or more directories to search for collections in addition " "to the default COLLECTIONS_PATHS. Separate multiple paths " "with '{0}'.".format(os.path.pathsep)) cache_options = opt_help.ArgumentParser(add_help=False) cache_options.add_argument('--clear-response-cache', dest='clear_response_cache', action='store_true', default=False, help='Clear the existing server response cache.') cache_options.add_argument('--no-cache', dest='no_cache', action='store_true', default=False, help='Do not use the server response cache.') # Add sub parser for the Galaxy role type (role or collection) type_parser = self.parser.add_subparsers(metavar='TYPE', dest='type') type_parser.required = True # Add sub parser for the Galaxy collection actions collection = type_parser.add_parser('collection', help='Manage an Ansible Galaxy collection.') collection.set_defaults(func=self.execute_collection) # to satisfy doc build collection_parser = collection.add_subparsers(metavar='COLLECTION_ACTION', dest='action') collection_parser.required = True self.add_download_options(collection_parser, parents=[common, cache_options]) self.add_init_options(collection_parser, parents=[common, force]) self.add_build_options(collection_parser, parents=[common, force]) self.add_publish_options(collection_parser, parents=[common]) self.add_install_options(collection_parser, parents=[common, force, cache_options]) self.add_list_options(collection_parser, parents=[common, collections_path]) self.add_verify_options(collection_parser, parents=[common, collections_path]) # Add sub parser for the Galaxy role actions role = type_parser.add_parser('role', help='Manage an Ansible Galaxy role.') role.set_defaults(func=self.execute_role) # to satisfy doc build role_parser = role.add_subparsers(metavar='ROLE_ACTION', dest='action') role_parser.required = True self.add_init_options(role_parser, parents=[common, force, offline]) self.add_remove_options(role_parser, parents=[common, roles_path]) self.add_delete_options(role_parser, parents=[common, github]) self.add_list_options(role_parser, parents=[common, roles_path]) self.add_search_options(role_parser, parents=[common]) self.add_import_options(role_parser, parents=[common, github]) self.add_setup_options(role_parser, parents=[common, roles_path]) self.add_info_options(role_parser, parents=[common, roles_path, offline]) self.add_install_options(role_parser, parents=[common, force, roles_path]) def add_download_options(self, parser, parents=None): download_parser = parser.add_parser('download', parents=parents, help='Download collections and their dependencies as a tarball for an ' 'offline install.') download_parser.set_defaults(func=self.execute_download) download_parser.add_argument('args', help='Collection(s)', metavar='collection', nargs='*') download_parser.add_argument('-n', '--no-deps', dest='no_deps', action='store_true', default=False, help="Don't download collection(s) listed as dependencies.") download_parser.add_argument('-p', '--download-path', dest='download_path', default='./collections', help='The directory to download the collections to.') download_parser.add_argument('-r', '--requirements-file', dest='requirements', help='A file containing a list of collections to be downloaded.') download_parser.add_argument('--pre', dest='allow_pre_release', action='store_true', help='Include pre-release versions. Semantic versioning pre-releases are ignored by default') def add_init_options(self, parser, parents=None): galaxy_type = 'collection' if parser.metavar == 'COLLECTION_ACTION' else 'role' init_parser = parser.add_parser('init', parents=parents, help='Initialize new {0} with the base structure of a ' '{0}.'.format(galaxy_type)) init_parser.set_defaults(func=self.execute_init) init_parser.add_argument('--init-path', dest='init_path', default='./', help='The path in which the skeleton {0} will be created. The default is the ' 'current working directory.'.format(galaxy_type)) init_parser.add_argument('--{0}-skeleton'.format(galaxy_type), dest='{0}_skeleton'.format(galaxy_type), default=C.GALAXY_COLLECTION_SKELETON if galaxy_type == 'collection' else C.GALAXY_ROLE_SKELETON, help='The path to a {0} skeleton that the new {0} should be based ' 'upon.'.format(galaxy_type)) obj_name_kwargs = {} if galaxy_type == 'collection': obj_name_kwargs['type'] = validate_collection_name init_parser.add_argument('{0}_name'.format(galaxy_type), help='{0} name'.format(galaxy_type.capitalize()), **obj_name_kwargs) if galaxy_type == 'role': init_parser.add_argument('--type', dest='role_type', action='store', default='default', help="Initialize using an alternate role type. Valid types include: 'container', " "'apb' and 'network'.") opt_help.add_runtask_options(init_parser) def add_remove_options(self, parser, parents=None): remove_parser = parser.add_parser('remove', parents=parents, help='Delete roles from roles_path.') remove_parser.set_defaults(func=self.execute_remove) remove_parser.add_argument('args', help='Role(s)', metavar='role', nargs='+') def add_delete_options(self, parser, parents=None): delete_parser = parser.add_parser('delete', parents=parents, help='Removes the role from Galaxy. It does not remove or alter the actual ' 'GitHub repository.') delete_parser.set_defaults(func=self.execute_delete) def add_list_options(self, parser, parents=None): galaxy_type = 'role' if parser.metavar == 'COLLECTION_ACTION': galaxy_type = 'collection' list_parser = parser.add_parser('list', parents=parents, help='Show the name and version of each {0} installed in the {0}s_path.'.format(galaxy_type)) list_parser.set_defaults(func=self.execute_list) list_parser.add_argument(galaxy_type, help=galaxy_type.capitalize(), nargs='?', metavar=galaxy_type) if galaxy_type == 'collection': list_parser.add_argument('--format', dest='output_format', choices=('human', 'yaml', 'json'), default='human', help="Format to display the list of collections in.") def add_search_options(self, parser, parents=None): search_parser = parser.add_parser('search', parents=parents, help='Search the Galaxy database by tags, platforms, author and multiple ' 'keywords.') search_parser.set_defaults(func=self.execute_search) search_parser.add_argument('--platforms', dest='platforms', help='list of OS platforms to filter by') search_parser.add_argument('--galaxy-tags', dest='galaxy_tags', help='list of galaxy tags to filter by') search_parser.add_argument('--author', dest='author', help='GitHub username') search_parser.add_argument('args', help='Search terms', metavar='searchterm', nargs='*') def add_import_options(self, parser, parents=None): import_parser = parser.add_parser('import', parents=parents, help='Import a role into a galaxy server') import_parser.set_defaults(func=self.execute_import) import_parser.add_argument('--no-wait', dest='wait', action='store_false', default=True, help="Don't wait for import results.") import_parser.add_argument('--branch', dest='reference', help='The name of a branch to import. Defaults to the repository\'s default branch ' '(usually master)') import_parser.add_argument('--role-name', dest='role_name', help='The name the role should have, if different than the repo name') import_parser.add_argument('--status', dest='check_status', action='store_true', default=False, help='Check the status of the most recent import request for given github_' 'user/github_repo.') def add_setup_options(self, parser, parents=None): setup_parser = parser.add_parser('setup', parents=parents, help='Manage the integration between Galaxy and the given source.') setup_parser.set_defaults(func=self.execute_setup) setup_parser.add_argument('--remove', dest='remove_id', default=None, help='Remove the integration matching the provided ID value. Use --list to see ' 'ID values.') setup_parser.add_argument('--list', dest="setup_list", action='store_true', default=False, help='List all of your integrations.') setup_parser.add_argument('source', help='Source') setup_parser.add_argument('github_user', help='GitHub username') setup_parser.add_argument('github_repo', help='GitHub repository') setup_parser.add_argument('secret', help='Secret') def add_info_options(self, parser, parents=None): info_parser = parser.add_parser('info', parents=parents, help='View more details about a specific role.') info_parser.set_defaults(func=self.execute_info) info_parser.add_argument('args', nargs='+', help='role', metavar='role_name[,version]') def add_verify_options(self, parser, parents=None): galaxy_type = 'collection' verify_parser = parser.add_parser('verify', parents=parents, help='Compare checksums with the collection(s) ' 'found on the server and the installed copy. This does not verify dependencies.') verify_parser.set_defaults(func=self.execute_verify) verify_parser.add_argument('args', metavar='{0}_name'.format(galaxy_type), nargs='*', help='The installed collection(s) name. ' 'This is mutually exclusive with --requirements-file.') verify_parser.add_argument('-i', '--ignore-errors', dest='ignore_errors', action='store_true', default=False, help='Ignore errors during verification and continue with the next specified collection.') verify_parser.add_argument('--offline', dest='offline', action='store_true', default=False, help='Validate collection integrity locally without contacting server for ' 'canonical manifest hash.') verify_parser.add_argument('-r', '--requirements-file', dest='requirements', help='A file containing a list of collections to be verified.') verify_parser.add_argument('--keyring', dest='keyring', default=C.GALAXY_GPG_KEYRING, help='The keyring used during signature verification') # Eventually default to ~/.ansible/pubring.kbx? verify_parser.add_argument('--signature', dest='signatures', action='append', help='An additional signature source to verify the authenticity of the MANIFEST.json before using ' 'it to verify the rest of the contents of a collection from a Galaxy server. Use in ' 'conjunction with a positional collection name (mutually exclusive with --requirements-file).') valid_signature_count_help = 'The number of signatures that must successfully verify the collection. This should be a positive integer ' \ 'or all to signify that all signatures must be used to verify the collection. ' \ 'Prepend the value with + to fail if no valid signatures are found for the collection (e.g. +all).' ignore_gpg_status_help = 'A space separated list of status codes to ignore during signature verification (for example, NO_PUBKEY FAILURE). ' \ 'Descriptions for the choices can be seen at L(https://github.com/gpg/gnupg/blob/master/doc/DETAILS#general-status-codes).' \ 'Note: specify these after positional arguments or use -- to separate them.' verify_parser.add_argument('--required-valid-signature-count', dest='required_valid_signature_count', type=validate_signature_count, help=valid_signature_count_help, default=C.GALAXY_REQUIRED_VALID_SIGNATURE_COUNT) verify_parser.add_argument('--ignore-signature-status-code', dest='ignore_gpg_errors', type=str, action='append', help=opt_help.argparse.SUPPRESS, default=C.GALAXY_IGNORE_INVALID_SIGNATURE_STATUS_CODES, choices=list(GPG_ERROR_MAP.keys())) verify_parser.add_argument('--ignore-signature-status-codes', dest='ignore_gpg_errors', type=str, action='extend', nargs='+', help=ignore_gpg_status_help, default=C.GALAXY_IGNORE_INVALID_SIGNATURE_STATUS_CODES, choices=list(GPG_ERROR_MAP.keys())) def add_install_options(self, parser, parents=None): galaxy_type = 'collection' if parser.metavar == 'COLLECTION_ACTION' else 'role' args_kwargs = {} if galaxy_type == 'collection': args_kwargs['help'] = 'The collection(s) name or path/url to a tar.gz collection artifact. This is ' \ 'mutually exclusive with --requirements-file.' ignore_errors_help = 'Ignore errors during installation and continue with the next specified ' \ 'collection. This will not ignore dependency conflict errors.' else: args_kwargs['help'] = 'Role name, URL or tar file. This is mutually exclusive with -r.' ignore_errors_help = 'Ignore errors and continue with the next specified role.' if self._implicit_role: # might install both roles and collections description_text = ( 'Install roles and collections from file(s), URL(s) or Ansible ' 'Galaxy to the first entry in the config COLLECTIONS_PATH for collections ' 'and first entry in the config ROLES_PATH for roles. ' 'The first entry in the config ROLES_PATH can be overridden by --roles-path ' 'or -p, but this will result in only roles being installed.' ) prog = 'ansible-galaxy install' else: prog = f"ansible-galaxy {galaxy_type} install" description_text = ( 'Install {0}(s) from file(s), URL(s) or Ansible ' 'Galaxy to the first entry in the config {1}S_PATH ' 'unless overridden by --{0}s-path.'.format(galaxy_type, galaxy_type.upper()) ) install_parser = parser.add_parser('install', parents=parents, help='Install {0}(s) from file(s), URL(s) or Ansible ' 'Galaxy'.format(galaxy_type), description=description_text, prog=prog,) install_parser.set_defaults(func=self.execute_install) install_parser.add_argument('args', metavar='{0}_name'.format(galaxy_type), nargs='*', **args_kwargs) install_parser.add_argument('-i', '--ignore-errors', dest='ignore_errors', action='store_true', default=False, help=ignore_errors_help) install_exclusive = install_parser.add_mutually_exclusive_group() install_exclusive.add_argument('-n', '--no-deps', dest='no_deps', action='store_true', default=False, help="Don't download {0}s listed as dependencies.".format(galaxy_type)) install_exclusive.add_argument('--force-with-deps', dest='force_with_deps', action='store_true', default=False, help="Force overwriting an existing {0} and its " "dependencies.".format(galaxy_type)) valid_signature_count_help = 'The number of signatures that must successfully verify the collection. This should be a positive integer ' \ 'or -1 to signify that all signatures must be used to verify the collection. ' \ 'Prepend the value with + to fail if no valid signatures are found for the collection (e.g. +all).' ignore_gpg_status_help = 'A space separated list of status codes to ignore during signature verification (for example, NO_PUBKEY FAILURE). ' \ 'Descriptions for the choices can be seen at L(https://github.com/gpg/gnupg/blob/master/doc/DETAILS#general-status-codes).' \ 'Note: specify these after positional arguments or use -- to separate them.' if galaxy_type == 'collection': install_parser.add_argument('-p', '--collections-path', dest='collections_path', default=self._get_default_collection_path(), help='The path to the directory containing your collections.') install_parser.add_argument('-r', '--requirements-file', dest='requirements', help='A file containing a list of collections to be installed.') install_parser.add_argument('--pre', dest='allow_pre_release', action='store_true', help='Include pre-release versions. Semantic versioning pre-releases are ignored by default') install_parser.add_argument('-U', '--upgrade', dest='upgrade', action='store_true', default=False, help='Upgrade installed collection artifacts. This will also update dependencies unless --no-deps is provided') install_parser.add_argument('--keyring', dest='keyring', default=C.GALAXY_GPG_KEYRING, help='The keyring used during signature verification') # Eventually default to ~/.ansible/pubring.kbx? install_parser.add_argument('--disable-gpg-verify', dest='disable_gpg_verify', action='store_true', default=C.GALAXY_DISABLE_GPG_VERIFY, help='Disable GPG signature verification when installing collections from a Galaxy server') install_parser.add_argument('--signature', dest='signatures', action='append', help='An additional signature source to verify the authenticity of the MANIFEST.json before ' 'installing the collection from a Galaxy server. Use in conjunction with a positional ' 'collection name (mutually exclusive with --requirements-file).') install_parser.add_argument('--required-valid-signature-count', dest='required_valid_signature_count', type=validate_signature_count, help=valid_signature_count_help, default=C.GALAXY_REQUIRED_VALID_SIGNATURE_COUNT) install_parser.add_argument('--ignore-signature-status-code', dest='ignore_gpg_errors', type=str, action='append', help=opt_help.argparse.SUPPRESS, default=C.GALAXY_IGNORE_INVALID_SIGNATURE_STATUS_CODES, choices=list(GPG_ERROR_MAP.keys())) install_parser.add_argument('--ignore-signature-status-codes', dest='ignore_gpg_errors', type=str, action='extend', nargs='+', help=ignore_gpg_status_help, default=C.GALAXY_IGNORE_INVALID_SIGNATURE_STATUS_CODES, choices=list(GPG_ERROR_MAP.keys())) install_parser.add_argument('--offline', dest='offline', action='store_true', default=False, help='Install collection artifacts (tarballs) without contacting any distribution servers. ' 'This does not apply to collections in remote Git repositories or URLs to remote tarballs.' ) else: if self._implicit_role: install_parser.add_argument('-r', '--role-file', dest='requirements', help='A file containing a list of collections and roles to be installed.') else: install_parser.add_argument('-r', '--role-file', dest='requirements', help='A file containing a list of roles to be installed.') r_re = re.compile(r'^(?", v) v = const_pattern.sub(r"'\1'", v) return textwrap.fill(v, width=117, initial_indent="# ", subsequent_indent="# ", break_on_hyphens=False) loader = DataLoader() templar = TemplateEngine(loader, variables={'required_config': required_config, 'optional_config': optional_config}) templar.environment.filters['comment_ify'] = comment_ify meta_value = templar.template(meta_template) return meta_value def _require_one_of_collections_requirements( self, collections, requirements_file, signatures=None, artifacts_manager=None, ): if collections and requirements_file: raise AnsibleError("The positional collection_name arg and --requirements-file are mutually exclusive.") elif not collections and not requirements_file: raise AnsibleError("You must specify a collection name or a requirements file.") elif requirements_file: if signatures is not None: raise AnsibleError( "The --signatures option and --requirements-file are mutually exclusive. " "Use the --signatures with positional collection_name args or provide a " "'signatures' key for requirements in the --requirements-file." ) requirements_file = GalaxyCLI._resolve_path(requirements_file) requirements = self._parse_requirements_file( requirements_file, allow_old_format=False, artifacts_manager=artifacts_manager, ) else: requirements = { 'collections': [ Requirement.from_string(coll_input, artifacts_manager, signatures) for coll_input in collections ], 'roles': [], } return requirements ############################ # execute actions ############################ def execute_role(self): """ Perform the action on an Ansible Galaxy role. Must be combined with a further action like delete/install/init as listed below. """ # To satisfy doc build pass def execute_collection(self): """ Perform the action on an Ansible Galaxy collection. Must be combined with a further action like init/install as listed below. """ # To satisfy doc build pass def execute_build(self): """ Build an Ansible Galaxy collection artifact that can be stored in a central repository like Ansible Galaxy. By default, this command builds from the current working directory. You can optionally pass in the collection input path (where the ``galaxy.yml`` file is). """ force = context.CLIARGS['force'] output_path = GalaxyCLI._resolve_path(context.CLIARGS['output_path']) b_output_path = to_bytes(output_path, errors='surrogate_or_strict') if not os.path.exists(b_output_path): os.makedirs(b_output_path) elif os.path.isfile(b_output_path): raise AnsibleError("- the output collection directory %s is a file - aborting" % to_native(output_path)) for collection_path in context.CLIARGS['args']: collection_path = GalaxyCLI._resolve_path(collection_path) build_collection( to_text(collection_path, errors='surrogate_or_strict'), to_text(output_path, errors='surrogate_or_strict'), force, ) @with_collection_artifacts_manager def execute_download(self, artifacts_manager=None): """Download collections and their dependencies as a tarball for an offline install.""" collections = context.CLIARGS['args'] no_deps = context.CLIARGS['no_deps'] download_path = context.CLIARGS['download_path'] requirements_file = context.CLIARGS['requirements'] if requirements_file: requirements_file = GalaxyCLI._resolve_path(requirements_file) requirements = self._require_one_of_collections_requirements( collections, requirements_file, artifacts_manager=artifacts_manager, )['collections'] download_path = GalaxyCLI._resolve_path(download_path) b_download_path = to_bytes(download_path, errors='surrogate_or_strict') if not os.path.exists(b_download_path): os.makedirs(b_download_path) download_collections( requirements, download_path, self.api_servers, no_deps, context.CLIARGS['allow_pre_release'], artifacts_manager=artifacts_manager, ) return 0 def execute_init(self): """ Creates the skeleton framework of a role or collection that complies with the Galaxy metadata format. Requires a role or collection name. The collection name must be in the format ``.``. """ galaxy_type = context.CLIARGS['type'] init_path = context.CLIARGS['init_path'] force = context.CLIARGS['force'] obj_skeleton = context.CLIARGS['{0}_skeleton'.format(galaxy_type)] obj_name = context.CLIARGS['{0}_name'.format(galaxy_type)] inject_data = dict( description='your {0} description'.format(galaxy_type), ansible_plugin_list_dir=get_versioned_doclink('plugins/plugins.html'), ) if galaxy_type == 'role': inject_data.update(dict( author='your name', company='your company (optional)', license='license (GPL-2.0-or-later, MIT, etc)', role_name=obj_name, role_type=context.CLIARGS['role_type'], issue_tracker_url='http://example.com/issue/tracker', repository_url='http://example.com/repository', documentation_url='http://docs.example.com', homepage_url='http://example.com', min_ansible_version=ansible_version[:3], # x.y dependencies=[], )) skeleton_ignore_expressions = C.GALAXY_ROLE_SKELETON_IGNORE obj_path = os.path.join(init_path, obj_name) elif galaxy_type == 'collection': namespace, collection_name = obj_name.split('.', 1) inject_data.update(dict( namespace=namespace, collection_name=collection_name, version='1.0.0', readme='README.md', authors=['your name '], license=['GPL-2.0-or-later'], repository='http://example.com/repository', documentation='http://docs.example.com', homepage='http://example.com', issues='http://example.com/issue/tracker', build_ignore=[], )) skeleton_ignore_expressions = C.GALAXY_COLLECTION_SKELETON_IGNORE obj_path = os.path.join(init_path, namespace, collection_name) b_obj_path = to_bytes(obj_path, errors='surrogate_or_strict') if os.path.exists(b_obj_path): if os.path.isfile(obj_path): raise AnsibleError("- the path %s already exists, but is a file - aborting" % to_native(obj_path)) elif not force: raise AnsibleError("- the directory %s already exists. " "You can use --force to re-initialize this directory,\n" "however it will reset any main.yml files that may have\n" "been modified there already." % to_native(obj_path)) # delete the contents rather than the collection root in case init was run from the root (--init-path ../../) for root, dirs, files in os.walk(b_obj_path, topdown=True): for old_dir in dirs: path = os.path.join(root, old_dir) shutil.rmtree(path) for old_file in files: path = os.path.join(root, old_file) os.unlink(path) if obj_skeleton is not None: own_skeleton = False else: own_skeleton = True obj_skeleton = self.galaxy.default_role_skeleton_path skeleton_ignore_expressions = ['^.*/.git_keep$'] obj_skeleton = os.path.expanduser(obj_skeleton) skeleton_ignore_re = [re.compile(x) for x in skeleton_ignore_expressions] if not os.path.exists(obj_skeleton): raise AnsibleError("- the skeleton path '{0}' does not exist, cannot init {1}".format( to_native(obj_skeleton), galaxy_type) ) loader = DataLoader() inject_data.update(load_extra_vars(loader)) templar = TemplateEngine(loader, variables=inject_data) # create role directory if not os.path.exists(b_obj_path): os.makedirs(b_obj_path) for root, dirs, files in os.walk(obj_skeleton, topdown=True): rel_root = os.path.relpath(root, obj_skeleton) rel_dirs = rel_root.split(os.sep) rel_root_dir = rel_dirs[0] if galaxy_type == 'collection': # A collection can contain templates in playbooks/*/templates and roles/*/templates in_templates_dir = rel_root_dir in ['playbooks', 'roles'] and 'templates' in rel_dirs else: in_templates_dir = rel_root_dir == 'templates' # Filter out ignored directory names # Use [:] to mutate the list os.walk uses dirs[:] = [d for d in dirs if not any(r.match(d) for r in skeleton_ignore_re)] for f in files: filename, ext = os.path.splitext(f) if any(r.match(os.path.join(rel_root, f)) for r in skeleton_ignore_re): continue if galaxy_type == 'collection' and own_skeleton and rel_root == '.' and f == 'galaxy.yml.j2': # Special use case for galaxy.yml.j2 in our own default collection skeleton. We build the options # dynamically which requires special options to be set. # The templated data's keys must match the key name but the inject data contains collection_name # instead of name. We just make a copy and change the key back to name for this file. template_data = inject_data.copy() template_data['name'] = template_data.pop('collection_name') meta_value = GalaxyCLI._get_skeleton_galaxy_yml(os.path.join(root, rel_root, f), template_data) b_dest_file = to_bytes(os.path.join(obj_path, rel_root, filename), errors='surrogate_or_strict') with open(b_dest_file, 'wb') as galaxy_obj: galaxy_obj.write(to_bytes(meta_value, errors='surrogate_or_strict')) elif ext == ".j2" and not in_templates_dir: src_template = os.path.join(root, f) dest_file = os.path.join(obj_path, rel_root, filename) template_data = trust_as_template(loader.get_text_file_contents(src_template)) try: b_rendered = to_bytes(templar.template(template_data), errors='surrogate_or_strict') except AnsibleError as e: shutil.rmtree(b_obj_path) raise AnsibleError(f"Failed to create {galaxy_type.title()} {obj_name}. Templating {src_template} failed with the error: {e}") from e with open(dest_file, 'wb') as df: df.write(b_rendered) else: f_rel_path = os.path.relpath(os.path.join(root, f), obj_skeleton) shutil.copyfile(os.path.join(root, f), os.path.join(obj_path, f_rel_path), follow_symlinks=False) for d in dirs: b_dir_path = to_bytes(os.path.join(obj_path, rel_root, d), errors='surrogate_or_strict') if os.path.exists(b_dir_path): continue b_src_dir = to_bytes(os.path.join(root, d), errors='surrogate_or_strict') if os.path.islink(b_src_dir): shutil.copyfile(b_src_dir, b_dir_path, follow_symlinks=False) else: os.makedirs(b_dir_path) display.display("- %s %s was created successfully" % (galaxy_type.title(), obj_name)) def execute_info(self): """ prints out detailed information about an installed role as well as info available from the galaxy API. """ roles_path = context.CLIARGS['roles_path'] data = '' for role in context.CLIARGS['args']: role_info = {'path': roles_path} gr = GalaxyRole(self.galaxy, self.lazy_role_api, role) install_info = gr.install_info if install_info: if 'version' in install_info: install_info['installed_version'] = install_info['version'] del install_info['version'] role_info.update(install_info) if not context.CLIARGS['offline']: remote_data = None try: remote_data = self.api.lookup_role_by_name(role, False) except GalaxyError as e: if e.http_code == 400 and 'Bad Request' in e.message: # Role does not exist in Ansible Galaxy data = u"- the role %s was not found" % role break raise AnsibleError("Unable to find info about '%s': %s" % (role, e)) if remote_data: role_info.update(remote_data) else: data = u"- the role %s was not found" % role break elif context.CLIARGS['offline'] and not gr._exists: data = u"- the role %s was not found" % role break if gr.metadata: role_info.update(gr.metadata) req = RoleRequirement() role_spec = req.role_yaml_parse({'role': role}) if role_spec: role_info.update(role_spec) data += self._display_role_info(role_info) self.pager(data) @with_collection_artifacts_manager def execute_verify(self, artifacts_manager=None): """Compare checksums with the collection(s) found on the server and the installed copy. This does not verify dependencies.""" collections = context.CLIARGS['args'] search_paths = AnsibleCollectionConfig.collection_paths ignore_errors = context.CLIARGS['ignore_errors'] local_verify_only = context.CLIARGS['offline'] requirements_file = context.CLIARGS['requirements'] signatures = context.CLIARGS['signatures'] if signatures is not None: signatures = list(signatures) requirements = self._require_one_of_collections_requirements( collections, requirements_file, signatures=signatures, artifacts_manager=artifacts_manager, )['collections'] resolved_paths = [validate_collection_path(GalaxyCLI._resolve_path(path)) for path in search_paths] results = verify_collections( requirements, resolved_paths, self.api_servers, ignore_errors, local_verify_only=local_verify_only, artifacts_manager=artifacts_manager, ) if any(result for result in results if not result.success): return 1 return 0 @with_collection_artifacts_manager def execute_install(self, artifacts_manager=None): """ Install one or more roles(``ansible-galaxy role install``), or one or more collections(``ansible-galaxy collection install``). You can pass in a list (roles or collections) or use the file option listed below (these are mutually exclusive). If you pass in a list, it can be a name (which will be downloaded via the galaxy API and github), or it can be a local tar archive file. """ install_items = context.CLIARGS['args'] requirements_file = context.CLIARGS['requirements'] collection_path = None signatures = context.CLIARGS.get('signatures') if signatures is not None: signatures = list(signatures) if requirements_file: requirements_file = GalaxyCLI._resolve_path(requirements_file) two_type_warning = "The requirements file '%s' contains {0}s which will be ignored. To install these {0}s " \ "run 'ansible-galaxy {0} install -r' or to install both at the same time run " \ "'ansible-galaxy install -r' without a custom install path." % to_text(requirements_file) # TODO: Would be nice to share the same behaviour with args and -r in collections and roles. collection_requirements = [] role_requirements = [] if context.CLIARGS['type'] == 'collection': collection_path = GalaxyCLI._resolve_path(context.CLIARGS['collections_path']) requirements = self._require_one_of_collections_requirements( install_items, requirements_file, signatures=signatures, artifacts_manager=artifacts_manager, ) collection_requirements = requirements['collections'] if requirements['roles']: display.vvv(two_type_warning.format('role')) else: if not install_items and requirements_file is None: raise AnsibleOptionsError("- you must specify a user/role name or a roles file") if requirements_file: if not (requirements_file.endswith('.yaml') or requirements_file.endswith('.yml')): raise AnsibleError("Invalid role requirements file, it must end with a .yml or .yaml extension") galaxy_args = self._raw_args will_install_collections = self._implicit_role and '-p' not in galaxy_args and '--roles-path' not in galaxy_args requirements = self._parse_requirements_file( requirements_file, artifacts_manager=artifacts_manager, validate_signature_options=will_install_collections, ) role_requirements = requirements['roles'] # We can only install collections and roles at the same time if the type wasn't specified and the -p # argument was not used. If collections are present in the requirements then at least display a msg. if requirements['collections'] and (not self._implicit_role or '-p' in galaxy_args or '--roles-path' in galaxy_args): # We only want to display a warning if 'ansible-galaxy install -r ... -p ...'. Other cases the user # was explicit about the type and shouldn't care that collections were skipped. display_func = display.warning if self._implicit_role else display.vvv display_func(two_type_warning.format('collection')) else: collection_path = self._get_default_collection_path() collection_requirements = requirements['collections'] else: # roles were specified directly, so we'll just go out grab them # (and their dependencies, unless the user doesn't want us to). for rname in context.CLIARGS['args']: role = RoleRequirement.role_yaml_parse(rname.strip()) role_requirements.append(GalaxyRole(self.galaxy, self.lazy_role_api, **role)) if not role_requirements and not collection_requirements: display.display("Skipping install, no requirements found") return if role_requirements: display.display("Starting galaxy role install process") self._execute_install_role(role_requirements) if collection_requirements: display.display("Starting galaxy collection install process") # Collections can technically be installed even when ansible-galaxy is in role mode so we need to pass in # the install path as context.CLIARGS['collections_path'] won't be set (default is calculated above). self._execute_install_collection( collection_requirements, collection_path, artifacts_manager=artifacts_manager, ) def _execute_install_collection( self, requirements, path, artifacts_manager, ): force = context.CLIARGS['force'] ignore_errors = context.CLIARGS['ignore_errors'] no_deps = context.CLIARGS['no_deps'] force_with_deps = context.CLIARGS['force_with_deps'] try: disable_gpg_verify = context.CLIARGS['disable_gpg_verify'] except KeyError: if self._implicit_role: raise AnsibleError( 'Unable to properly parse command line arguments. Please use "ansible-galaxy collection install" ' 'instead of "ansible-galaxy install".' ) raise # If `ansible-galaxy install` is used, collection-only options aren't available to the user and won't be in context.CLIARGS allow_pre_release = context.CLIARGS.get('allow_pre_release', False) upgrade = context.CLIARGS.get('upgrade', False) collections_path = C.COLLECTIONS_PATHS managed_paths = set(validate_collection_path(p) for p in C.COLLECTIONS_PATHS) read_req_paths = set(validate_collection_path(p) for p in AnsibleCollectionConfig.collection_paths) unexpected_path = C.GALAXY_COLLECTIONS_PATH_WARNING and not any(p.startswith(path) for p in managed_paths) if unexpected_path and any(p.startswith(path) for p in read_req_paths): display.warning( f"The specified collections path '{path}' appears to be part of the pip Ansible package. " "Managing these directly with ansible-galaxy could break the Ansible package. " "Install collections to a configured collections path, which will take precedence over " "collections found in the PYTHONPATH." ) elif unexpected_path: display.warning("The specified collections path '%s' is not part of the configured Ansible " "collections paths '%s'. The installed collection will not be picked up in an Ansible " "run, unless within a playbook-adjacent collections directory." % (to_text(path), to_text(":".join(collections_path)))) output_path = validate_collection_path(path) b_output_path = to_bytes(output_path, errors='surrogate_or_strict') if not os.path.exists(b_output_path): os.makedirs(b_output_path) install_collections( requirements, output_path, self.api_servers, ignore_errors, no_deps, force, force_with_deps, upgrade, allow_pre_release=allow_pre_release, artifacts_manager=artifacts_manager, disable_gpg_verify=disable_gpg_verify, offline=context.CLIARGS.get('offline', False), read_requirement_paths=read_req_paths, ) return 0 def _execute_install_role(self, requirements): role_file = context.CLIARGS['requirements'] no_deps = context.CLIARGS['no_deps'] force_deps = context.CLIARGS['force_with_deps'] force = context.CLIARGS['force'] or force_deps for role in requirements: # only process roles in roles files when names matches if given if role_file and context.CLIARGS['args'] and role.name not in context.CLIARGS['args']: display.vvv('Skipping role %s' % role.name) continue display.vvv('Processing role %s ' % role.name) # query the galaxy API for the role data if role.install_info is not None: if role.install_info['version'] != role.version or force: if force: display.display('- changing role %s from %s to %s' % (role.name, role.install_info['version'], role.version or "unspecified")) role.remove() else: display.warning('- %s (%s) is already installed - use --force to change version to %s' % (role.name, role.install_info['version'], role.version or "unspecified")) continue else: if not force: display.display('- %s is already installed, skipping.' % str(role)) continue try: installed = role.install() except AnsibleError as e: display.warning(u"- %s was NOT installed successfully: %s " % (role.name, to_text(e))) self.exit_without_ignore() continue # install dependencies, if we want them if not no_deps and installed: if not role.metadata: # NOTE: the meta file is also required for installing the role, not just dependencies display.warning("Meta file %s is empty. Skipping dependencies." % role.path) else: role_dependencies = role.metadata_dependencies + role.requirements for dep in role_dependencies: display.debug('Installing dep %s' % dep) dep_req = RoleRequirement() dep_info = dep_req.role_yaml_parse(dep) dep_role = GalaxyRole(self.galaxy, self.lazy_role_api, **dep_info) if '.' not in dep_role.name and '.' not in dep_role.src and dep_role.scm is None: # we know we can skip this, as it's not going to # be found on galaxy.ansible.com continue if dep_role.install_info is None: if dep_role not in requirements: display.display('- adding dependency: %s' % to_text(dep_role)) requirements.append(dep_role) else: display.display('- dependency %s already pending installation.' % dep_role.name) else: if dep_role.install_info['version'] != dep_role.version: if force_deps: display.display('- changing dependent role %s from %s to %s' % (dep_role.name, dep_role.install_info['version'], dep_role.version or "unspecified")) dep_role.remove() requirements.append(dep_role) else: display.warning('- dependency %s (%s) from role %s differs from already installed version (%s), skipping' % (to_text(dep_role), dep_role.version, role.name, dep_role.install_info['version'])) else: if force_deps: requirements.append(dep_role) else: display.display('- dependency %s is already installed, skipping.' % dep_role.name) if not installed: display.warning("- %s was NOT installed successfully." % role.name) self.exit_without_ignore() return 0 def execute_remove(self): """ removes the list of roles passed as arguments from the local system. """ if not context.CLIARGS['args']: raise AnsibleOptionsError('- you must specify at least one role to remove.') for role_name in context.CLIARGS['args']: role = GalaxyRole(self.galaxy, self.api, role_name) try: if role.remove(): display.display('- successfully removed %s' % role_name) else: display.display('- %s is not installed, skipping.' % role_name) except Exception as e: raise AnsibleError("Failed to remove role %s: %s" % (role_name, to_native(e))) return 0 def execute_list(self): """ List installed collections or roles """ if context.CLIARGS['type'] == 'role': self.execute_list_role() elif context.CLIARGS['type'] == 'collection': self.execute_list_collection() def execute_list_role(self): """ List all roles installed on the local system or a specific role """ path_found = False role_found = False warnings = [] roles_search_paths = context.CLIARGS['roles_path'] role_name = context.CLIARGS['role'] for path in roles_search_paths: role_path = GalaxyCLI._resolve_path(path) if os.path.isdir(path): path_found = True else: warnings.append("- the configured path {0} does not exist.".format(path)) continue if role_name: # show the requested role, if it exists gr = GalaxyRole(self.galaxy, self.lazy_role_api, role_name, path=os.path.join(role_path, role_name)) if os.path.isdir(gr.path): role_found = True display.display('# %s' % os.path.dirname(gr.path)) _display_role(gr) break warnings.append("- the role %s was not found" % role_name) else: if not os.path.exists(role_path): warnings.append("- the configured path %s does not exist." % role_path) continue if not os.path.isdir(role_path): warnings.append("- the configured path %s, exists, but it is not a directory." % role_path) continue display.display('# %s' % role_path) path_files = os.listdir(role_path) for path_file in path_files: gr = GalaxyRole(self.galaxy, self.lazy_role_api, path_file, path=path) if gr.metadata: _display_role(gr) # Do not warn if the role was found in any of the search paths if role_found and role_name: warnings = [] for w in warnings: display.warning(w) if not path_found: raise AnsibleOptionsError( "- None of the provided paths were usable. Please specify a valid path with --{0}s-path".format(context.CLIARGS['type']) ) return 0 @with_collection_artifacts_manager def execute_list_collection(self, artifacts_manager=None): """ List all collections installed on the local system :param artifacts_manager: Artifacts manager. """ if artifacts_manager is not None: artifacts_manager.require_build_metadata = False output_format = context.CLIARGS['output_format'] collection_name = context.CLIARGS['collection'] default_collections_path = set(C.COLLECTIONS_PATHS) collections_search_paths = ( set(context.CLIARGS['collections_path'] or []) | default_collections_path | set(AnsibleCollectionConfig.collection_paths) ) collections_in_paths = {} warnings = [] path_found = False collection_found = False namespace_filter = None collection_filter = None if collection_name: # list a specific collection validate_collection_name(collection_name) namespace_filter, collection_filter = collection_name.split('.') collections = list(find_existing_collections( list(collections_search_paths), artifacts_manager, namespace_filter=namespace_filter, collection_filter=collection_filter, dedupe=False )) seen = set() fqcn_width, version_width = _get_collection_widths(collections) for collection in sorted(collections, key=lambda c: c.src): collection_found = True collection_path = pathlib.Path(to_text(collection.src)).parent.parent.as_posix() if output_format in {'yaml', 'json'}: collections_in_paths.setdefault(collection_path, {}) collections_in_paths[collection_path][collection.fqcn] = {'version': collection.ver} else: if collection_path not in seen: _display_header( collection_path, 'Collection', 'Version', fqcn_width, version_width ) seen.add(collection_path) _display_collection(collection, fqcn_width, version_width) path_found = False for path in collections_search_paths: if not os.path.exists(path): if path in default_collections_path: # don't warn for missing default paths continue warnings.append("- the configured path {0} does not exist.".format(path)) elif os.path.exists(path) and not os.path.isdir(path): warnings.append("- the configured path {0}, exists, but it is not a directory.".format(path)) else: path_found = True # Do not warn if the specific collection was found in any of the search paths if collection_found and collection_name: warnings = [] for w in warnings: display.warning(w) if not collections and not path_found: raise AnsibleOptionsError( "- None of the provided paths were usable. Please specify a valid path with --{0}s-path".format(context.CLIARGS['type']) ) if output_format == 'json': display.display(json.dumps(collections_in_paths)) elif output_format == 'yaml': display.display(yaml_dump(collections_in_paths)) return 0 def execute_publish(self): """ Publish a collection into Ansible Galaxy. Requires the path to the collection tarball to publish. """ collection_path = GalaxyCLI._resolve_path(context.CLIARGS['args']) wait = context.CLIARGS['wait'] timeout = context.CLIARGS['import_timeout'] publish_collection(collection_path, self.api, wait, timeout) def execute_search(self): """ searches for roles on the Ansible Galaxy server""" page_size = 1000 search = None if context.CLIARGS['args']: search = '+'.join(context.CLIARGS['args']) if not search and not context.CLIARGS['platforms'] and not context.CLIARGS['galaxy_tags'] and not context.CLIARGS['author']: raise AnsibleError("Invalid query. At least one search term, platform, galaxy tag or author must be provided.") response = self.api.search_roles(search, platforms=context.CLIARGS['platforms'], tags=context.CLIARGS['galaxy_tags'], author=context.CLIARGS['author'], page_size=page_size) if response['count'] == 0: display.warning("No roles match your search.") return 0 data = [u''] if response['count'] > page_size: data.append(u"Found %d roles matching your search. Showing first %s." % (response['count'], page_size)) else: data.append(u"Found %d roles matching your search:" % response['count']) max_len = [] for role in response['results']: max_len.append(len(role['username'] + '.' + role['name'])) name_len = max(max_len) format_str = u" %%-%ds %%s" % name_len data.append(u'') data.append(format_str % (u"Name", u"Description")) data.append(format_str % (u"----", u"-----------")) for role in response['results']: data.append(format_str % (u'%s.%s' % (role['username'], role['name']), role['description'])) data = u'\n'.join(data) self.pager(data) return 0 _task_check_delay_sec = 10 # allows unit test override def execute_import(self): """ used to import a role into Ansible Galaxy """ colors = { 'INFO': 'normal', 'WARNING': C.COLOR_WARN, 'ERROR': C.COLOR_ERROR, 'SUCCESS': C.COLOR_OK, 'FAILED': C.COLOR_ERROR, } github_user = to_text(context.CLIARGS['github_user'], errors='surrogate_or_strict') github_repo = to_text(context.CLIARGS['github_repo'], errors='surrogate_or_strict') rc = 0 if context.CLIARGS['check_status']: task = self.api.get_import_task(github_user=github_user, github_repo=github_repo) else: # Submit an import request task = self.api.create_import_task(github_user, github_repo, reference=context.CLIARGS['reference'], role_name=context.CLIARGS['role_name']) if len(task) > 1: # found multiple roles associated with github_user/github_repo display.display("WARNING: More than one Galaxy role associated with Github repo %s/%s." % (github_user, github_repo), color='yellow') display.display("The following Galaxy roles are being updated:" + u'\n', color=C.COLOR_CHANGED) for t in task: display.display('%s.%s' % (t['summary_fields']['role']['namespace'], t['summary_fields']['role']['name']), color=C.COLOR_CHANGED) display.display(u'\nTo properly namespace this role, remove each of the above and re-import %s/%s from scratch' % (github_user, github_repo), color=C.COLOR_CHANGED) return rc # found a single role as expected display.display("Successfully submitted import request %d" % task[0]['id']) if not context.CLIARGS['wait']: display.display("Role name: %s" % task[0]['summary_fields']['role']['name']) display.display("Repo: %s/%s" % (task[0]['github_user'], task[0]['github_repo'])) if context.CLIARGS['check_status'] or context.CLIARGS['wait']: # Get the status of the import msg_list = [] finished = False while not finished: task = self.api.get_import_task(task_id=task[0]['id']) for msg in task[0]['summary_fields']['task_messages']: if msg['id'] not in msg_list: display.display(msg['message_text'], color=colors[msg['message_type']]) msg_list.append(msg['id']) if (state := task[0]['state']) in ['SUCCESS', 'FAILED']: rc = ['SUCCESS', 'FAILED'].index(state) finished = True else: time.sleep(self._task_check_delay_sec) return rc def execute_setup(self): """ Setup an integration from Github or Travis for Ansible Galaxy roles""" if context.CLIARGS['setup_list']: # List existing integration secrets secrets = self.api.list_secrets() if len(secrets) == 0: # None found display.display("No integrations found.") return 0 display.display(u'\n' + "ID Source Repo", color=C.COLOR_OK) display.display("---------- ---------- ----------", color=C.COLOR_OK) for secret in secrets: display.display("%-10s %-10s %s/%s" % (secret['id'], secret['source'], secret['github_user'], secret['github_repo']), color=C.COLOR_OK) return 0 if context.CLIARGS['remove_id']: # Remove a secret self.api.remove_secret(context.CLIARGS['remove_id']) display.display("Secret removed. Integrations using this secret will not longer work.", color=C.COLOR_OK) return 0 source = context.CLIARGS['source'] github_user = context.CLIARGS['github_user'] github_repo = context.CLIARGS['github_repo'] secret = context.CLIARGS['secret'] resp = self.api.add_secret(source, github_user, github_repo, secret) display.display("Added integration for %s %s/%s" % (resp['source'], resp['github_user'], resp['github_repo'])) return 0 def execute_delete(self): """ Delete a role from Ansible Galaxy. """ github_user = context.CLIARGS['github_user'] github_repo = context.CLIARGS['github_repo'] resp = self.api.delete_role(github_user, github_repo) if len(resp['deleted_roles']) > 1: display.display("Deleted the following roles:") display.display("ID User Name") display.display("------ --------------- ----------") for role in resp['deleted_roles']: display.display("%-8s %-15s %s" % (role.id, role.namespace, role.name)) display.display(resp['status']) return 0 def main(args=None): GalaxyCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/inventory.py0000755000000000000000000003763615017704211020576 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2017, Brian Coca # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import json import sys import typing as t import argparse import functools from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRuntimeError from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible._internal._json._profiles import _inventory_legacy from ansible.utils.vars import combine_vars from ansible.utils.display import Display from ansible.vars.plugins import get_vars_from_inventory_sources, get_vars_from_path display = Display() class InventoryCLI(CLI): """ used to display or dump the configured inventory as Ansible sees it """ name = 'ansible-inventory' ARGUMENTS = {'group': 'The name of a group in the inventory, relevant when using --graph', } def __init__(self, args): super(InventoryCLI, self).__init__(args) self.vm = None self.loader = None self.inventory = None def init_parser(self): super(InventoryCLI, self).init_parser( usage='usage: %prog [options] [group]', desc='Show Ansible inventory information, by default it uses the inventory script JSON format') opt_help.add_inventory_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_basedir_options(self.parser) opt_help.add_runtask_options(self.parser) # remove unused default options self.parser.add_argument('--list-hosts', help=argparse.SUPPRESS, action=opt_help.UnrecognizedArgument) self.parser.add_argument('args', metavar='group', nargs='?', help='The name of a group in the inventory, relevant when using --graph') # Actions action_group = self.parser.add_argument_group("Actions", "One of following must be used on invocation, ONLY ONE!") action_group.add_argument("--list", action="store_true", default=False, dest='list', help='Output all hosts info, works as inventory script') action_group.add_argument("--host", action="store", default=None, dest='host', help='Output specific host info, works as inventory script. It will ignore limit') action_group.add_argument("--graph", action="store_true", default=False, dest='graph', help='create inventory graph, if supplying pattern it must be a valid group name. It will ignore limit') self.parser.add_argument_group(action_group) # graph self.parser.add_argument("-y", "--yaml", action="store_true", default=False, dest='yaml', help='Use YAML format instead of default JSON, ignored for --graph') self.parser.add_argument('--toml', action='store_true', default=False, dest='toml', help='Use TOML format instead of default JSON, ignored for --graph') self.parser.add_argument("--vars", action="store_true", default=False, dest='show_vars', help='Add vars to graph display, ignored unless used with --graph') # list self.parser.add_argument("--export", action="store_true", default=C.INVENTORY_EXPORT, dest='export', help="When doing --list, represent in a way that is optimized for export," "not as an accurate representation of how Ansible has processed it") self.parser.add_argument('--output', default=None, dest='output_file', help="When doing --list, send the inventory to a file instead of to the screen") # self.parser.add_argument("--ignore-vars-plugins", action="store_true", default=False, dest='ignore_vars_plugins', # help="When doing --list, skip vars data from vars plugins, by default, this would include group_vars/ and host_vars/") def post_process_args(self, options): options = super(InventoryCLI, self).post_process_args(options) display.verbosity = options.verbosity self.validate_conflicts(options) # there can be only one! and, at least, one! used = 0 for opt in (options.list, options.host, options.graph): if opt: used += 1 if used == 0: raise AnsibleOptionsError("No action selected, at least one of --host, --graph or --list needs to be specified.") elif used > 1: raise AnsibleOptionsError("Conflicting options used, only one of --host, --graph or --list can be used at the same time.") # set host pattern to default if not supplied if options.args: options.pattern = options.args else: options.pattern = 'all' return options def run(self): super(InventoryCLI, self).run() # Initialize needed objects self.loader, self.inventory, self.vm = self._play_prereqs() results = None if context.CLIARGS['host']: hosts = self.inventory.get_hosts(context.CLIARGS['host']) if len(hosts) != 1: raise AnsibleOptionsError("You must pass a single valid host to --host parameter") myvars = self._get_host_variables(host=hosts[0]) # FIXME: should we template first? results = self.dump(myvars) else: if context.CLIARGS['subset']: # not doing single host, set limit in general if given self.inventory.subset(context.CLIARGS['subset']) if context.CLIARGS['graph']: results = self.inventory_graph() elif context.CLIARGS['list']: top = self._get_group('all') if context.CLIARGS['yaml']: results = self.yaml_inventory(top) elif context.CLIARGS['toml']: results = self.toml_inventory(top) else: results = self.json_inventory(top) results = self.dump(results) if results: outfile = context.CLIARGS['output_file'] if outfile is None: # FIXME: pager? display.display(results) else: try: with open(to_bytes(outfile), 'wb') as f: f.write(to_bytes(results)) except (OSError, IOError) as e: raise AnsibleError('Unable to write to destination file (%s): %s' % (to_native(outfile), to_native(e))) sys.exit(0) sys.exit(1) @staticmethod def dump(stuff): if context.CLIARGS['yaml']: import yaml from ansible.parsing.yaml.dumper import AnsibleDumper # DTFIX0: need shared infra to smuggle custom kwargs to dumpers, since yaml.dump cannot (as of PyYAML 6.0.1) dumper = functools.partial(AnsibleDumper, dump_vault_tags=True) results = to_text(yaml.dump(stuff, Dumper=dumper, default_flow_style=False, allow_unicode=True)) elif context.CLIARGS['toml']: results = toml_dumps(stuff) else: results = json.dumps(stuff, cls=_inventory_legacy.Encoder, sort_keys=True, indent=4) return results def _get_group_variables(self, group): # get info from inventory source res = group.get_vars() # Always load vars plugins res = combine_vars(res, get_vars_from_inventory_sources(self.loader, self.inventory._sources, [group], 'all')) if context.CLIARGS['basedir']: res = combine_vars(res, get_vars_from_path(self.loader, context.CLIARGS['basedir'], [group], 'all')) if group.priority != 1: res['ansible_group_priority'] = group.priority return self._remove_internal(res) def _get_host_variables(self, host): if context.CLIARGS['export']: # only get vars defined directly host hostvars = host.get_vars() # Always load vars plugins hostvars = combine_vars(hostvars, get_vars_from_inventory_sources(self.loader, self.inventory._sources, [host], 'all')) if context.CLIARGS['basedir']: hostvars = combine_vars(hostvars, get_vars_from_path(self.loader, context.CLIARGS['basedir'], [host], 'all')) else: # get all vars flattened by host, but skip magic hostvars hostvars = self.vm.get_vars(host=host, include_hostvars=False, stage='all') return self._remove_internal(hostvars) def _get_group(self, gname): group = self.inventory.groups.get(gname) return group @staticmethod def _remove_internal(dump): for internal in C.INTERNAL_STATIC_VARS: if internal in dump: del dump[internal] return dump @staticmethod def _remove_empty_keys(dump): # remove empty keys for x in ('hosts', 'vars', 'children'): if x in dump and not dump[x]: del dump[x] @staticmethod def _show_vars(dump, depth): result = [] for (name, val) in sorted(dump.items()): result.append(InventoryCLI._graph_name('{%s = %s}' % (name, val), depth)) return result @staticmethod def _graph_name(name, depth=0): if depth: name = " |" * (depth) + "--%s" % name return name def _graph_group(self, group, depth=0): result = [self._graph_name('@%s:' % group.name, depth)] depth = depth + 1 for kid in group.child_groups: result.extend(self._graph_group(kid, depth)) if group.name != 'all': for host in group.hosts: result.append(self._graph_name(host.name, depth)) if context.CLIARGS['show_vars']: result.extend(self._show_vars(self._get_host_variables(host), depth + 1)) if context.CLIARGS['show_vars']: result.extend(self._show_vars(self._get_group_variables(group), depth)) return result def inventory_graph(self): start_at = self._get_group(context.CLIARGS['pattern']) if start_at: return '\n'.join(self._graph_group(start_at)) else: raise AnsibleOptionsError("Pattern must be valid group name when using --graph") def json_inventory(self, top): seen_groups = set() def format_group(group, available_hosts): results = {} results[group.name] = {} if group.name != 'all': results[group.name]['hosts'] = [h.name for h in group.hosts if h.name in available_hosts] results[group.name]['children'] = [] for subgroup in group.child_groups: results[group.name]['children'].append(subgroup.name) if subgroup.name not in seen_groups: results.update(format_group(subgroup, available_hosts)) seen_groups.add(subgroup.name) if context.CLIARGS['export']: results[group.name]['vars'] = self._get_group_variables(group) self._remove_empty_keys(results[group.name]) # remove empty groups if not results[group.name]: del results[group.name] return results hosts = self.inventory.get_hosts(top.name) results = format_group(top, frozenset(h.name for h in hosts)) # populate meta results['_meta'] = { 'hostvars': {}, 'profile': _inventory_legacy.Encoder.profile_name, } for host in hosts: hvars = self._get_host_variables(host) if hvars: results['_meta']['hostvars'][host.name] = hvars return results def yaml_inventory(self, top): seen_hosts = set() seen_groups = set() def format_group(group, available_hosts): results = {} # initialize group + vars results[group.name] = {} # subgroups results[group.name]['children'] = {} for subgroup in group.child_groups: if subgroup.name != 'all': if subgroup.name in seen_groups: results[group.name]['children'].update({subgroup.name: {}}) else: results[group.name]['children'].update(format_group(subgroup, available_hosts)) seen_groups.add(subgroup.name) # hosts for group results[group.name]['hosts'] = {} if group.name != 'all': for h in group.hosts: if h.name not in available_hosts: continue # observe limit myvars = {} if h.name not in seen_hosts: # avoid defining host vars more than once seen_hosts.add(h.name) myvars = self._get_host_variables(host=h) results[group.name]['hosts'][h.name] = myvars if context.CLIARGS['export']: gvars = self._get_group_variables(group) if gvars: results[group.name]['vars'] = gvars self._remove_empty_keys(results[group.name]) # remove empty groups if not results[group.name]: del results[group.name] return results available_hosts = frozenset(h.name for h in self.inventory.get_hosts(top.name)) return format_group(top, available_hosts) def toml_inventory(self, top): seen_hosts = set() seen_hosts = set() has_ungrouped = bool(next(g.hosts for g in top.child_groups if g.name == 'ungrouped')) def format_group(group, available_hosts): results = {} results[group.name] = {} results[group.name]['children'] = [] for subgroup in group.child_groups: if subgroup.name == 'ungrouped' and not has_ungrouped: continue if group.name != 'all': results[group.name]['children'].append(subgroup.name) results.update(format_group(subgroup, available_hosts)) if group.name != 'all': for host in group.hosts: if host.name not in available_hosts: continue if host.name not in seen_hosts: seen_hosts.add(host.name) host_vars = self._get_host_variables(host=host) else: host_vars = {} try: results[group.name]['hosts'][host.name] = host_vars except KeyError: results[group.name]['hosts'] = {host.name: host_vars} if context.CLIARGS['export']: results[group.name]['vars'] = self._get_group_variables(group) self._remove_empty_keys(results[group.name]) # remove empty groups if not results[group.name]: del results[group.name] return results available_hosts = frozenset(h.name for h in self.inventory.get_hosts(top.name)) results = format_group(top, available_hosts) return results def toml_dumps(data: t.Any) -> str: try: from tomli_w import dumps as _tomli_w_dumps except ImportError: pass else: return _tomli_w_dumps(data) raise AnsibleRuntimeError('The Python library "tomli-w" is required when using the TOML output format.') def main(args=None): InventoryCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/playbook.py0000755000000000000000000002446215017704211020352 0ustar00rootroot#!/usr/bin/env python # (c) 2012, Michael DeHaan # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import os import stat from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleError from ansible.executor.playbook_executor import PlaybookExecutor from ansible.module_utils.common.text.converters import to_bytes from ansible.playbook.block import Block from ansible.plugins.loader import add_all_plugin_dirs from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path, _get_collection_playbook_path from ansible.utils.display import Display display = Display() class PlaybookCLI(CLI): """ the tool to run *Ansible playbooks*, which are a configuration and multinode deployment system. See the project home page (https://docs.ansible.com) for more information. """ name = 'ansible-playbook' USES_CONNECTION = True def init_parser(self): # create parser for CLI options super(PlaybookCLI, self).init_parser( usage="%prog [options] playbook.yml [playbook2 ...]", desc="Runs Ansible playbooks, executing the defined tasks on the targeted hosts.") opt_help.add_connect_options(self.parser) opt_help.add_meta_options(self.parser) opt_help.add_runas_options(self.parser) opt_help.add_subset_options(self.parser) opt_help.add_check_options(self.parser) opt_help.add_inventory_options(self.parser) opt_help.add_runtask_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_fork_options(self.parser) opt_help.add_module_options(self.parser) # ansible playbook specific opts self.parser.add_argument('--syntax-check', dest='syntax', action='store_true', help="perform a syntax check on the playbook, but do not execute it") self.parser.add_argument('--list-tasks', dest='listtasks', action='store_true', help="list all tasks that would be executed") self.parser.add_argument('--list-tags', dest='listtags', action='store_true', help="list all available tags") self.parser.add_argument('--step', dest='step', action='store_true', help="one-step-at-a-time: confirm each task before running") self.parser.add_argument('--start-at-task', dest='start_at_task', help="start the playbook at the task matching this name") self.parser.add_argument('args', help='Playbook(s)', metavar='playbook', nargs='+') def post_process_args(self, options): # for listing, we need to know if user had tag input # capture here as parent function sets defaults for tags havetags = bool(options.tags or options.skip_tags) options = super(PlaybookCLI, self).post_process_args(options) if options.listtags: # default to all tags (including never), when listing tags # unless user specified tags if not havetags: options.tags = ['never', 'all'] display.verbosity = options.verbosity self.validate_conflicts(options, runas_opts=True, fork_opts=True) return options def run(self): super(PlaybookCLI, self).run() # Note: slightly wrong, this is written so that implicit localhost # manages passwords sshpass = None becomepass = None passwords = {} # initial error check, to make sure all specified playbooks are accessible # before we start running anything through the playbook executor # also prep plugin paths b_playbook_dirs = [] for playbook in context.CLIARGS['args']: # resolve if it is collection playbook with FQCN notation, if not, leaves unchanged resource = _get_collection_playbook_path(playbook) if resource is not None: playbook_collection = resource[2] else: # not an FQCN so must be a file if not os.path.exists(playbook): raise AnsibleError("the playbook: %s could not be found" % playbook) if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)): raise AnsibleError("the playbook: %s does not appear to be a file" % playbook) # check if playbook is from collection (path can be passed directly) playbook_collection = _get_collection_name_from_path(playbook) # don't add collection playbooks to adjacency search path if not playbook_collection: # setup dirs to enable loading plugins from all playbooks in case they add callbacks/inventory/etc b_playbook_dir = os.path.dirname(os.path.abspath(to_bytes(playbook, errors='surrogate_or_strict'))) add_all_plugin_dirs(b_playbook_dir) b_playbook_dirs.append(b_playbook_dir) if b_playbook_dirs: # allow collections adjacent to these playbooks # we use list copy to avoid opening up 'adjacency' in the previous loop AnsibleCollectionConfig.playbook_paths = b_playbook_dirs # don't deal with privilege escalation or passwords when we don't need to if not (context.CLIARGS['listhosts'] or context.CLIARGS['listtasks'] or context.CLIARGS['listtags'] or context.CLIARGS['syntax']): (sshpass, becomepass) = self.ask_passwords() passwords = {'conn_pass': sshpass, 'become_pass': becomepass} # create base objects loader, inventory, variable_manager = self._play_prereqs() # (which is not returned in list_hosts()) is taken into account for # warning if inventory is empty. But it can't be taken into account for # checking if limit doesn't match any hosts. Instead we don't worry about # limit if only implicit localhost was in inventory to start with. # # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts()) CLI.get_host_list(inventory, context.CLIARGS['subset']) # create the playbook executor, which manages running the plays via a task queue manager pbex = PlaybookExecutor(playbooks=context.CLIARGS['args'], inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=passwords) results = pbex.run() if isinstance(results, list): for p in results: display.display('\nplaybook: %s' % p['playbook']) for idx, play in enumerate(p['plays']): if play._included_path is not None: loader.set_basedir(play._included_path) else: pb_dir = os.path.realpath(os.path.dirname(p['playbook'])) loader.set_basedir(pb_dir) # show host list if we were able to template into a list try: host_list = ','.join(play.hosts) except TypeError: host_list = '' msg = "\n play #%d (%s): %s" % (idx + 1, host_list, play.name) mytags = set(play.tags) msg += '\tTAGS: [%s]' % (','.join(mytags)) if context.CLIARGS['listhosts']: playhosts = set(inventory.get_hosts(play.hosts)) msg += "\n pattern: %s\n hosts (%d):" % (play.hosts, len(playhosts)) for host in playhosts: msg += "\n %s" % host display.display(msg) all_tags = set() if context.CLIARGS['listtags'] or context.CLIARGS['listtasks']: taskmsg = '' if context.CLIARGS['listtasks']: taskmsg = ' tasks:\n' def _process_block(b): taskmsg = '' for task in b.block: if isinstance(task, Block): taskmsg += _process_block(task) else: if task.action in C._ACTION_META and task.implicit: continue all_tags.update(task.tags) if context.CLIARGS['listtasks']: cur_tags = list(mytags.union(set(task.tags))) cur_tags.sort() if task.name: taskmsg += " %s" % task.get_name() else: taskmsg += " %s" % task.action taskmsg += "\tTAGS: [%s]\n" % ', '.join(cur_tags) return taskmsg all_vars = variable_manager.get_vars(play=play) for block in play.compile(): block = block.filter_tagged_tasks(all_vars) if not block.has_tasks(): continue taskmsg += _process_block(block) if context.CLIARGS['listtags']: cur_tags = list(mytags.union(all_tags)) cur_tags.sort() taskmsg += " TASK TAGS: [%s]\n" % ', '.join(cur_tags) display.display(taskmsg) return 0 else: return results def main(args=None): PlaybookCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/pull.py0000755000000000000000000004377115017704211017512 0ustar00rootroot#!/usr/bin/env python # Copyright: (c) 2012, Michael DeHaan # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import datetime import os import platform import secrets import shlex import shutil import socket import sys import time from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleOptionsError from ansible.module_utils.common.text.converters import to_native, to_text from ansible.plugins.loader import module_loader from ansible.utils.cmd_functions import run_cmd from ansible.utils.display import Display display = Display() SAFE_OUTPUT_ENV = { 'ANSIBLE_CALLBACK_RESULT_FORMAT': 'json', 'ANSIBLE_LOAD_CALLBACK_PLUGINS': '0', } def safe_output_env(f): def wrapper(*args, **kwargs): orig = {} for k, v in SAFE_OUTPUT_ENV.items(): orig[k] = os.environ.get(k, None) os.environ[k] = v result = f(*args, **kwargs) for key in orig.keys(): if orig[key] is None: del os.environ[key] else: os.environ[key] = orig[key] return result return wrapper class PullCLI(CLI): """ Used to pull a remote copy of ansible on each managed node, each set to run via cron and update playbook source via a source repository. This inverts the default *push* architecture of ansible into a *pull* architecture, which has near-limitless scaling potential. None of the CLI tools are designed to run concurrently with themselves, you should use an external scheduler and/or locking to ensure there are no clashing operations. The setup playbook can be tuned to change the cron frequency, logging locations, and parameters to ansible-pull. This is useful both for extreme scale-out and periodic remediation. Usage of the 'fetch' module to retrieve logs from ansible-pull runs would be an excellent way to gather and analyze remote logs from ansible-pull. """ name = 'ansible-pull' DEFAULT_REPO_TYPE = 'git' DEFAULT_PLAYBOOK = 'local.yml' REPO_CHOICES = ('git', 'subversion', 'hg', 'bzr') PLAYBOOK_ERRORS = { 1: 'File does not exist', 2: 'File is not readable', } ARGUMENTS = {'playbook.yml': 'The name of one the YAML format files to run as an Ansible playbook. ' 'This can be a relative path within the checkout. By default, Ansible will ' "look for a playbook based on the host's fully-qualified domain name, " 'on the host hostname and finally a playbook named *local.yml*.', } SKIP_INVENTORY_DEFAULTS = True @staticmethod def _get_inv_cli(): inv_opts = '' if context.CLIARGS.get('inventory', False): for inv in context.CLIARGS['inventory']: if isinstance(inv, list): inv_opts += " -i '%s' " % ','.join(inv) elif ',' in inv or os.path.exists(inv): inv_opts += ' -i %s ' % inv return inv_opts def init_parser(self): """ Specific args/option parser for pull """ # signature is different from parent as caller should not need to add usage/desc super(PullCLI, self).init_parser( usage='%prog -U [options] []', desc="pulls playbooks from a VCS repo and executes them on target host") # Do not add check_options as there's a conflict with --checkout/-C opt_help.add_connect_options(self.parser) opt_help.add_vault_options(self.parser) opt_help.add_runtask_options(self.parser) opt_help.add_subset_options(self.parser) opt_help.add_inventory_options(self.parser) opt_help.add_module_options(self.parser) opt_help.add_runas_prompt_options(self.parser) self.parser.add_argument('args', help='Playbook(s)', metavar='playbook.yml', nargs='*') # options unique to pull self.parser.add_argument('--purge', default=False, action='store_true', help='purge checkout after playbook run') self.parser.add_argument('-o', '--only-if-changed', dest='ifchanged', default=False, action='store_true', help='only run the playbook if the repository has been updated') self.parser.add_argument('-s', '--sleep', dest='sleep', default=None, help='sleep for random interval (between 0 and n number of seconds) before starting. ' 'This is a useful way to disperse git requests') self.parser.add_argument('-f', '--force', dest='force', default=False, action='store_true', help='run the playbook even if the repository could not be updated') self.parser.add_argument('-d', '--directory', dest='dest', default=None, type=opt_help.unfrack_path(), help='path to the directory to which Ansible will checkout the repository.') self.parser.add_argument('-U', '--url', dest='url', default=None, help='URL of the playbook repository') self.parser.add_argument('--full', dest='fullclone', action='store_true', help='Do a full clone, instead of a shallow one.') # TODO: resolve conflict with check mode, added manually below self.parser.add_argument('-C', '--checkout', dest='checkout', help='branch/tag/commit to checkout. Defaults to behavior of repository module.') self.parser.add_argument('--accept-host-key', default=False, dest='accept_host_key', action='store_true', help='adds the hostkey for the repo url if not already added') # Overloaded with adhoc ... but really passthrough to adhoc self.parser.add_argument('-m', '--module-name', dest='module_name', default=self.DEFAULT_REPO_TYPE, help='Repository module name, which ansible will use to check out the repo. Choices are %s. Default is %s.' % (self.REPO_CHOICES, self.DEFAULT_REPO_TYPE)) self.parser.add_argument('--verify-commit', dest='verify', default=False, action='store_true', help='verify GPG signature of checked out commit, if it fails abort running the playbook. ' 'This needs the corresponding VCS module to support such an operation') self.parser.add_argument('--clean', dest='clean', default=False, action='store_true', help='modified files in the working repository will be discarded') self.parser.add_argument('--track-subs', dest='tracksubs', default=False, action='store_true', help='submodules will track the latest changes. This is equivalent to specifying the --remote flag to git submodule update') # add a subset of the check_opts flag group manually, as the full set's # shortcodes conflict with above --checkout/-C, see to-do above self.parser.add_argument("--check", default=False, dest='check', action='store_true', help="don't make any changes; instead, try to predict some of the changes that may occur") self.parser.add_argument("--diff", default=C.DIFF_ALWAYS, dest='diff', action='store_true', help="when changing (small) files and templates, show the differences in those files; works great with --check") def post_process_args(self, options): options = super(PullCLI, self).post_process_args(options) if not options.dest: hostname = socket.getfqdn() # use a hostname dependent directory, in case of $HOME on nfs options.dest = os.path.join(C.ANSIBLE_HOME, 'pull', hostname) if os.path.exists(options.dest) and not os.path.isdir(options.dest): raise AnsibleOptionsError("%s is not a valid or accessible directory." % options.dest) if options.sleep: try: secs = secrets.randbelow(int(options.sleep)) options.sleep = secs except ValueError: raise AnsibleOptionsError("%s is not a number." % options.sleep) if not options.url: raise AnsibleOptionsError("URL for repository not specified, use -h for help") if options.module_name not in self.REPO_CHOICES: raise AnsibleOptionsError("Unsupported repo module %s, choices are %s" % (options.module_name, ','.join(self.REPO_CHOICES))) display.verbosity = options.verbosity self.validate_conflicts(options) return options def run(self): """ use Runner lib to do SSH things """ super(PullCLI, self).run() # log command line now = datetime.datetime.now() display.display(now.strftime("Starting Ansible Pull at %F %T")) display.display(' '.join(sys.argv)) # Build Checkout command # Now construct the ansible command node = platform.node() host = socket.getfqdn() hostnames = ','.join(set([host, node, host.split('.')[0], node.split('.')[0]])) if hostnames: limit_opts = 'localhost,%s,127.0.0.1' % hostnames else: limit_opts = 'localhost,127.0.0.1' base_opts = '-c local ' if context.CLIARGS['verbosity'] > 0: base_opts += ' -%s' % ''.join(["v" for dummy in range(0, context.CLIARGS['verbosity'])]) # Attempt to use the inventory passed in as an argument # It might not yet have been downloaded so use localhost as default inv_opts = self._get_inv_cli() if not inv_opts: inv_opts = " -i localhost, " # avoid interpreter discovery since we already know which interpreter to use on localhost inv_opts += '-e %s ' % shlex.quote('ansible_python_interpreter=%s' % sys.executable) # SCM specific options if context.CLIARGS['module_name'] == 'git': repo_opts = "name=%s dest=%s" % (context.CLIARGS['url'], context.CLIARGS['dest']) if context.CLIARGS['checkout']: repo_opts += ' version=%s' % context.CLIARGS['checkout'] if context.CLIARGS['accept_host_key']: repo_opts += ' accept_hostkey=yes' if context.CLIARGS['private_key_file']: repo_opts += ' key_file=%s' % context.CLIARGS['private_key_file'] if context.CLIARGS['verify']: repo_opts += ' verify_commit=yes' if context.CLIARGS['tracksubs']: repo_opts += ' track_submodules=yes' if not context.CLIARGS['fullclone']: repo_opts += ' depth=1' elif context.CLIARGS['module_name'] == 'subversion': repo_opts = "repo=%s dest=%s" % (context.CLIARGS['url'], context.CLIARGS['dest']) if context.CLIARGS['checkout']: repo_opts += ' revision=%s' % context.CLIARGS['checkout'] if not context.CLIARGS['fullclone']: repo_opts += ' export=yes' elif context.CLIARGS['module_name'] == 'hg': repo_opts = "repo=%s dest=%s" % (context.CLIARGS['url'], context.CLIARGS['dest']) if context.CLIARGS['checkout']: repo_opts += ' revision=%s' % context.CLIARGS['checkout'] elif context.CLIARGS['module_name'] == 'bzr': repo_opts = "name=%s dest=%s" % (context.CLIARGS['url'], context.CLIARGS['dest']) if context.CLIARGS['checkout']: repo_opts += ' version=%s' % context.CLIARGS['checkout'] else: raise AnsibleOptionsError('Unsupported (%s) SCM module for pull, choices are: %s' % (context.CLIARGS['module_name'], ','.join(self.REPO_CHOICES))) # options common to all supported SCMS if context.CLIARGS['clean']: repo_opts += ' force=yes' path = module_loader.find_plugin(context.CLIARGS['module_name']) if path is None: raise AnsibleOptionsError(("module '%s' not found.\n" % context.CLIARGS['module_name'])) bin_path = os.path.dirname(os.path.abspath(sys.argv[0])) # hardcode local and inventory/host as this is just meant to fetch the repo cmd = '%s/ansible %s %s -m %s -a "%s" all -l "%s"' % (bin_path, inv_opts, base_opts, context.CLIARGS['module_name'], repo_opts, limit_opts) for ev in context.CLIARGS['extra_vars']: cmd += ' -e %s' % shlex.quote(ev) # Nap? if context.CLIARGS['sleep']: display.display("Sleeping for %d seconds..." % context.CLIARGS['sleep']) time.sleep(context.CLIARGS['sleep']) # RUN the Checkout command display.debug("running ansible with VCS module to checkout repo") display.vvvv('EXEC: %s' % cmd) rc, b_out, b_err = safe_output_env(run_cmd)(cmd, live=True) if rc != 0: if context.CLIARGS['force']: display.warning("Unable to update repository. Continuing with (forced) run of playbook.") else: return rc elif context.CLIARGS['ifchanged']: # detect json/yaml/header, any count as 'changed' for detect in (b'"changed": true', b"changed: True", b"| CHANGED =>"): if detect in b_out: break else: # no change, we bail display.display(f"Repository has not changed, quitting: {b_out!r}") return 0 playbook = self.select_playbook(context.CLIARGS['dest']) if playbook is None: raise AnsibleOptionsError("Could not find a playbook to run.") # Build playbook command cmd = '%s/ansible-playbook %s %s' % (bin_path, base_opts, playbook) if context.CLIARGS['vault_password_files']: for vault_password_file in context.CLIARGS['vault_password_files']: cmd += " --vault-password-file=%s" % vault_password_file if context.CLIARGS['vault_ids']: for vault_id in context.CLIARGS['vault_ids']: cmd += " --vault-id=%s" % vault_id if context.CLIARGS['become_password_file']: cmd += " --become-password-file=%s" % context.CLIARGS['become_password_file'] if context.CLIARGS['connection_password_file']: cmd += " --connection-password-file=%s" % context.CLIARGS['connection_password_file'] for ev in context.CLIARGS['extra_vars']: cmd += ' -e %s' % shlex.quote(ev) if context.CLIARGS['become_ask_pass']: cmd += ' --ask-become-pass' if context.CLIARGS['skip_tags']: cmd += ' --skip-tags "%s"' % to_native(u','.join(context.CLIARGS['skip_tags'])) if context.CLIARGS['tags']: cmd += ' -t "%s"' % to_native(u','.join(context.CLIARGS['tags'])) if context.CLIARGS['subset']: cmd += ' -l "%s"' % context.CLIARGS['subset'] else: cmd += ' -l "%s"' % limit_opts if context.CLIARGS['check']: cmd += ' -C' if context.CLIARGS['diff']: cmd += ' -D' if context.CLIARGS['flush_cache']: cmd += ' --flush-cache' os.chdir(context.CLIARGS['dest']) # redo inventory options as new files might exist now inv_opts = self._get_inv_cli() if inv_opts: cmd += inv_opts # RUN THE PLAYBOOK COMMAND display.debug("running ansible-playbook to do actual work") display.debug('EXEC: %s' % cmd) rc, b_out, b_err = run_cmd(cmd, live=True) if context.CLIARGS['purge']: os.chdir('/') try: display.debug("removing: %s" % context.CLIARGS['dest']) shutil.rmtree(context.CLIARGS['dest']) except Exception as e: display.error(u"Failed to remove %s: %s" % (context.CLIARGS['dest'], to_text(e))) return rc @staticmethod def try_playbook(path): if not os.path.exists(path): return 1 if not os.access(path, os.R_OK): return 2 return 0 @staticmethod def select_playbook(path): playbook = None errors = [] if context.CLIARGS['args'] and context.CLIARGS['args'][0] is not None: playbooks = [] for book in context.CLIARGS['args']: book_path = os.path.join(path, book) rc = PullCLI.try_playbook(book_path) if rc != 0: errors.append("%s: %s" % (book_path, PullCLI.PLAYBOOK_ERRORS[rc])) continue playbooks.append(book_path) if 0 < len(errors): display.warning("\n".join(errors)) elif len(playbooks) == len(context.CLIARGS['args']): playbook = " ".join(playbooks) return playbook else: fqdn = socket.getfqdn() hostpb = os.path.join(path, fqdn + '.yml') shorthostpb = os.path.join(path, fqdn.split('.')[0] + '.yml') localpb = os.path.join(path, PullCLI.DEFAULT_PLAYBOOK) for pb in [hostpb, shorthostpb, localpb]: rc = PullCLI.try_playbook(pb) if rc == 0: playbook = pb break else: errors.append("%s: %s" % (pb, PullCLI.PLAYBOOK_ERRORS[rc])) if playbook is None: display.warning("\n".join(errors)) return playbook def main(args=None): PullCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/scripts/0000755000000000000000000000000015017704211017634 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/cli/scripts/__init__.py0000644000000000000000000000000015017704211021733 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/cli/scripts/ansible_connection_cli_stub.py0000644000000000000000000003150215017704211025727 0ustar00rootroot# Copyright: (c) 2017, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import fcntl import io import os import pickle import signal import socket import sys import time import traceback import errno import json from contextlib import contextmanager from ansible import constants as C from ansible.cli.arguments import option_helpers as opt_help from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.connection import Connection, ConnectionError, send_data, recv_data from ansible.module_utils.service import fork_process from ansible.module_utils._internal._json._profiles import _tagless from ansible.playbook.play_context import PlayContext from ansible.plugins.loader import connection_loader, init_plugin_loader from ansible.utils.path import unfrackpath, makedirs_safe from ansible.utils.display import Display from ansible.utils.jsonrpc import JsonRpcServer display = Display() def read_stream(byte_stream): size = int(byte_stream.readline().strip()) data = byte_stream.read(size) if len(data) < size: raise Exception("EOF found before data was complete") return data @contextmanager def file_lock(lock_path): """ Uses contextmanager to create and release a file lock based on the given path. This allows us to create locks using `with file_lock()` to prevent deadlocks related to failure to unlock properly. """ lock_fd = os.open(lock_path, os.O_RDWR | os.O_CREAT, 0o600) fcntl.lockf(lock_fd, fcntl.LOCK_EX) yield fcntl.lockf(lock_fd, fcntl.LOCK_UN) os.close(lock_fd) class ConnectionProcess(object): """ The connection process wraps around a Connection object that manages the connection to a remote device that persists over the playbook """ def __init__(self, fd, play_context, socket_path, original_path, task_uuid=None, ansible_playbook_pid=None): self.play_context = play_context self.socket_path = socket_path self.original_path = original_path self._task_uuid = task_uuid self.fd = fd self.exception = None self.srv = JsonRpcServer() self.sock = None self.connection = None self._ansible_playbook_pid = ansible_playbook_pid def start(self, options): messages = list() result = {} try: messages.append(('vvvv', 'control socket path is %s' % self.socket_path)) # If this is a relative path (~ gets expanded later) then plug the # key's path on to the directory we originally came from, so we can # find it now that our cwd is / if self.play_context.private_key_file and self.play_context.private_key_file[0] not in '~/': self.play_context.private_key_file = os.path.join(self.original_path, self.play_context.private_key_file) self.connection = connection_loader.get(self.play_context.connection, self.play_context, '/dev/null', task_uuid=self._task_uuid, ansible_playbook_pid=self._ansible_playbook_pid) try: self.connection.set_options(direct=options) except ConnectionError as exc: messages.append(('debug', to_text(exc))) raise ConnectionError('Unable to decode JSON from response set_options. See the debug log for more information.') self.connection._socket_path = self.socket_path self.srv.register(self.connection) messages.extend([('vvvv', msg) for msg in sys.stdout.getvalue().splitlines()]) self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.bind(self.socket_path) self.sock.listen(1) messages.append(('vvvv', 'local domain socket listeners started successfully')) except Exception as exc: messages.extend(self.connection.pop_messages()) result['error'] = to_text(exc) result['exception'] = traceback.format_exc() finally: result['messages'] = messages self.fd.write(json.dumps(result, cls=_tagless.Encoder)) self.fd.close() def run(self): try: log_messages = self.connection.get_option('persistent_log_messages') while not self.connection._conn_closed: signal.signal(signal.SIGALRM, self.connect_timeout) signal.signal(signal.SIGTERM, self.handler) signal.alarm(self.connection.get_option('persistent_connect_timeout')) self.exception = None (s, addr) = self.sock.accept() signal.alarm(0) signal.signal(signal.SIGALRM, self.command_timeout) while True: data = recv_data(s) if not data: break if log_messages: display.display("jsonrpc request: %s" % data, log_only=True) request = json.loads(to_text(data, errors='surrogate_or_strict')) if request.get('method') == "exec_command" and not self.connection.connected: self.connection._connect() signal.alarm(self.connection.get_option('persistent_command_timeout')) resp = self.srv.handle_request(data) signal.alarm(0) if log_messages: display.display("jsonrpc response: %s" % resp, log_only=True) send_data(s, to_bytes(resp)) s.close() except Exception as e: # socket.accept() will raise EINTR if the socket.close() is called if hasattr(e, 'errno'): if e.errno != errno.EINTR: self.exception = traceback.format_exc() else: self.exception = traceback.format_exc() finally: # allow time for any exception msg send over socket to receive at other end before shutting down time.sleep(0.1) # when done, close the connection properly and cleanup the socket file so it can be recreated self.shutdown() def connect_timeout(self, signum, frame): msg = 'persistent connection idle timeout triggered, timeout value is %s secs.\nSee the timeout setting options in the Network Debug and ' \ 'Troubleshooting Guide.' % self.connection.get_option('persistent_connect_timeout') display.display(msg, log_only=True) raise Exception(msg) def command_timeout(self, signum, frame): msg = 'command timeout triggered, timeout value is %s secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide.'\ % self.connection.get_option('persistent_command_timeout') display.display(msg, log_only=True) raise Exception(msg) def handler(self, signum, frame): msg = 'signal handler called with signal %s.' % signum display.display(msg, log_only=True) raise Exception(msg) def shutdown(self): """ Shuts down the local domain socket """ lock_path = unfrackpath("%s/.ansible_pc_lock_%s" % os.path.split(self.socket_path)) if os.path.exists(self.socket_path): try: if self.sock: self.sock.close() if self.connection: self.connection.close() if self.connection.get_option("persistent_log_messages"): for _level, message in self.connection.pop_messages(): display.display(message, log_only=True) except Exception: pass finally: if os.path.exists(self.socket_path): os.remove(self.socket_path) setattr(self.connection, '_socket_path', None) setattr(self.connection, '_connected', False) if os.path.exists(lock_path): os.remove(lock_path) display.display('shutdown complete', log_only=True) def main(args=None): """ Called to initiate the connect to the remote device """ parser = opt_help.create_base_parser(prog=None) opt_help.add_verbosity_options(parser) parser.add_argument('playbook_pid') parser.add_argument('task_uuid') args = parser.parse_args(args[1:] if args is not None else args) init_plugin_loader() # initialize verbosity display.verbosity = args.verbosity rc = 0 result = {} messages = list() socket_path = None # Need stdin as a byte stream stdin = sys.stdin.buffer # Note: update the below log capture code after Display.display() is refactored. saved_stdout = sys.stdout sys.stdout = io.StringIO() try: # read the play context data via stdin, which means depickling it opts_data = read_stream(stdin) init_data = read_stream(stdin) pc_data = pickle.loads(init_data, encoding='bytes') options = pickle.loads(opts_data, encoding='bytes') play_context = PlayContext() play_context.deserialize(pc_data) except Exception as e: rc = 1 result.update({ 'error': to_text(e), 'exception': traceback.format_exc() }) if rc == 0: ssh = connection_loader.get('ssh', class_only=True) ansible_playbook_pid = args.playbook_pid task_uuid = args.task_uuid cp = ssh._create_control_path(play_context.remote_addr, play_context.port, play_context.remote_user, play_context.connection, ansible_playbook_pid) # create the persistent connection dir if need be and create the paths # which we will be using later tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR) makedirs_safe(tmp_path) socket_path = unfrackpath(cp % dict(directory=tmp_path)) lock_path = unfrackpath("%s/.ansible_pc_lock_%s" % os.path.split(socket_path)) with file_lock(lock_path): if not os.path.exists(socket_path): messages.append(('vvvv', 'local domain socket does not exist, starting it')) original_path = os.getcwd() r, w = os.pipe() pid = fork_process() if pid == 0: try: os.close(r) wfd = os.fdopen(w, 'w') process = ConnectionProcess(wfd, play_context, socket_path, original_path, task_uuid, ansible_playbook_pid) process.start(options) except Exception: messages.append(('error', traceback.format_exc())) rc = 1 if rc == 0: process.run() else: process.shutdown() sys.exit(rc) else: os.close(w) rfd = os.fdopen(r, 'r') data = json.loads(rfd.read(), cls=_tagless.Decoder) messages.extend(data.pop('messages')) result.update(data) else: messages.append(('vvvv', 'found existing local domain socket, using it!')) conn = Connection(socket_path) try: conn.set_options(direct=options) except ConnectionError as exc: messages.append(('debug', to_text(exc))) raise ConnectionError('Unable to decode JSON from response set_options. See the debug log for more information.') pc_data = to_text(init_data) try: conn.update_play_context(pc_data) conn.set_check_prompt(task_uuid) except Exception as exc: # Only network_cli has update_play context and set_check_prompt, so missing this is # not fatal e.g. netconf if isinstance(exc, ConnectionError) and getattr(exc, 'code', None) == -32601: pass else: result.update({ 'error': to_text(exc), 'exception': traceback.format_exc() }) if os.path.exists(socket_path): messages.extend(Connection(socket_path).pop_messages()) messages.append(('vvvv', sys.stdout.getvalue())) result.update({ 'messages': messages, 'socket_path': socket_path }) sys.stdout = saved_stdout if 'exception' in result: rc = 1 sys.stderr.write(json.dumps(result, cls=_tagless.Encoder)) else: rc = 0 sys.stdout.write(json.dumps(result, cls=_tagless.Encoder)) sys.exit(rc) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/cli/vault.py0000755000000000000000000005523315017704211017665 0ustar00rootroot#!/usr/bin/env python # (c) 2014, James Tanner # Copyright: (c) 2018, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # PYTHON_ARGCOMPLETE_OK from __future__ import annotations # ansible.cli needs to be imported first, to ensure the source bin/* scripts run that code first from ansible.cli import CLI import os import sys from ansible import constants as C from ansible import context from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleOptionsError from ansible.module_utils.common.text.converters import to_text, to_bytes from ansible.parsing.dataloader import DataLoader from ansible.parsing.vault import VaultEditor, VaultLib, match_encrypt_secret from ansible.utils.display import Display display = Display() class VaultCLI(CLI): """ can encrypt any structured data file used by Ansible. This can include *group_vars/* or *host_vars/* inventory variables, variables loaded by *include_vars* or *vars_files*, or variable files passed on the ansible-playbook command line with *-e @file.yml* or *-e @file.json*. Role variables and defaults are also included! Because Ansible tasks, handlers, and other objects are data, these can also be encrypted with vault. If you'd like to not expose what variables you are using, you can keep an individual task file entirely encrypted. """ name = 'ansible-vault' FROM_STDIN = "stdin" FROM_ARGS = "the command line args" FROM_PROMPT = "the interactive prompt" def __init__(self, args): self.b_vault_pass = None self.b_new_vault_pass = None self.encrypt_string_read_stdin = False self.encrypt_secret = None self.encrypt_vault_id = None self.new_encrypt_secret = None self.new_encrypt_vault_id = None super(VaultCLI, self).__init__(args) def init_parser(self): super(VaultCLI, self).init_parser( desc="encryption/decryption utility for Ansible data files", epilog="\nSee '%s --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]) ) common = opt_help.ArgumentParser(add_help=False) opt_help.add_vault_options(common) opt_help.add_verbosity_options(common) subparsers = self.parser.add_subparsers(dest='action') subparsers.required = True output = opt_help.ArgumentParser(add_help=False) output.add_argument('--output', default=None, dest='output_file', help='output file name for encrypt or decrypt; use - for stdout', type=opt_help.unfrack_path()) # For encrypting actions, we can also specify which of multiple vault ids should be used for encrypting vault_id = opt_help.ArgumentParser(add_help=False) vault_id.add_argument('--encrypt-vault-id', default=[], dest='encrypt_vault_id', action='store', type=str, help='the vault id used to encrypt (required if more than one vault-id is provided)') create_parser = subparsers.add_parser('create', help='Create new vault encrypted file', parents=[vault_id, common]) create_parser.set_defaults(func=self.execute_create) create_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') create_parser.add_argument('--skip-tty-check', default=False, help='allows editor to be opened when no tty attached', dest='skip_tty_check', action='store_true') decrypt_parser = subparsers.add_parser('decrypt', help='Decrypt vault encrypted file or string', parents=[output, common]) decrypt_parser.set_defaults(func=self.execute_decrypt) decrypt_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') edit_parser = subparsers.add_parser('edit', help='Edit vault encrypted file', parents=[vault_id, common]) edit_parser.set_defaults(func=self.execute_edit) edit_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') view_parser = subparsers.add_parser('view', help='View vault encrypted file', parents=[common]) view_parser.set_defaults(func=self.execute_view) view_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') encrypt_parser = subparsers.add_parser('encrypt', help='Encrypt YAML file', parents=[common, output, vault_id]) encrypt_parser.set_defaults(func=self.execute_encrypt) encrypt_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') enc_str_parser = subparsers.add_parser('encrypt_string', help='Encrypt a string', parents=[common, output, vault_id]) enc_str_parser.set_defaults(func=self.execute_encrypt_string) enc_str_parser.add_argument('args', help='String to encrypt', metavar='string_to_encrypt', nargs='*') enc_str_parser.add_argument('-p', '--prompt', dest='encrypt_string_prompt', action='store_true', help="Prompt for the string to encrypt") enc_str_parser.add_argument('--show-input', dest='show_string_input', default=False, action='store_true', help='Do not hide input when prompted for the string to encrypt') enc_str_parser.add_argument('-n', '--name', dest='encrypt_string_names', action='append', help="Specify the variable name") enc_str_parser.add_argument('--stdin-name', dest='encrypt_string_stdin_name', default=None, help="Specify the variable name for stdin") rekey_parser = subparsers.add_parser('rekey', help='Re-key a vault encrypted file', parents=[common, vault_id]) rekey_parser.set_defaults(func=self.execute_rekey) rekey_new_group = rekey_parser.add_mutually_exclusive_group() rekey_new_group.add_argument('--new-vault-password-file', default=None, dest='new_vault_password_file', help="new vault password file for rekey", type=opt_help.unfrack_path()) rekey_new_group.add_argument('--new-vault-id', default=None, dest='new_vault_id', type=str, help='the new vault identity to use for rekey') rekey_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') def post_process_args(self, options): options = super(VaultCLI, self).post_process_args(options) display.verbosity = options.verbosity if options.vault_ids: for vault_id in options.vault_ids: if u';' in vault_id: raise AnsibleOptionsError("'%s' is not a valid vault id. The character ';' is not allowed in vault ids" % vault_id) if getattr(options, 'output_file', None) and len(options.args) > 1: raise AnsibleOptionsError("At most one input file may be used with the --output option") if options.action == 'encrypt_string': if '-' in options.args or options.encrypt_string_stdin_name or (not options.args and not options.encrypt_string_prompt): # prompting from stdin and reading from stdin are mutually exclusive, if stdin is still provided, it is ignored self.encrypt_string_read_stdin = True if options.encrypt_string_prompt and self.encrypt_string_read_stdin: # should only trigger if prompt + either - or encrypt string stdin name were provided raise AnsibleOptionsError('The --prompt option is not supported if also reading input from stdin') return options def run(self): super(VaultCLI, self).run() loader = DataLoader() # set default restrictive umask old_umask = os.umask(0o077) vault_ids = list(context.CLIARGS['vault_ids']) # there are 3 types of actions, those that just 'read' (decrypt, view) and only # need to ask for a password once, and those that 'write' (create, encrypt) that # ask for a new password and confirm it, and 'read/write (rekey) that asks for the # old password, then asks for a new one and confirms it. default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST vault_ids = default_vault_ids + vault_ids action = context.CLIARGS['action'] # TODO: instead of prompting for these before, we could let VaultEditor # call a callback when it needs it. if action in ['decrypt', 'view', 'rekey', 'edit']: vault_secrets = self.setup_vault_secrets(loader, vault_ids=vault_ids, vault_password_files=list(context.CLIARGS['vault_password_files']), ask_vault_pass=context.CLIARGS['ask_vault_pass']) if not vault_secrets: raise AnsibleOptionsError("A vault password is required to use Ansible's Vault") if action in ['encrypt', 'encrypt_string', 'create']: encrypt_vault_id = None # no --encrypt-vault-id context.CLIARGS['encrypt_vault_id'] for 'edit' if action not in ['edit']: encrypt_vault_id = context.CLIARGS['encrypt_vault_id'] or C.DEFAULT_VAULT_ENCRYPT_IDENTITY vault_secrets = None vault_secrets = \ self.setup_vault_secrets(loader, vault_ids=vault_ids, vault_password_files=list(context.CLIARGS['vault_password_files']), ask_vault_pass=context.CLIARGS['ask_vault_pass'], create_new_password=True) if len(vault_secrets) > 1 and not encrypt_vault_id: raise AnsibleOptionsError("The vault-ids %s are available to encrypt. Specify the vault-id to encrypt with --encrypt-vault-id" % ','.join([x[0] for x in vault_secrets])) if not vault_secrets: raise AnsibleOptionsError("A vault password is required to use Ansible's Vault") encrypt_secret = match_encrypt_secret(vault_secrets, encrypt_vault_id=encrypt_vault_id) # only one secret for encrypt for now, use the first vault_id and use its first secret # TODO: exception if more than one? self.encrypt_vault_id = encrypt_secret[0] self.encrypt_secret = encrypt_secret[1] if action in ['rekey']: encrypt_vault_id = context.CLIARGS['encrypt_vault_id'] or C.DEFAULT_VAULT_ENCRYPT_IDENTITY # print('encrypt_vault_id: %s' % encrypt_vault_id) # print('default_encrypt_vault_id: %s' % default_encrypt_vault_id) # new_vault_ids should only ever be one item, from # load the default vault ids if we are using encrypt-vault-id new_vault_ids = [] if encrypt_vault_id: new_vault_ids = default_vault_ids if context.CLIARGS['new_vault_id']: new_vault_ids.append(context.CLIARGS['new_vault_id']) new_vault_password_files = [] if context.CLIARGS['new_vault_password_file']: new_vault_password_files.append(context.CLIARGS['new_vault_password_file']) new_vault_secrets = \ self.setup_vault_secrets(loader, vault_ids=new_vault_ids, vault_password_files=new_vault_password_files, ask_vault_pass=context.CLIARGS['ask_vault_pass'], initialize_context=False, create_new_password=True) if not new_vault_secrets: raise AnsibleOptionsError("A new vault password is required to use Ansible's Vault rekey") # There is only one new_vault_id currently and one new_vault_secret, or we # use the id specified in --encrypt-vault-id new_encrypt_secret = match_encrypt_secret(new_vault_secrets, encrypt_vault_id=encrypt_vault_id) self.new_encrypt_vault_id = new_encrypt_secret[0] self.new_encrypt_secret = new_encrypt_secret[1] loader.set_vault_secrets(vault_secrets) # FIXME: do we need to create VaultEditor here? its not reused vault = VaultLib(vault_secrets) self.editor = VaultEditor(vault) context.CLIARGS['func']() # and restore umask os.umask(old_umask) def execute_encrypt(self): """ encrypt the supplied file using the provided vault secret """ if not context.CLIARGS['args'] and sys.stdin.isatty(): display.display("Reading plaintext input from stdin", stderr=True) for f in context.CLIARGS['args'] or ['-']: # FIXME: use the correct vau self.editor.encrypt_file(f, self.encrypt_secret, vault_id=self.encrypt_vault_id, output_file=context.CLIARGS['output_file']) if sys.stdout.isatty(): display.display("Encryption successful", stderr=True) @staticmethod def format_ciphertext_yaml(b_ciphertext, indent=None, name=None): indent = indent or 10 block_format_var_name = "" if name: block_format_var_name = "%s: " % name block_format_header = "%s!vault |" % block_format_var_name lines = [] vault_ciphertext = to_text(b_ciphertext) lines.append(block_format_header) for line in vault_ciphertext.splitlines(): lines.append('%s%s' % (' ' * indent, line)) yaml_ciphertext = '\n'.join(lines) return yaml_ciphertext def execute_encrypt_string(self): """ encrypt the supplied string using the provided vault secret """ b_plaintext = None # Holds tuples (the_text, the_source_of_the_string, the variable name if its provided). b_plaintext_list = [] # remove the non-option '-' arg (used to indicate 'read from stdin') from the candidate args so # we don't add it to the plaintext list args = [x for x in context.CLIARGS['args'] if x != '-'] # We can prompt and read input, or read from stdin, but not both. if context.CLIARGS['encrypt_string_prompt']: msg = "String to encrypt: " name = None name_prompt_response = display.prompt('Variable name (enter for no name): ') # TODO: enforce var naming rules? if name_prompt_response != "": name = name_prompt_response # TODO: could prompt for which vault_id to use for each plaintext string # currently, it will just be the default hide_input = not context.CLIARGS['show_string_input'] if hide_input: msg = "String to encrypt (hidden): " else: msg = "String to encrypt:" prompt_response = display.prompt(msg, private=hide_input) if prompt_response == '': raise AnsibleOptionsError('The plaintext provided from the prompt was empty, not encrypting') b_plaintext = to_bytes(prompt_response) b_plaintext_list.append((b_plaintext, self.FROM_PROMPT, name)) # read from stdin if self.encrypt_string_read_stdin: if sys.stdout.isatty(): display.display("Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)", stderr=True) stdin_text = sys.stdin.read() if stdin_text == '': raise AnsibleOptionsError('stdin was empty, not encrypting') if sys.stdout.isatty() and not stdin_text.endswith("\n"): display.display("\n") b_plaintext = to_bytes(stdin_text) # defaults to None name = context.CLIARGS['encrypt_string_stdin_name'] b_plaintext_list.append((b_plaintext, self.FROM_STDIN, name)) # use any leftover args as strings to encrypt # Try to match args up to --name options if context.CLIARGS.get('encrypt_string_names', False): name_and_text_list = list(zip(context.CLIARGS['encrypt_string_names'], args)) # Some but not enough --name's to name each var if len(args) > len(name_and_text_list): # Trying to avoid ever showing the plaintext in the output, so this warning is vague to avoid that. display.display('The number of --name options do not match the number of args.', stderr=True) display.display('The last named variable will be "%s". The rest will not have' ' names.' % context.CLIARGS['encrypt_string_names'][-1], stderr=True) # Add the rest of the args without specifying a name for extra_arg in args[len(name_and_text_list):]: name_and_text_list.append((None, extra_arg)) # if no --names are provided, just use the args without a name. else: name_and_text_list = [(None, x) for x in args] # Convert the plaintext text objects to bytestrings and collect for name_and_text in name_and_text_list: name, plaintext = name_and_text if plaintext == '': raise AnsibleOptionsError('The plaintext provided from the command line args was empty, not encrypting') b_plaintext = to_bytes(plaintext) b_plaintext_list.append((b_plaintext, self.FROM_ARGS, name)) # TODO: specify vault_id per string? # Format the encrypted strings and any corresponding stderr output outputs = self._format_output_vault_strings(b_plaintext_list, vault_id=self.encrypt_vault_id) b_outs = [] for output in outputs: err = output.get('err', None) out = output.get('out', '') if err: sys.stderr.write(err) b_outs.append(to_bytes(out)) # The output must end with a newline to play nice with terminal representation. # Refs: # * https://stackoverflow.com/a/729795/595220 # * https://github.com/ansible/ansible/issues/78932 b_outs.append(b'') self.editor.write_data(b'\n'.join(b_outs), context.CLIARGS['output_file'] or '-') if sys.stdout.isatty(): display.display("Encryption successful", stderr=True) # TODO: offer block or string ala eyaml def _format_output_vault_strings(self, b_plaintext_list, vault_id=None): # If we are only showing one item in the output, we don't need to included commented # delimiters in the text show_delimiter = False if len(b_plaintext_list) > 1: show_delimiter = True # list of dicts {'out': '', 'err': ''} output = [] # Encrypt the plaintext, and format it into a yaml block that can be pasted into a playbook. # For more than one input, show some differentiating info in the stderr output so we can tell them # apart. If we have a var name, we include that in the yaml for index, b_plaintext_info in enumerate(b_plaintext_list): # (the text itself, which input it came from, its name) b_plaintext, src, name = b_plaintext_info b_ciphertext = self.editor.encrypt_bytes(b_plaintext, self.encrypt_secret, vault_id=vault_id) # block formatting yaml_text = self.format_ciphertext_yaml(b_ciphertext, name=name) err_msg = None if show_delimiter: human_index = index + 1 if name: err_msg = '# The encrypted version of variable ("%s", the string #%d from %s).\n' % (name, human_index, src) else: err_msg = '# The encrypted version of the string #%d from %s.)\n' % (human_index, src) output.append({'out': yaml_text, 'err': err_msg}) return output def execute_decrypt(self): """ decrypt the supplied file using the provided vault secret """ if not context.CLIARGS['args'] and sys.stdin.isatty(): display.display("Reading ciphertext input from stdin", stderr=True) for f in context.CLIARGS['args'] or ['-']: self.editor.decrypt_file(f, output_file=context.CLIARGS['output_file']) if sys.stdout.isatty(): display.display("Decryption successful", stderr=True) def execute_create(self): """ create and open a file in an editor that will be encrypted with the provided vault secret when closed""" if len(context.CLIARGS['args']) != 1: raise AnsibleOptionsError("ansible-vault create can take only one filename argument") if sys.stdout.isatty() or context.CLIARGS['skip_tty_check']: self.editor.create_file(context.CLIARGS['args'][0], self.encrypt_secret, vault_id=self.encrypt_vault_id) else: raise AnsibleOptionsError("not a tty, editor cannot be opened") def execute_edit(self): """ open and decrypt an existing vaulted file in an editor, that will be encrypted again when closed""" for f in context.CLIARGS['args']: self.editor.edit_file(f) def execute_view(self): """ open, decrypt and view an existing vaulted file using a pager using the supplied vault secret """ for f in context.CLIARGS['args']: # Note: vault should return byte strings because it could encrypt # and decrypt binary files. We are responsible for changing it to # unicode here because we are displaying it and therefore can make # the decision that the display doesn't have to be precisely what # the input was (leave that to decrypt instead) plaintext = self.editor.plaintext(f) self.pager(to_text(plaintext)) def execute_rekey(self): """ re-encrypt a vaulted file with a new secret, the previous secret is required """ for f in context.CLIARGS['args']: # FIXME: plumb in vault_id, use the default new_vault_secret for now self.editor.rekey_file(f, self.new_encrypt_secret, self.new_encrypt_vault_id) display.display("Rekey successful", stderr=True) def main(args=None): VaultCLI.cli_executor(args) if __name__ == '__main__': main() ansible_core-2.19.0b5/lib/ansible/collections/0000755000000000000000000000000015017704211017714 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/collections/__init__.py0000644000000000000000000000000015017704211022013 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/collections/list.py0000644000000000000000000000547115017704211021250 0ustar00rootroot# (c) 2019 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations from ansible.errors import AnsibleError from ansible.cli.galaxy import with_collection_artifacts_manager from ansible.galaxy.collection import find_existing_collections from ansible.module_utils.common.text.converters import to_bytes from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path from ansible.utils.display import Display display = Display() @with_collection_artifacts_manager def list_collections(coll_filter=None, search_paths=None, dedupe=True, artifacts_manager=None): collections = {} for candidate in list_collection_dirs(search_paths=search_paths, coll_filter=coll_filter, artifacts_manager=artifacts_manager, dedupe=dedupe): collection = _get_collection_name_from_path(candidate) collections[collection] = candidate return collections @with_collection_artifacts_manager def list_collection_dirs(search_paths=None, coll_filter=None, artifacts_manager=None, dedupe=True): """ Return paths for the specific collections found in passed or configured search paths :param search_paths: list of text-string paths, if none load default config :param coll_filter: limit collections to just the specific namespace or collection, if None all are returned :return: list of collection directory paths """ namespace_filter = None collection_filter = None has_pure_namespace_filter = False # whether at least one coll_filter is a namespace-only filter if coll_filter is not None: if isinstance(coll_filter, str): coll_filter = [coll_filter] namespace_filter = set() for coll_name in coll_filter: if '.' in coll_name: try: namespace, collection = coll_name.split('.') except ValueError: raise AnsibleError("Invalid collection pattern supplied: %s" % coll_name) namespace_filter.add(namespace) if not has_pure_namespace_filter: if collection_filter is None: collection_filter = [] collection_filter.append(collection) else: namespace_filter.add(coll_name) has_pure_namespace_filter = True collection_filter = None namespace_filter = sorted(namespace_filter) for req in find_existing_collections(search_paths, artifacts_manager, namespace_filter=namespace_filter, collection_filter=collection_filter, dedupe=dedupe): if not has_pure_namespace_filter and coll_filter is not None and req.fqcn not in coll_filter: continue yield to_bytes(req.src) ansible_core-2.19.0b5/lib/ansible/compat/0000755000000000000000000000000015017704211016661 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/compat/__init__.py0000644000000000000000000000175215017704211020777 0ustar00rootroot# (c) 2014, Toshio Kuratomi # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . """ Compat library for ansible. This contains compatibility definitions for older python When we need to import a module differently depending on python version, do it here. Then in the code we can simply import from compat in order to get what we want. """ from __future__ import annotations ansible_core-2.19.0b5/lib/ansible/compat/importlib_resources.py0000644000000000000000000000103615017704211023326 0ustar00rootroot# Copyright: Contributors to the Ansible project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations from ansible.utils.display import Display as _Display from importlib.resources import files # pylint: disable=unused-import HAS_IMPORTLIB_RESOURCES = True _Display().deprecated( msg="The `ansible.compat.importlib_resources` module is deprecated.", help_text="Use `importlib.resources` from the Python standard library instead.", version="2.23", ) ansible_core-2.19.0b5/lib/ansible/config/0000755000000000000000000000000015017704211016643 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/config/__init__.py0000644000000000000000000000000015017704211020742 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/config/ansible_builtin_runtime.yml0000644000000000000000000133641415017704211024310 0ustar00rootroot# Copyright (c) 2020 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) plugin_routing: connection: # test entries redirected_local: redirect: ansible.builtin.local buildah: redirect: containers.podman.buildah podman: redirect: containers.podman.podman aws_ssm: redirect: community.aws.aws_ssm chroot: redirect: community.general.chroot docker: redirect: community.docker.docker funcd: redirect: community.general.funcd iocage: redirect: community.general.iocage jail: redirect: community.general.jail kubectl: redirect: kubernetes.core.kubectl libvirt_lxc: redirect: community.libvirt.libvirt_lxc lxc: redirect: community.general.lxc lxd: redirect: community.general.lxd oc: redirect: community.okd.oc qubes: redirect: community.general.qubes saltstack: redirect: community.general.saltstack zone: redirect: community.general.zone vmware_tools: redirect: community.vmware.vmware_tools httpapi: redirect: ansible.netcommon.httpapi napalm: redirect: ansible.netcommon.napalm netconf: redirect: ansible.netcommon.netconf network_cli: redirect: ansible.netcommon.network_cli persistent: redirect: ansible.netcommon.persistent modules: # test entry formerly_core_ping: redirect: testns.testcoll.ping # test entry uses_redirected_action: redirect: ansible.builtin.ping podman_container_info: redirect: containers.podman.podman_container_info podman_image_info: redirect: containers.podman.podman_image_info podman_image: redirect: containers.podman.podman_image podman_volume_info: redirect: containers.podman.podman_volume_info frr_facts: redirect: frr.frr.frr_facts frr_bgp: redirect: frr.frr.frr_bgp apt_repo: redirect: community.general.apt_repo aws_acm_facts: redirect: community.aws.aws_acm_facts aws_kms_facts: redirect: community.aws.aws_kms_facts aws_region_facts: redirect: community.aws.aws_region_facts aws_s3_bucket_facts: redirect: community.aws.aws_s3_bucket_facts aws_sgw_facts: redirect: community.aws.aws_sgw_facts aws_waf_facts: redirect: community.aws.aws_waf_facts cloudfront_facts: redirect: community.aws.cloudfront_facts cloudwatchlogs_log_group_facts: redirect: community.aws.cloudwatchlogs_log_group_facts ec2_asg_facts: redirect: community.aws.ec2_asg_facts ec2_customer_gateway_facts: redirect: community.aws.ec2_customer_gateway_facts ec2_instance_facts: redirect: community.aws.ec2_instance_facts ec2_eip_facts: redirect: community.aws.ec2_eip_facts ec2_elb_facts: redirect: community.aws.ec2_elb_facts ec2_lc_facts: redirect: community.aws.ec2_lc_facts ec2_placement_group_facts: redirect: community.aws.ec2_placement_group_facts ec2_vpc_endpoint_facts: redirect: community.aws.ec2_vpc_endpoint_facts ec2_vpc_igw_facts: redirect: community.aws.ec2_vpc_igw_facts ec2_vpc_nacl_facts: redirect: community.aws.ec2_vpc_nacl_facts ec2_vpc_nat_gateway_facts: redirect: community.aws.ec2_vpc_nat_gateway_facts ec2_vpc_peering_facts: redirect: community.aws.ec2_vpc_peering_facts ec2_vpc_route_table_facts: redirect: community.aws.ec2_vpc_route_table_facts ec2_vpc_vgw_facts: redirect: community.aws.ec2_vpc_vgw_facts ec2_vpc_vpn_facts: redirect: community.aws.ec2_vpc_vpn_facts ecs_service_facts: redirect: community.aws.ecs_service_facts ecs_taskdefinition_facts: redirect: community.aws.ecs_taskdefinition_facts efs_facts: redirect: community.aws.efs_facts elasticache_facts: redirect: community.aws.elasticache_facts elb_application_lb_facts: redirect: community.aws.elb_application_lb_facts elb_classic_lb_facts: redirect: community.aws.elb_classic_lb_facts elb_target_facts: redirect: community.aws.elb_target_facts elb_target_group_facts: redirect: community.aws.elb_target_group_facts iam_cert_facts: redirect: community.aws.iam_cert_facts iam_mfa_device_facts: redirect: community.aws.iam_mfa_device_facts iam_role_facts: redirect: community.aws.iam_role_facts iam_server_certificate_facts: redirect: community.aws.iam_server_certificate_facts lambda_facts: redirect: community.aws.lambda_facts rds_instance_facts: redirect: community.aws.rds_instance_facts rds_snapshot_facts: redirect: community.aws.rds_snapshot_facts redshift_facts: redirect: community.aws.redshift_facts route53_facts: redirect: community.aws.route53_facts aws_acm: redirect: community.aws.aws_acm aws_acm_info: redirect: community.aws.aws_acm_info aws_api_gateway: redirect: community.aws.aws_api_gateway aws_application_scaling_policy: redirect: community.aws.aws_application_scaling_policy aws_batch_compute_environment: redirect: community.aws.aws_batch_compute_environment aws_batch_job_definition: redirect: community.aws.aws_batch_job_definition aws_batch_job_queue: redirect: community.aws.aws_batch_job_queue aws_codebuild: redirect: community.aws.aws_codebuild aws_codecommit: redirect: community.aws.aws_codecommit aws_codepipeline: redirect: community.aws.aws_codepipeline aws_config_aggregation_authorization: redirect: community.aws.aws_config_aggregation_authorization aws_config_aggregator: redirect: community.aws.aws_config_aggregator aws_config_delivery_channel: redirect: community.aws.aws_config_delivery_channel aws_config_recorder: redirect: community.aws.aws_config_recorder aws_config_rule: redirect: community.aws.aws_config_rule aws_direct_connect_connection: redirect: community.aws.aws_direct_connect_connection aws_direct_connect_gateway: redirect: community.aws.aws_direct_connect_gateway aws_direct_connect_link_aggregation_group: redirect: community.aws.aws_direct_connect_link_aggregation_group aws_direct_connect_virtual_interface: redirect: community.aws.aws_direct_connect_virtual_interface aws_eks_cluster: redirect: community.aws.aws_eks_cluster aws_elasticbeanstalk_app: redirect: community.aws.aws_elasticbeanstalk_app aws_glue_connection: redirect: community.aws.aws_glue_connection aws_glue_job: redirect: community.aws.aws_glue_job aws_inspector_target: redirect: community.aws.aws_inspector_target aws_kms: redirect: community.aws.aws_kms aws_kms_info: redirect: community.aws.aws_kms_info aws_region_info: redirect: community.aws.aws_region_info aws_s3_bucket_info: redirect: community.aws.aws_s3_bucket_info aws_s3_cors: redirect: community.aws.aws_s3_cors aws_secret: redirect: community.aws.aws_secret aws_ses_identity: redirect: community.aws.aws_ses_identity aws_ses_identity_policy: redirect: community.aws.aws_ses_identity_policy aws_ses_rule_set: redirect: community.aws.aws_ses_rule_set aws_sgw_info: redirect: community.aws.aws_sgw_info aws_ssm_parameter_store: redirect: community.aws.aws_ssm_parameter_store aws_step_functions_state_machine: redirect: community.aws.aws_step_functions_state_machine aws_step_functions_state_machine_execution: redirect: community.aws.aws_step_functions_state_machine_execution aws_waf_condition: redirect: community.aws.aws_waf_condition aws_waf_info: redirect: community.aws.aws_waf_info aws_waf_rule: redirect: community.aws.aws_waf_rule aws_waf_web_acl: redirect: community.aws.aws_waf_web_acl cloudformation_stack_set: redirect: community.aws.cloudformation_stack_set cloudformation_exports_info: redirect: community.aws.cloudformation_exports_info cloudfront_distribution: redirect: community.aws.cloudfront_distribution cloudfront_info: redirect: community.aws.cloudfront_info cloudfront_invalidation: redirect: community.aws.cloudfront_invalidation cloudfront_origin_access_identity: redirect: community.aws.cloudfront_origin_access_identity cloudtrail: redirect: community.aws.cloudtrail cloudwatchevent_rule: redirect: community.aws.cloudwatchevent_rule cloudwatchlogs_log_group: redirect: community.aws.cloudwatchlogs_log_group cloudwatchlogs_log_group_info: redirect: community.aws.cloudwatchlogs_log_group_info cloudwatchlogs_log_group_metric_filter: redirect: community.aws.cloudwatchlogs_log_group_metric_filter data_pipeline: redirect: community.aws.data_pipeline dms_endpoint: redirect: community.aws.dms_endpoint dms_replication_subnet_group: redirect: community.aws.dms_replication_subnet_group dynamodb_table: redirect: community.aws.dynamodb_table dynamodb_ttl: redirect: community.aws.dynamodb_ttl ec2_ami_copy: redirect: community.aws.ec2_ami_copy ec2_asg: redirect: community.aws.ec2_asg ec2_asg_info: redirect: community.aws.ec2_asg_info ec2_asg_lifecycle_hook: redirect: community.aws.ec2_asg_lifecycle_hook ec2_customer_gateway: redirect: community.aws.ec2_customer_gateway ec2_customer_gateway_info: redirect: community.aws.ec2_customer_gateway_info ec2_eip: redirect: community.aws.ec2_eip ec2_eip_info: redirect: community.aws.ec2_eip_info ec2_elb: redirect: community.aws.ec2_elb ec2_elb_info: redirect: community.aws.ec2_elb_info ec2_instance: redirect: community.aws.ec2_instance ec2_instance_info: redirect: community.aws.ec2_instance_info ec2_launch_template: redirect: community.aws.ec2_launch_template ec2_lc: redirect: community.aws.ec2_lc ec2_lc_find: redirect: community.aws.ec2_lc_find ec2_lc_info: redirect: community.aws.ec2_lc_info ec2_metric_alarm: redirect: community.aws.ec2_metric_alarm ec2_placement_group: redirect: community.aws.ec2_placement_group ec2_placement_group_info: redirect: community.aws.ec2_placement_group_info ec2_scaling_policy: redirect: community.aws.ec2_scaling_policy ec2_snapshot_copy: redirect: community.aws.ec2_snapshot_copy ec2_transit_gateway: redirect: community.aws.ec2_transit_gateway ec2_transit_gateway_info: redirect: community.aws.ec2_transit_gateway_info ec2_vpc_egress_igw: redirect: community.aws.ec2_vpc_egress_igw ec2_vpc_endpoint: redirect: community.aws.ec2_vpc_endpoint ec2_vpc_endpoint_info: redirect: community.aws.ec2_vpc_endpoint_info ec2_vpc_igw: redirect: community.aws.ec2_vpc_igw ec2_vpc_igw_info: redirect: community.aws.ec2_vpc_igw_info ec2_vpc_nacl: redirect: community.aws.ec2_vpc_nacl ec2_vpc_nacl_info: redirect: community.aws.ec2_vpc_nacl_info ec2_vpc_nat_gateway: redirect: community.aws.ec2_vpc_nat_gateway ec2_vpc_nat_gateway_info: redirect: community.aws.ec2_vpc_nat_gateway_info ec2_vpc_peer: redirect: community.aws.ec2_vpc_peer ec2_vpc_peering_info: redirect: community.aws.ec2_vpc_peering_info ec2_vpc_route_table: redirect: community.aws.ec2_vpc_route_table ec2_vpc_route_table_info: redirect: community.aws.ec2_vpc_route_table_info ec2_vpc_vgw: redirect: community.aws.ec2_vpc_vgw ec2_vpc_vgw_info: redirect: community.aws.ec2_vpc_vgw_info ec2_vpc_vpn: redirect: community.aws.ec2_vpc_vpn ec2_vpc_vpn_info: redirect: community.aws.ec2_vpc_vpn_info ec2_win_password: redirect: community.aws.ec2_win_password ecs_attribute: redirect: community.aws.ecs_attribute ecs_cluster: redirect: community.aws.ecs_cluster ecs_ecr: redirect: community.aws.ecs_ecr ecs_service: redirect: community.aws.ecs_service ecs_service_info: redirect: community.aws.ecs_service_info ecs_tag: redirect: community.aws.ecs_tag ecs_task: redirect: community.aws.ecs_task ecs_taskdefinition: redirect: community.aws.ecs_taskdefinition ecs_taskdefinition_info: redirect: community.aws.ecs_taskdefinition_info efs: redirect: community.aws.efs efs_info: redirect: community.aws.efs_info elasticache: redirect: community.aws.elasticache elasticache_info: redirect: community.aws.elasticache_info elasticache_parameter_group: redirect: community.aws.elasticache_parameter_group elasticache_snapshot: redirect: community.aws.elasticache_snapshot elasticache_subnet_group: redirect: community.aws.elasticache_subnet_group elb_application_lb: redirect: community.aws.elb_application_lb elb_application_lb_info: redirect: community.aws.elb_application_lb_info elb_classic_lb: redirect: community.aws.elb_classic_lb elb_classic_lb_info: redirect: community.aws.elb_classic_lb_info elb_instance: redirect: community.aws.elb_instance elb_network_lb: redirect: community.aws.elb_network_lb elb_target: redirect: community.aws.elb_target elb_target_group: redirect: community.aws.elb_target_group elb_target_group_info: redirect: community.aws.elb_target_group_info elb_target_info: redirect: community.aws.elb_target_info execute_lambda: redirect: community.aws.execute_lambda iam: redirect: community.aws.iam iam_cert: redirect: community.aws.iam_cert iam_group: redirect: community.aws.iam_group iam_managed_policy: redirect: community.aws.iam_managed_policy iam_mfa_device_info: redirect: community.aws.iam_mfa_device_info iam_password_policy: redirect: community.aws.iam_password_policy iam_policy: redirect: community.aws.iam_policy iam_policy_info: redirect: community.aws.iam_policy_info iam_role: redirect: community.aws.iam_role iam_role_info: redirect: community.aws.iam_role_info iam_saml_federation: redirect: community.aws.iam_saml_federation iam_server_certificate_info: redirect: community.aws.iam_server_certificate_info iam_user: redirect: community.aws.iam_user iam_user_info: redirect: community.aws.iam_user_info kinesis_stream: redirect: community.aws.kinesis_stream lambda: redirect: community.aws.lambda lambda_alias: redirect: community.aws.lambda_alias lambda_event: redirect: community.aws.lambda_event lambda_info: redirect: community.aws.lambda_info lambda_policy: redirect: community.aws.lambda_policy lightsail: redirect: community.aws.lightsail rds: redirect: community.aws.rds rds_instance: redirect: community.aws.rds_instance rds_instance_info: redirect: community.aws.rds_instance_info rds_param_group: redirect: community.aws.rds_param_group rds_snapshot: redirect: community.aws.rds_snapshot rds_snapshot_info: redirect: community.aws.rds_snapshot_info rds_subnet_group: redirect: community.aws.rds_subnet_group redshift: redirect: community.aws.redshift redshift_cross_region_snapshots: redirect: community.aws.redshift_cross_region_snapshots redshift_info: redirect: community.aws.redshift_info redshift_subnet_group: redirect: community.aws.redshift_subnet_group route53: redirect: community.aws.route53 route53_health_check: redirect: community.aws.route53_health_check route53_info: redirect: community.aws.route53_info route53_zone: redirect: community.aws.route53_zone s3_bucket_notification: redirect: community.aws.s3_bucket_notification s3_lifecycle: redirect: community.aws.s3_lifecycle s3_logging: redirect: community.aws.s3_logging s3_sync: redirect: community.aws.s3_sync s3_website: redirect: community.aws.s3_website sns: redirect: community.aws.sns sns_topic: redirect: community.aws.sns_topic sqs_queue: redirect: community.aws.sqs_queue sts_assume_role: redirect: community.aws.sts_assume_role sts_session_token: redirect: community.aws.sts_session_token ali_instance_facts: redirect: community.general.ali_instance_facts ali_instance: redirect: community.general.ali_instance ali_instance_info: redirect: community.general.ali_instance_info atomic_container: redirect: community.general.atomic_container atomic_host: redirect: community.general.atomic_host atomic_image: redirect: community.general.atomic_image clc_aa_policy: redirect: community.general.clc_aa_policy clc_alert_policy: redirect: community.general.clc_alert_policy clc_blueprint_package: redirect: community.general.clc_blueprint_package clc_firewall_policy: redirect: community.general.clc_firewall_policy clc_group: redirect: community.general.clc_group clc_loadbalancer: redirect: community.general.clc_loadbalancer clc_modify_server: redirect: community.general.clc_modify_server clc_publicip: redirect: community.general.clc_publicip clc_server: redirect: community.general.clc_server clc_server_snapshot: redirect: community.general.clc_server_snapshot cloudscale_floating_ip: redirect: cloudscale_ch.cloud.floating_ip cloudscale_server: redirect: cloudscale_ch.cloud.server cloudscale_server_group: redirect: cloudscale_ch.cloud.server_group cloudscale_volume: redirect: cloudscale_ch.cloud.volume cs_instance_facts: redirect: ngine_io.cloudstack.cs_instance_info cs_zone_facts: redirect: ngine_io.cloudstack.cs_zone_info cs_account: redirect: ngine_io.cloudstack.cs_account cs_affinitygroup: redirect: ngine_io.cloudstack.cs_affinitygroup cs_cluster: redirect: ngine_io.cloudstack.cs_cluster cs_configuration: redirect: ngine_io.cloudstack.cs_configuration cs_disk_offering: redirect: ngine_io.cloudstack.cs_disk_offering cs_domain: redirect: ngine_io.cloudstack.cs_domain cs_facts: redirect: ngine_io.cloudstack.cs_facts cs_firewall: redirect: ngine_io.cloudstack.cs_firewall cs_host: redirect: ngine_io.cloudstack.cs_host cs_image_store: redirect: ngine_io.cloudstack.cs_image_store cs_instance: redirect: ngine_io.cloudstack.cs_instance cs_instance_info: redirect: ngine_io.cloudstack.cs_instance_info cs_instance_nic: redirect: ngine_io.cloudstack.cs_instance_nic cs_instance_nic_secondaryip: redirect: ngine_io.cloudstack.cs_instance_nic_secondaryip cs_instance_password_reset: redirect: ngine_io.cloudstack.cs_instance_password_reset cs_instancegroup: redirect: ngine_io.cloudstack.cs_instancegroup cs_ip_address: redirect: ngine_io.cloudstack.cs_ip_address cs_iso: redirect: ngine_io.cloudstack.cs_iso cs_loadbalancer_rule: redirect: ngine_io.cloudstack.cs_loadbalancer_rule cs_loadbalancer_rule_member: redirect: ngine_io.cloudstack.cs_loadbalancer_rule_member cs_network: redirect: ngine_io.cloudstack.cs_network cs_network_acl: redirect: ngine_io.cloudstack.cs_network_acl cs_network_acl_rule: redirect: ngine_io.cloudstack.cs_network_acl_rule cs_network_offering: redirect: ngine_io.cloudstack.cs_network_offering cs_physical_network: redirect: ngine_io.cloudstack.cs_physical_network cs_pod: redirect: ngine_io.cloudstack.cs_pod cs_portforward: redirect: ngine_io.cloudstack.cs_portforward cs_project: redirect: ngine_io.cloudstack.cs_project cs_region: redirect: ngine_io.cloudstack.cs_region cs_resourcelimit: redirect: ngine_io.cloudstack.cs_resourcelimit cs_role: redirect: ngine_io.cloudstack.cs_role cs_role_permission: redirect: ngine_io.cloudstack.cs_role_permission cs_router: redirect: ngine_io.cloudstack.cs_router cs_securitygroup: redirect: ngine_io.cloudstack.cs_securitygroup cs_securitygroup_rule: redirect: ngine_io.cloudstack.cs_securitygroup_rule cs_service_offering: redirect: ngine_io.cloudstack.cs_service_offering cs_snapshot_policy: redirect: ngine_io.cloudstack.cs_snapshot_policy cs_sshkeypair: redirect: ngine_io.cloudstack.cs_sshkeypair cs_staticnat: redirect: ngine_io.cloudstack.cs_staticnat cs_storage_pool: redirect: ngine_io.cloudstack.cs_storage_pool cs_template: redirect: ngine_io.cloudstack.cs_template cs_traffic_type: redirect: ngine_io.cloudstack.cs_traffic_type cs_user: redirect: ngine_io.cloudstack.cs_user cs_vlan_ip_range: redirect: ngine_io.cloudstack.cs_vlan_ip_range cs_vmsnapshot: redirect: ngine_io.cloudstack.cs_vmsnapshot cs_volume: redirect: ngine_io.cloudstack.cs_volume cs_vpc: redirect: ngine_io.cloudstack.cs_vpc cs_vpc_offering: redirect: ngine_io.cloudstack.cs_vpc_offering cs_vpn_connection: redirect: ngine_io.cloudstack.cs_vpn_connection cs_vpn_customer_gateway: redirect: ngine_io.cloudstack.cs_vpn_customer_gateway cs_vpn_gateway: redirect: ngine_io.cloudstack.cs_vpn_gateway cs_zone: redirect: ngine_io.cloudstack.cs_zone cs_zone_info: redirect: ngine_io.cloudstack.cs_zone_info digital_ocean: redirect: community.digitalocean.digital_ocean digital_ocean_account_facts: redirect: community.digitalocean.digital_ocean_account_facts digital_ocean_certificate_facts: redirect: community.digitalocean.digital_ocean_certificate_facts digital_ocean_domain_facts: redirect: community.digitalocean.digital_ocean_domain_facts digital_ocean_firewall_facts: redirect: community.digitalocean.digital_ocean_firewall_facts digital_ocean_floating_ip_facts: redirect: community.digitalocean.digital_ocean_floating_ip_facts digital_ocean_image_facts: redirect: community.digitalocean.digital_ocean_image_facts digital_ocean_load_balancer_facts: redirect: community.digitalocean.digital_ocean_load_balancer_facts digital_ocean_region_facts: redirect: community.digitalocean.digital_ocean_region_facts digital_ocean_size_facts: redirect: community.digitalocean.digital_ocean_size_facts digital_ocean_snapshot_facts: redirect: community.digitalocean.digital_ocean_snapshot_facts digital_ocean_sshkey_facts: redirect: community.digitalocean.digital_ocean_sshkey_facts digital_ocean_tag_facts: redirect: community.digitalocean.digital_ocean_tag_facts digital_ocean_volume_facts: redirect: community.digitalocean.digital_ocean_volume_facts digital_ocean_account_info: redirect: community.digitalocean.digital_ocean_account_info digital_ocean_block_storage: redirect: community.digitalocean.digital_ocean_block_storage digital_ocean_certificate: redirect: community.digitalocean.digital_ocean_certificate digital_ocean_certificate_info: redirect: community.digitalocean.digital_ocean_certificate_info digital_ocean_domain: redirect: community.digitalocean.digital_ocean_domain digital_ocean_domain_info: redirect: community.digitalocean.digital_ocean_domain_info digital_ocean_droplet: redirect: community.digitalocean.digital_ocean_droplet digital_ocean_firewall_info: redirect: community.digitalocean.digital_ocean_firewall_info digital_ocean_floating_ip: redirect: community.digitalocean.digital_ocean_floating_ip digital_ocean_floating_ip_info: redirect: community.digitalocean.digital_ocean_floating_ip_info digital_ocean_image_info: redirect: community.digitalocean.digital_ocean_image_info digital_ocean_load_balancer_info: redirect: community.digitalocean.digital_ocean_load_balancer_info digital_ocean_region_info: redirect: community.digitalocean.digital_ocean_region_info digital_ocean_size_info: redirect: community.digitalocean.digital_ocean_size_info digital_ocean_snapshot_info: redirect: community.digitalocean.digital_ocean_snapshot_info digital_ocean_sshkey: redirect: community.digitalocean.digital_ocean_sshkey digital_ocean_sshkey_info: redirect: community.digitalocean.digital_ocean_sshkey_info digital_ocean_tag: redirect: community.digitalocean.digital_ocean_tag digital_ocean_tag_info: redirect: community.digitalocean.digital_ocean_tag_info digital_ocean_volume_info: redirect: community.digitalocean.digital_ocean_volume_info dimensiondata_network: redirect: community.general.dimensiondata_network dimensiondata_vlan: redirect: community.general.dimensiondata_vlan docker_image_facts: redirect: community.general.docker_image_facts docker_service: redirect: community.general.docker_service docker_compose: redirect: community.docker.docker_compose docker_config: redirect: community.docker.docker_config docker_container: redirect: community.docker.docker_container docker_container_info: redirect: community.docker.docker_container_info docker_host_info: redirect: community.docker.docker_host_info docker_image: redirect: community.docker.docker_image docker_image_info: redirect: community.docker.docker_image_info docker_login: redirect: community.docker.docker_login docker_network: redirect: community.docker.docker_network docker_network_info: redirect: community.docker.docker_network_info docker_node: redirect: community.docker.docker_node docker_node_info: redirect: community.docker.docker_node_info docker_prune: redirect: community.docker.docker_prune docker_secret: redirect: community.docker.docker_secret docker_stack: redirect: community.docker.docker_stack docker_swarm: redirect: community.docker.docker_swarm docker_swarm_info: redirect: community.docker.docker_swarm_info docker_swarm_service: redirect: community.docker.docker_swarm_service docker_swarm_service_info: redirect: community.docker.docker_swarm_service_info docker_volume: redirect: community.docker.docker_volume docker_volume_info: redirect: community.docker.docker_volume_info gcdns_record: redirect: community.general.gcdns_record gcdns_zone: redirect: community.general.gcdns_zone gce: redirect: community.general.gce gcp_backend_service: redirect: community.general.gcp_backend_service gcp_bigquery_dataset_facts: redirect: google.cloud.gcp_bigquery_dataset_info gcp_bigquery_table_facts: redirect: google.cloud.gcp_bigquery_table_info gcp_cloudbuild_trigger_facts: redirect: google.cloud.gcp_cloudbuild_trigger_info gcp_compute_address_facts: redirect: google.cloud.gcp_compute_address_info gcp_compute_backend_bucket_facts: redirect: google.cloud.gcp_compute_backend_bucket_info gcp_compute_backend_service_facts: redirect: google.cloud.gcp_compute_backend_service_info gcp_compute_disk_facts: redirect: google.cloud.gcp_compute_disk_info gcp_compute_firewall_facts: redirect: google.cloud.gcp_compute_firewall_info gcp_compute_forwarding_rule_facts: redirect: google.cloud.gcp_compute_forwarding_rule_info gcp_compute_global_address_facts: redirect: google.cloud.gcp_compute_global_address_info gcp_compute_global_forwarding_rule_facts: redirect: google.cloud.gcp_compute_global_forwarding_rule_info gcp_compute_health_check_facts: redirect: google.cloud.gcp_compute_health_check_info gcp_compute_http_health_check_facts: redirect: google.cloud.gcp_compute_http_health_check_info gcp_compute_https_health_check_facts: redirect: google.cloud.gcp_compute_https_health_check_info gcp_compute_image_facts: redirect: google.cloud.gcp_compute_image_info gcp_compute_instance_facts: redirect: google.cloud.gcp_compute_instance_info gcp_compute_instance_group_facts: redirect: google.cloud.gcp_compute_instance_group_info gcp_compute_instance_group_manager_facts: redirect: google.cloud.gcp_compute_instance_group_manager_info gcp_compute_instance_template_facts: redirect: google.cloud.gcp_compute_instance_template_info gcp_compute_interconnect_attachment_facts: redirect: google.cloud.gcp_compute_interconnect_attachment_info gcp_compute_network_facts: redirect: google.cloud.gcp_compute_network_info gcp_compute_region_disk_facts: redirect: google.cloud.gcp_compute_region_disk_info gcp_compute_route_facts: redirect: google.cloud.gcp_compute_route_info gcp_compute_router_facts: redirect: google.cloud.gcp_compute_router_info gcp_compute_ssl_certificate_facts: redirect: google.cloud.gcp_compute_ssl_certificate_info gcp_compute_ssl_policy_facts: redirect: google.cloud.gcp_compute_ssl_policy_info gcp_compute_subnetwork_facts: redirect: google.cloud.gcp_compute_subnetwork_info gcp_compute_target_http_proxy_facts: redirect: google.cloud.gcp_compute_target_http_proxy_info gcp_compute_target_https_proxy_facts: redirect: google.cloud.gcp_compute_target_https_proxy_info gcp_compute_target_pool_facts: redirect: google.cloud.gcp_compute_target_pool_info gcp_compute_target_ssl_proxy_facts: redirect: google.cloud.gcp_compute_target_ssl_proxy_info gcp_compute_target_tcp_proxy_facts: redirect: google.cloud.gcp_compute_target_tcp_proxy_info gcp_compute_target_vpn_gateway_facts: redirect: google.cloud.gcp_compute_target_vpn_gateway_info gcp_compute_url_map_facts: redirect: google.cloud.gcp_compute_url_map_info gcp_compute_vpn_tunnel_facts: redirect: google.cloud.gcp_compute_vpn_tunnel_info gcp_container_cluster_facts: redirect: google.cloud.gcp_container_cluster_info gcp_container_node_pool_facts: redirect: google.cloud.gcp_container_node_pool_info gcp_dns_managed_zone_facts: redirect: google.cloud.gcp_dns_managed_zone_info gcp_dns_resource_record_set_facts: redirect: google.cloud.gcp_dns_resource_record_set_info gcp_forwarding_rule: redirect: community.general.gcp_forwarding_rule gcp_healthcheck: redirect: community.general.gcp_healthcheck gcp_iam_role_facts: redirect: google.cloud.gcp_iam_role_info gcp_iam_service_account_facts: redirect: google.cloud.gcp_iam_service_account_info gcp_pubsub_subscription_facts: redirect: google.cloud.gcp_pubsub_subscription_info gcp_pubsub_topic_facts: redirect: google.cloud.gcp_pubsub_topic_info gcp_redis_instance_facts: redirect: google.cloud.gcp_redis_instance_info gcp_resourcemanager_project_facts: redirect: google.cloud.gcp_resourcemanager_project_info gcp_sourcerepo_repository_facts: redirect: google.cloud.gcp_sourcerepo_repository_info gcp_spanner_database_facts: redirect: google.cloud.gcp_spanner_database_info gcp_spanner_instance_facts: redirect: google.cloud.gcp_spanner_instance_info gcp_sql_database_facts: redirect: google.cloud.gcp_sql_database_info gcp_sql_instance_facts: redirect: google.cloud.gcp_sql_instance_info gcp_sql_user_facts: redirect: google.cloud.gcp_sql_user_info gcp_target_proxy: redirect: community.general.gcp_target_proxy gcp_tpu_node_facts: redirect: google.cloud.gcp_tpu_node_info gcp_url_map: redirect: community.general.gcp_url_map gcpubsub_facts: redirect: community.general.gcpubsub_facts gcspanner: redirect: community.general.gcspanner gc_storage: redirect: community.google.gc_storage gce_eip: redirect: community.google.gce_eip gce_img: redirect: community.google.gce_img gce_instance_template: redirect: community.google.gce_instance_template gce_labels: redirect: community.google.gce_labels gce_lb: redirect: community.google.gce_lb gce_mig: redirect: community.google.gce_mig gce_net: redirect: community.google.gce_net gce_pd: redirect: community.google.gce_pd gce_snapshot: redirect: community.google.gce_snapshot gce_tag: redirect: community.google.gce_tag gcpubsub: redirect: community.google.gcpubsub gcpubsub_info: redirect: community.google.gcpubsub_info heroku_collaborator: redirect: community.general.heroku_collaborator hwc_ecs_instance: redirect: community.general.hwc_ecs_instance hwc_evs_disk: redirect: community.general.hwc_evs_disk hwc_network_vpc: redirect: community.general.hwc_network_vpc hwc_smn_topic: redirect: community.general.hwc_smn_topic hwc_vpc_eip: redirect: community.general.hwc_vpc_eip hwc_vpc_peering_connect: redirect: community.general.hwc_vpc_peering_connect hwc_vpc_port: redirect: community.general.hwc_vpc_port hwc_vpc_private_ip: redirect: community.general.hwc_vpc_private_ip hwc_vpc_route: redirect: community.general.hwc_vpc_route hwc_vpc_security_group: redirect: community.general.hwc_vpc_security_group hwc_vpc_security_group_rule: redirect: community.general.hwc_vpc_security_group_rule hwc_vpc_subnet: redirect: community.general.hwc_vpc_subnet kubevirt_cdi_upload: redirect: community.kubevirt.kubevirt_cdi_upload kubevirt_preset: redirect: community.kubevirt.kubevirt_preset kubevirt_pvc: redirect: community.kubevirt.kubevirt_pvc kubevirt_rs: redirect: community.kubevirt.kubevirt_rs kubevirt_template: redirect: community.kubevirt.kubevirt_template kubevirt_vm: redirect: community.kubevirt.kubevirt_vm linode: redirect: community.general.linode linode_v4: redirect: community.general.linode_v4 lxc_container: redirect: community.general.lxc_container lxd_container: redirect: community.general.lxd_container lxd_profile: redirect: community.general.lxd_profile memset_memstore_facts: redirect: community.general.memset_memstore_facts memset_server_facts: redirect: community.general.memset_server_facts memset_dns_reload: redirect: community.general.memset_dns_reload memset_memstore_info: redirect: community.general.memset_memstore_info memset_server_info: redirect: community.general.memset_server_info memset_zone: redirect: community.general.memset_zone memset_zone_domain: redirect: community.general.memset_zone_domain memset_zone_record: redirect: community.general.memset_zone_record cloud_init_data_facts: redirect: community.general.cloud_init_data_facts helm: redirect: community.general.helm ovirt: redirect: community.general.ovirt proxmox: redirect: community.general.proxmox proxmox_kvm: redirect: community.general.proxmox_kvm proxmox_template: redirect: community.general.proxmox_template rhevm: redirect: community.general.rhevm serverless: redirect: community.general.serverless terraform: redirect: community.general.terraform virt: redirect: community.libvirt.virt virt_net: redirect: community.libvirt.virt_net virt_pool: redirect: community.libvirt.virt_pool xenserver_facts: redirect: community.general.xenserver_facts oneandone_firewall_policy: redirect: community.general.oneandone_firewall_policy oneandone_load_balancer: redirect: community.general.oneandone_load_balancer oneandone_monitoring_policy: redirect: community.general.oneandone_monitoring_policy oneandone_private_network: redirect: community.general.oneandone_private_network oneandone_public_ip: redirect: community.general.oneandone_public_ip oneandone_server: redirect: community.general.oneandone_server online_server_facts: redirect: community.general.online_server_facts online_user_facts: redirect: community.general.online_user_facts online_server_info: redirect: community.general.online_server_info online_user_info: redirect: community.general.online_user_info one_image_facts: redirect: community.general.one_image_facts one_host: redirect: community.general.one_host one_image: redirect: community.general.one_image one_image_info: redirect: community.general.one_image_info one_service: redirect: community.general.one_service one_vm: redirect: community.general.one_vm os_flavor_facts: redirect: openstack.cloud.os_flavor_info os_image_facts: redirect: openstack.cloud.os_image_info os_keystone_domain_facts: redirect: openstack.cloud.os_keystone_domain_info os_networks_facts: redirect: openstack.cloud.os_networks_info os_port_facts: redirect: openstack.cloud.os_port_info os_project_facts: redirect: openstack.cloud.os_project_info os_server_facts: redirect: openstack.cloud.os_server_info os_subnets_facts: redirect: openstack.cloud.os_subnets_info os_user_facts: redirect: openstack.cloud.os_user_info oci_vcn: redirect: community.general.oci_vcn ovh_ip_failover: redirect: community.general.ovh_ip_failover ovh_ip_loadbalancing_backend: redirect: community.general.ovh_ip_loadbalancing_backend ovh_monthly_billing: redirect: community.general.ovh_monthly_billing ovirt_affinity_label_facts: redirect: community.general.ovirt_affinity_label_facts ovirt_api_facts: redirect: community.general.ovirt_api_facts ovirt_cluster_facts: redirect: community.general.ovirt_cluster_facts ovirt_datacenter_facts: redirect: community.general.ovirt_datacenter_facts ovirt_disk_facts: redirect: community.general.ovirt_disk_facts ovirt_event_facts: redirect: community.general.ovirt_event_facts ovirt_external_provider_facts: redirect: community.general.ovirt_external_provider_facts ovirt_group_facts: redirect: community.general.ovirt_group_facts ovirt_host_facts: redirect: community.general.ovirt_host_facts ovirt_host_storage_facts: redirect: community.general.ovirt_host_storage_facts ovirt_network_facts: redirect: community.general.ovirt_network_facts ovirt_nic_facts: redirect: community.general.ovirt_nic_facts ovirt_permission_facts: redirect: community.general.ovirt_permission_facts ovirt_quota_facts: redirect: community.general.ovirt_quota_facts ovirt_scheduling_policy_facts: redirect: community.general.ovirt_scheduling_policy_facts ovirt_snapshot_facts: redirect: community.general.ovirt_snapshot_facts ovirt_storage_domain_facts: redirect: community.general.ovirt_storage_domain_facts ovirt_storage_template_facts: redirect: community.general.ovirt_storage_template_facts ovirt_storage_vm_facts: redirect: community.general.ovirt_storage_vm_facts ovirt_tag_facts: redirect: community.general.ovirt_tag_facts ovirt_template_facts: redirect: community.general.ovirt_template_facts ovirt_user_facts: redirect: community.general.ovirt_user_facts ovirt_vm_facts: redirect: community.general.ovirt_vm_facts ovirt_vmpool_facts: redirect: community.general.ovirt_vmpool_facts packet_device: redirect: community.general.packet_device packet_ip_subnet: redirect: community.general.packet_ip_subnet packet_project: redirect: community.general.packet_project packet_sshkey: redirect: community.general.packet_sshkey packet_volume: redirect: community.general.packet_volume packet_volume_attachment: redirect: community.general.packet_volume_attachment profitbricks: redirect: community.general.profitbricks profitbricks_datacenter: redirect: community.general.profitbricks_datacenter profitbricks_nic: redirect: community.general.profitbricks_nic profitbricks_volume: redirect: community.general.profitbricks_volume profitbricks_volume_attachments: redirect: community.general.profitbricks_volume_attachments pubnub_blocks: redirect: community.general.pubnub_blocks rax: redirect: community.general.rax rax_cbs: redirect: community.general.rax_cbs rax_cbs_attachments: redirect: community.general.rax_cbs_attachments rax_cdb: redirect: community.general.rax_cdb rax_cdb_database: redirect: community.general.rax_cdb_database rax_cdb_user: redirect: community.general.rax_cdb_user rax_clb: redirect: community.general.rax_clb rax_clb_nodes: redirect: community.general.rax_clb_nodes rax_clb_ssl: redirect: community.general.rax_clb_ssl rax_dns: redirect: community.general.rax_dns rax_dns_record: redirect: community.general.rax_dns_record rax_facts: redirect: community.general.rax_facts rax_files: redirect: community.general.rax_files rax_files_objects: redirect: community.general.rax_files_objects rax_identity: redirect: community.general.rax_identity rax_keypair: redirect: community.general.rax_keypair rax_meta: redirect: community.general.rax_meta rax_mon_alarm: redirect: community.general.rax_mon_alarm rax_mon_check: redirect: community.general.rax_mon_check rax_mon_entity: redirect: community.general.rax_mon_entity rax_mon_notification: redirect: community.general.rax_mon_notification rax_mon_notification_plan: redirect: community.general.rax_mon_notification_plan rax_network: redirect: community.general.rax_network rax_queue: redirect: community.general.rax_queue rax_scaling_group: redirect: community.general.rax_scaling_group rax_scaling_policy: redirect: community.general.rax_scaling_policy scaleway_image_facts: redirect: community.general.scaleway_image_facts scaleway_ip_facts: redirect: community.general.scaleway_ip_facts scaleway_organization_facts: redirect: community.general.scaleway_organization_facts scaleway_security_group_facts: redirect: community.general.scaleway_security_group_facts scaleway_server_facts: redirect: community.general.scaleway_server_facts scaleway_snapshot_facts: redirect: community.general.scaleway_snapshot_facts scaleway_volume_facts: redirect: community.general.scaleway_volume_facts scaleway_compute: redirect: community.general.scaleway_compute scaleway_image_info: redirect: community.general.scaleway_image_info scaleway_ip: redirect: community.general.scaleway_ip scaleway_ip_info: redirect: community.general.scaleway_ip_info scaleway_lb: redirect: community.general.scaleway_lb scaleway_organization_info: redirect: community.general.scaleway_organization_info scaleway_security_group: redirect: community.general.scaleway_security_group scaleway_security_group_info: redirect: community.general.scaleway_security_group_info scaleway_security_group_rule: redirect: community.general.scaleway_security_group_rule scaleway_server_info: redirect: community.general.scaleway_server_info scaleway_snapshot_info: redirect: community.general.scaleway_snapshot_info scaleway_sshkey: redirect: community.general.scaleway_sshkey scaleway_user_data: redirect: community.general.scaleway_user_data scaleway_volume: redirect: community.general.scaleway_volume scaleway_volume_info: redirect: community.general.scaleway_volume_info smartos_image_facts: redirect: community.general.smartos_image_facts imgadm: redirect: community.general.imgadm nictagadm: redirect: community.general.nictagadm smartos_image_info: redirect: community.general.smartos_image_info vmadm: redirect: community.general.vmadm sl_vm: redirect: community.general.sl_vm spotinst_aws_elastigroup: redirect: community.general.spotinst_aws_elastigroup udm_dns_record: redirect: community.general.udm_dns_record udm_dns_zone: redirect: community.general.udm_dns_zone udm_group: redirect: community.general.udm_group udm_share: redirect: community.general.udm_share udm_user: redirect: community.general.udm_user vr_account_facts: redirect: ngine_io.vultr.vultr_account_facts vr_dns_domain: redirect: ngine_io.vultr.vultr_dns_domain vr_dns_record: redirect: ngine_io.vultr.vultr_dns_record vr_firewall_group: redirect: ngine_io.vultr.vultr_firewall_group vr_firewall_rule: redirect: ngine_io.vultr.vultr_firewall_rule vr_server: redirect: ngine_io.vultr.vultr_server vr_ssh_key: redirect: ngine_io.vultr.vultr_ssh_key vr_startup_script: redirect: ngine_io.vultr.vultr_startup_script vr_user: redirect: ngine_io.vultr.vultr_user vultr_account_facts: redirect: ngine_io.vultr.vultr_account_info vultr_block_storage_facts: redirect: ngine_io.vultr.vultr_block_storage_info vultr_dns_domain_facts: redirect: ngine_io.vultr.vultr_dns_domain_info vultr_firewall_group_facts: redirect: ngine_io.vultr.vultr_firewall_group_info vultr_network_facts: redirect: ngine_io.vultr.vultr_network_info vultr_os_facts: redirect: ngine_io.vultr.vultr_os_info vultr_plan_facts: redirect: ngine_io.vultr.vultr_plan_info vultr_region_facts: redirect: ngine_io.vultr.vultr_region_info vultr_server_facts: redirect: ngine_io.vultr.vultr_server_info vultr_ssh_key_facts: redirect: ngine_io.vultr.vultr_ssh_key_info vultr_startup_script_facts: redirect: ngine_io.vultr.vultr_startup_script_info vultr_user_facts: redirect: ngine_io.vultr.vultr_user_info vultr_account_info: redirect: ngine_io.vultr.vultr_account_info vultr_block_storage: redirect: ngine_io.vultr.vultr_block_storage vultr_block_storage_info: redirect: ngine_io.vultr.vultr_block_storage_info vultr_dns_domain: redirect: ngine_io.vultr.vultr_dns_domain vultr_dns_domain_info: redirect: ngine_io.vultr.vultr_dns_domain_info vultr_dns_record: redirect: ngine_io.vultr.vultr_dns_record vultr_firewall_group: redirect: ngine_io.vultr.vultr_firewall_group vultr_firewall_group_info: redirect: ngine_io.vultr.vultr_firewall_group_info vultr_firewall_rule: redirect: ngine_io.vultr.vultr_firewall_rule vultr_network: redirect: ngine_io.vultr.vultr_network vultr_network_info: redirect: ngine_io.vultr.vultr_network_info vultr_os_info: redirect: ngine_io.vultr.vultr_os_info vultr_plan_info: redirect: ngine_io.vultr.vultr_plan_info vultr_region_info: redirect: ngine_io.vultr.vultr_region_info vultr_server: redirect: ngine_io.vultr.vultr_server vultr_server_info: redirect: ngine_io.vultr.vultr_server_info vultr_ssh_key: redirect: ngine_io.vultr.vultr_ssh_key vultr_ssh_key_info: redirect: ngine_io.vultr.vultr_ssh_key_info vultr_startup_script: redirect: ngine_io.vultr.vultr_startup_script vultr_startup_script_info: redirect: ngine_io.vultr.vultr_startup_script_info vultr_user: redirect: ngine_io.vultr.vultr_user vultr_user_info: redirect: ngine_io.vultr.vultr_user_info webfaction_app: redirect: community.general.webfaction_app webfaction_db: redirect: community.general.webfaction_db webfaction_domain: redirect: community.general.webfaction_domain webfaction_mailbox: redirect: community.general.webfaction_mailbox webfaction_site: redirect: community.general.webfaction_site xenserver_guest_facts: redirect: community.general.xenserver_guest_facts xenserver_guest: redirect: community.general.xenserver_guest xenserver_guest_info: redirect: community.general.xenserver_guest_info xenserver_guest_powerstate: redirect: community.general.xenserver_guest_powerstate consul: redirect: community.general.consul consul_acl: redirect: community.general.consul_acl consul_kv: redirect: community.general.consul_kv consul_session: redirect: community.general.consul_session etcd3: redirect: community.general.etcd3 pacemaker_cluster: redirect: community.general.pacemaker_cluster znode: redirect: community.general.znode aerospike_migrations: redirect: community.general.aerospike_migrations influxdb_database: redirect: community.general.influxdb_database influxdb_query: redirect: community.general.influxdb_query influxdb_retention_policy: redirect: community.general.influxdb_retention_policy influxdb_user: redirect: community.general.influxdb_user influxdb_write: redirect: community.general.influxdb_write elasticsearch_plugin: redirect: community.general.elasticsearch_plugin kibana_plugin: redirect: community.general.kibana_plugin redis: redirect: community.general.redis riak: redirect: community.general.riak mssql_db: redirect: community.general.mssql_db mysql_db: redirect: community.mysql.mysql_db mysql_info: redirect: community.mysql.mysql_info mysql_query: redirect: community.mysql.mysql_query mysql_replication: redirect: community.mysql.mysql_replication mysql_user: redirect: community.mysql.mysql_user mysql_variables: redirect: community.mysql.mysql_variables postgresql_copy: redirect: community.postgresql.postgresql_copy postgresql_db: redirect: community.postgresql.postgresql_db postgresql_ext: redirect: community.postgresql.postgresql_ext postgresql_idx: redirect: community.postgresql.postgresql_idx postgresql_info: redirect: community.postgresql.postgresql_info postgresql_lang: redirect: community.postgresql.postgresql_lang postgresql_membership: redirect: community.postgresql.postgresql_membership postgresql_owner: redirect: community.postgresql.postgresql_owner postgresql_pg_hba: redirect: community.postgresql.postgresql_pg_hba postgresql_ping: redirect: community.postgresql.postgresql_ping postgresql_privs: redirect: community.postgresql.postgresql_privs postgresql_publication: redirect: community.postgresql.postgresql_publication postgresql_query: redirect: community.postgresql.postgresql_query postgresql_schema: redirect: community.postgresql.postgresql_schema postgresql_sequence: redirect: community.postgresql.postgresql_sequence postgresql_set: redirect: community.postgresql.postgresql_set postgresql_slot: redirect: community.postgresql.postgresql_slot postgresql_subscription: redirect: community.postgresql.postgresql_subscription postgresql_table: redirect: community.postgresql.postgresql_table postgresql_tablespace: redirect: community.postgresql.postgresql_tablespace postgresql_user: redirect: community.postgresql.postgresql_user postgresql_user_obj_stat_info: redirect: community.postgresql.postgresql_user_obj_stat_info proxysql_backend_servers: redirect: community.proxysql.proxysql_backend_servers proxysql_global_variables: redirect: community.proxysql.proxysql_global_variables proxysql_manage_config: redirect: community.proxysql.proxysql_manage_config proxysql_mysql_users: redirect: community.proxysql.proxysql_mysql_users proxysql_query_rules: redirect: community.proxysql.proxysql_query_rules proxysql_replication_hostgroups: redirect: community.proxysql.proxysql_replication_hostgroups proxysql_scheduler: redirect: community.proxysql.proxysql_scheduler vertica_facts: redirect: community.general.vertica_facts vertica_configuration: redirect: community.general.vertica_configuration vertica_info: redirect: community.general.vertica_info vertica_role: redirect: community.general.vertica_role vertica_schema: redirect: community.general.vertica_schema vertica_user: redirect: community.general.vertica_user archive: redirect: community.general.archive ini_file: redirect: community.general.ini_file iso_extract: redirect: community.general.iso_extract patch: redirect: ansible.posix.patch read_csv: redirect: community.general.read_csv xattr: redirect: community.general.xattr xml: redirect: community.general.xml onepassword_facts: redirect: community.general.onepassword_facts ipa_config: redirect: community.general.ipa_config ipa_dnsrecord: redirect: community.general.ipa_dnsrecord ipa_dnszone: redirect: community.general.ipa_dnszone ipa_group: redirect: community.general.ipa_group ipa_hbacrule: redirect: community.general.ipa_hbacrule ipa_host: redirect: community.general.ipa_host ipa_hostgroup: redirect: community.general.ipa_hostgroup ipa_role: redirect: community.general.ipa_role ipa_service: redirect: community.general.ipa_service ipa_subca: redirect: community.general.ipa_subca ipa_sudocmd: redirect: community.general.ipa_sudocmd ipa_sudocmdgroup: redirect: community.general.ipa_sudocmdgroup ipa_sudorule: redirect: community.general.ipa_sudorule ipa_user: redirect: community.general.ipa_user ipa_vault: redirect: community.general.ipa_vault keycloak_client: redirect: community.general.keycloak_client keycloak_clienttemplate: redirect: community.general.keycloak_clienttemplate keycloak_group: redirect: community.general.keycloak_group onepassword_info: redirect: community.general.onepassword_info opendj_backendprop: redirect: community.general.opendj_backendprop rabbitmq_binding: redirect: community.rabbitmq.rabbitmq_binding rabbitmq_exchange: redirect: community.rabbitmq.rabbitmq_exchange rabbitmq_global_parameter: redirect: community.rabbitmq.rabbitmq_global_parameter rabbitmq_parameter: redirect: community.rabbitmq.rabbitmq_parameter rabbitmq_plugin: redirect: community.rabbitmq.rabbitmq_plugin rabbitmq_policy: redirect: community.rabbitmq.rabbitmq_policy rabbitmq_queue: redirect: community.rabbitmq.rabbitmq_queue rabbitmq_user: redirect: community.rabbitmq.rabbitmq_user rabbitmq_vhost: redirect: community.rabbitmq.rabbitmq_vhost rabbitmq_vhost_limits: redirect: community.rabbitmq.rabbitmq_vhost_limits airbrake_deployment: redirect: community.general.airbrake_deployment bigpanda: redirect: community.general.bigpanda circonus_annotation: redirect: community.general.circonus_annotation datadog_event: redirect: community.general.datadog_event datadog_monitor: redirect: community.general.datadog_monitor honeybadger_deployment: redirect: community.general.honeybadger_deployment icinga2_feature: redirect: community.general.icinga2_feature icinga2_host: redirect: community.general.icinga2_host librato_annotation: redirect: community.general.librato_annotation logentries: redirect: community.general.logentries logicmonitor: redirect: community.general.logicmonitor logicmonitor_facts: redirect: community.general.logicmonitor_facts logstash_plugin: redirect: community.general.logstash_plugin monit: redirect: community.general.monit nagios: redirect: community.general.nagios newrelic_deployment: redirect: community.general.newrelic_deployment pagerduty: redirect: community.general.pagerduty pagerduty_alert: redirect: community.general.pagerduty_alert pingdom: redirect: community.general.pingdom rollbar_deployment: redirect: community.general.rollbar_deployment sensu_check: redirect: community.general.sensu_check sensu_client: redirect: community.general.sensu_client sensu_handler: redirect: community.general.sensu_handler sensu_silence: redirect: community.general.sensu_silence sensu_subscription: redirect: community.general.sensu_subscription spectrum_device: redirect: community.general.spectrum_device stackdriver: redirect: community.general.stackdriver statusio_maintenance: redirect: community.general.statusio_maintenance uptimerobot: redirect: community.general.uptimerobot zabbix_group_facts: redirect: community.zabbix.zabbix_group_facts zabbix_host_facts: redirect: community.zabbix.zabbix_host_facts zabbix_action: redirect: community.zabbix.zabbix_action zabbix_group: redirect: community.zabbix.zabbix_group zabbix_group_info: redirect: community.zabbix.zabbix_group_info zabbix_host: redirect: community.zabbix.zabbix_host zabbix_host_events_info: redirect: community.zabbix.zabbix_host_events_info zabbix_host_info: redirect: community.zabbix.zabbix_host_info zabbix_hostmacro: redirect: community.zabbix.zabbix_hostmacro zabbix_maintenance: redirect: community.zabbix.zabbix_maintenance zabbix_map: redirect: community.zabbix.zabbix_map zabbix_mediatype: redirect: community.zabbix.zabbix_mediatype zabbix_proxy: redirect: community.zabbix.zabbix_proxy zabbix_screen: redirect: community.zabbix.zabbix_screen zabbix_service: redirect: community.zabbix.zabbix_service zabbix_template: redirect: community.zabbix.zabbix_template zabbix_template_info: redirect: community.zabbix.zabbix_template_info zabbix_user: redirect: community.zabbix.zabbix_user zabbix_user_info: redirect: community.zabbix.zabbix_user_info zabbix_valuemap: redirect: community.zabbix.zabbix_valuemap cloudflare_dns: redirect: community.general.cloudflare_dns dnsimple: redirect: community.general.dnsimple dnsmadeeasy: redirect: community.general.dnsmadeeasy exo_dns_domain: redirect: ngine_io.exoscale.exo_dns_domain exo_dns_record: redirect: ngine_io.exoscale.exo_dns_record haproxy: redirect: community.general.haproxy hetzner_failover_ip: redirect: community.hrobot.failover_ip hetzner_failover_ip_info: redirect: community.hrobot.failover_ip_info hetzner_firewall: redirect: community.hrobot.firewall hetzner_firewall_info: redirect: community.hrobot.firewall_info infinity: redirect: community.general.infinity ip_netns: redirect: community.general.ip_netns ipify_facts: redirect: community.general.ipify_facts ipinfoio_facts: redirect: community.general.ipinfoio_facts ipwcli_dns: redirect: community.general.ipwcli_dns ldap_attr: redirect: community.general.ldap_attr ldap_attrs: redirect: community.general.ldap_attrs ldap_entry: redirect: community.general.ldap_entry ldap_passwd: redirect: community.general.ldap_passwd lldp: redirect: community.general.lldp netcup_dns: redirect: community.general.netcup_dns nios_a_record: redirect: community.general.nios_a_record nios_aaaa_record: redirect: community.general.nios_aaaa_record nios_cname_record: redirect: community.general.nios_cname_record nios_dns_view: redirect: community.general.nios_dns_view nios_fixed_address: redirect: community.general.nios_fixed_address nios_host_record: redirect: community.general.nios_host_record nios_member: redirect: community.general.nios_member nios_mx_record: redirect: community.general.nios_mx_record nios_naptr_record: redirect: community.general.nios_naptr_record nios_network: redirect: community.general.nios_network nios_network_view: redirect: community.general.nios_network_view nios_nsgroup: redirect: community.general.nios_nsgroup nios_ptr_record: redirect: community.general.nios_ptr_record nios_srv_record: redirect: community.general.nios_srv_record nios_txt_record: redirect: community.general.nios_txt_record nios_zone: redirect: community.general.nios_zone nmcli: redirect: community.general.nmcli nsupdate: redirect: community.general.nsupdate omapi_host: redirect: community.general.omapi_host snmp_facts: redirect: community.general.snmp_facts a10_server: redirect: community.network.a10_server a10_server_axapi3: redirect: community.network.a10_server_axapi3 a10_service_group: redirect: community.network.a10_service_group a10_virtual_server: redirect: community.network.a10_virtual_server aci_intf_policy_fc: redirect: cisco.aci.aci_interface_policy_fc aci_intf_policy_l2: redirect: cisco.aci.aci_interface_policy_l2 aci_intf_policy_lldp: redirect: cisco.aci.aci_interface_policy_lldp aci_intf_policy_mcp: redirect: cisco.aci.aci_interface_policy_mcp aci_intf_policy_port_channel: redirect: cisco.aci.aci_interface_policy_port_channel aci_intf_policy_port_security: redirect: cisco.aci.aci_interface_policy_port_security mso_schema_template_external_epg_contract: redirect: cisco.mso.mso_schema_template_external_epg_contract mso_schema_template_external_epg_subnet: redirect: cisco.mso.mso_schema_template_external_epg_subnet aireos_command: redirect: community.network.aireos_command aireos_config: redirect: community.network.aireos_config apconos_command: redirect: community.network.apconos_command aruba_command: redirect: community.network.aruba_command aruba_config: redirect: community.network.aruba_config avi_actiongroupconfig: redirect: community.network.avi_actiongroupconfig avi_alertconfig: redirect: community.network.avi_alertconfig avi_alertemailconfig: redirect: community.network.avi_alertemailconfig avi_alertscriptconfig: redirect: community.network.avi_alertscriptconfig avi_alertsyslogconfig: redirect: community.network.avi_alertsyslogconfig avi_analyticsprofile: redirect: community.network.avi_analyticsprofile avi_api_session: redirect: community.network.avi_api_session avi_api_version: redirect: community.network.avi_api_version avi_applicationpersistenceprofile: redirect: community.network.avi_applicationpersistenceprofile avi_applicationprofile: redirect: community.network.avi_applicationprofile avi_authprofile: redirect: community.network.avi_authprofile avi_autoscalelaunchconfig: redirect: community.network.avi_autoscalelaunchconfig avi_backup: redirect: community.network.avi_backup avi_backupconfiguration: redirect: community.network.avi_backupconfiguration avi_certificatemanagementprofile: redirect: community.network.avi_certificatemanagementprofile avi_cloud: redirect: community.network.avi_cloud avi_cloudconnectoruser: redirect: community.network.avi_cloudconnectoruser avi_cloudproperties: redirect: community.network.avi_cloudproperties avi_cluster: redirect: community.network.avi_cluster avi_clusterclouddetails: redirect: community.network.avi_clusterclouddetails avi_controllerproperties: redirect: community.network.avi_controllerproperties avi_customipamdnsprofile: redirect: community.network.avi_customipamdnsprofile avi_dnspolicy: redirect: community.network.avi_dnspolicy avi_errorpagebody: redirect: community.network.avi_errorpagebody avi_errorpageprofile: redirect: community.network.avi_errorpageprofile avi_gslb: redirect: community.network.avi_gslb avi_gslbgeodbprofile: redirect: community.network.avi_gslbgeodbprofile avi_gslbservice: redirect: community.network.avi_gslbservice avi_gslbservice_patch_member: redirect: community.network.avi_gslbservice_patch_member avi_hardwaresecuritymodulegroup: redirect: community.network.avi_hardwaresecuritymodulegroup avi_healthmonitor: redirect: community.network.avi_healthmonitor avi_httppolicyset: redirect: community.network.avi_httppolicyset avi_ipaddrgroup: redirect: community.network.avi_ipaddrgroup avi_ipamdnsproviderprofile: redirect: community.network.avi_ipamdnsproviderprofile avi_l4policyset: redirect: community.network.avi_l4policyset avi_microservicegroup: redirect: community.network.avi_microservicegroup avi_network: redirect: community.network.avi_network avi_networkprofile: redirect: community.network.avi_networkprofile avi_networksecuritypolicy: redirect: community.network.avi_networksecuritypolicy avi_pkiprofile: redirect: community.network.avi_pkiprofile avi_pool: redirect: community.network.avi_pool avi_poolgroup: redirect: community.network.avi_poolgroup avi_poolgroupdeploymentpolicy: redirect: community.network.avi_poolgroupdeploymentpolicy avi_prioritylabels: redirect: community.network.avi_prioritylabels avi_role: redirect: community.network.avi_role avi_scheduler: redirect: community.network.avi_scheduler avi_seproperties: redirect: community.network.avi_seproperties avi_serverautoscalepolicy: redirect: community.network.avi_serverautoscalepolicy avi_serviceengine: redirect: community.network.avi_serviceengine avi_serviceenginegroup: redirect: community.network.avi_serviceenginegroup avi_snmptrapprofile: redirect: community.network.avi_snmptrapprofile avi_sslkeyandcertificate: redirect: community.network.avi_sslkeyandcertificate avi_sslprofile: redirect: community.network.avi_sslprofile avi_stringgroup: redirect: community.network.avi_stringgroup avi_systemconfiguration: redirect: community.network.avi_systemconfiguration avi_tenant: redirect: community.network.avi_tenant avi_trafficcloneprofile: redirect: community.network.avi_trafficcloneprofile avi_user: redirect: community.network.avi_user avi_useraccount: redirect: community.network.avi_useraccount avi_useraccountprofile: redirect: community.network.avi_useraccountprofile avi_virtualservice: redirect: community.network.avi_virtualservice avi_vrfcontext: redirect: community.network.avi_vrfcontext avi_vsdatascriptset: redirect: community.network.avi_vsdatascriptset avi_vsvip: redirect: community.network.avi_vsvip avi_webhook: redirect: community.network.avi_webhook bcf_switch: redirect: community.network.bcf_switch bigmon_chain: redirect: community.network.bigmon_chain bigmon_policy: redirect: community.network.bigmon_policy checkpoint_access_layer_facts: redirect: check_point.mgmt.checkpoint_access_layer_facts checkpoint_access_rule: redirect: check_point.mgmt.checkpoint_access_rule checkpoint_access_rule_facts: redirect: check_point.mgmt.checkpoint_access_rule_facts checkpoint_host: redirect: check_point.mgmt.checkpoint_host checkpoint_host_facts: redirect: check_point.mgmt.checkpoint_host_facts checkpoint_object_facts: redirect: check_point.mgmt.checkpoint_object_facts checkpoint_run_script: redirect: check_point.mgmt.checkpoint_run_script checkpoint_session: redirect: check_point.mgmt.checkpoint_session checkpoint_task_facts: redirect: check_point.mgmt.checkpoint_task_facts cp_publish: redirect: community.network.cp_publish ce_aaa_server: redirect: community.network.ce_aaa_server ce_aaa_server_host: redirect: community.network.ce_aaa_server_host ce_acl: redirect: community.network.ce_acl ce_acl_advance: redirect: community.network.ce_acl_advance ce_acl_interface: redirect: community.network.ce_acl_interface ce_bfd_global: redirect: community.network.ce_bfd_global ce_bfd_session: redirect: community.network.ce_bfd_session ce_bfd_view: redirect: community.network.ce_bfd_view ce_bgp: redirect: community.network.ce_bgp ce_bgp_af: redirect: community.network.ce_bgp_af ce_bgp_neighbor: redirect: community.network.ce_bgp_neighbor ce_bgp_neighbor_af: redirect: community.network.ce_bgp_neighbor_af ce_command: redirect: community.network.ce_command ce_config: redirect: community.network.ce_config ce_dldp: redirect: community.network.ce_dldp ce_dldp_interface: redirect: community.network.ce_dldp_interface ce_eth_trunk: redirect: community.network.ce_eth_trunk ce_evpn_bd_vni: redirect: community.network.ce_evpn_bd_vni ce_evpn_bgp: redirect: community.network.ce_evpn_bgp ce_evpn_bgp_rr: redirect: community.network.ce_evpn_bgp_rr ce_evpn_global: redirect: community.network.ce_evpn_global ce_facts: redirect: community.network.ce_facts ce_file_copy: redirect: community.network.ce_file_copy ce_info_center_debug: redirect: community.network.ce_info_center_debug ce_info_center_global: redirect: community.network.ce_info_center_global ce_info_center_log: redirect: community.network.ce_info_center_log ce_info_center_trap: redirect: community.network.ce_info_center_trap ce_interface: redirect: community.network.ce_interface ce_interface_ospf: redirect: community.network.ce_interface_ospf ce_ip_interface: redirect: community.network.ce_ip_interface ce_is_is_instance: redirect: community.network.ce_is_is_instance ce_is_is_interface: redirect: community.network.ce_is_is_interface ce_is_is_view: redirect: community.network.ce_is_is_view ce_lacp: redirect: community.network.ce_lacp ce_link_status: redirect: community.network.ce_link_status ce_lldp: redirect: community.network.ce_lldp ce_lldp_interface: redirect: community.network.ce_lldp_interface ce_mdn_interface: redirect: community.network.ce_mdn_interface ce_mlag_config: redirect: community.network.ce_mlag_config ce_mlag_interface: redirect: community.network.ce_mlag_interface ce_mtu: redirect: community.network.ce_mtu ce_multicast_global: redirect: community.network.ce_multicast_global ce_multicast_igmp_enable: redirect: community.network.ce_multicast_igmp_enable ce_netconf: redirect: community.network.ce_netconf ce_netstream_aging: redirect: community.network.ce_netstream_aging ce_netstream_export: redirect: community.network.ce_netstream_export ce_netstream_global: redirect: community.network.ce_netstream_global ce_netstream_template: redirect: community.network.ce_netstream_template ce_ntp: redirect: community.network.ce_ntp ce_ntp_auth: redirect: community.network.ce_ntp_auth ce_ospf: redirect: community.network.ce_ospf ce_ospf_vrf: redirect: community.network.ce_ospf_vrf ce_reboot: redirect: community.network.ce_reboot ce_rollback: redirect: community.network.ce_rollback ce_sflow: redirect: community.network.ce_sflow ce_snmp_community: redirect: community.network.ce_snmp_community ce_snmp_contact: redirect: community.network.ce_snmp_contact ce_snmp_location: redirect: community.network.ce_snmp_location ce_snmp_target_host: redirect: community.network.ce_snmp_target_host ce_snmp_traps: redirect: community.network.ce_snmp_traps ce_snmp_user: redirect: community.network.ce_snmp_user ce_startup: redirect: community.network.ce_startup ce_static_route: redirect: community.network.ce_static_route ce_static_route_bfd: redirect: community.network.ce_static_route_bfd ce_stp: redirect: community.network.ce_stp ce_switchport: redirect: community.network.ce_switchport ce_vlan: redirect: community.network.ce_vlan ce_vrf: redirect: community.network.ce_vrf ce_vrf_af: redirect: community.network.ce_vrf_af ce_vrf_interface: redirect: community.network.ce_vrf_interface ce_vrrp: redirect: community.network.ce_vrrp ce_vxlan_arp: redirect: community.network.ce_vxlan_arp ce_vxlan_gateway: redirect: community.network.ce_vxlan_gateway ce_vxlan_global: redirect: community.network.ce_vxlan_global ce_vxlan_tunnel: redirect: community.network.ce_vxlan_tunnel ce_vxlan_vap: redirect: community.network.ce_vxlan_vap cv_server_provision: redirect: community.network.cv_server_provision cnos_backup: redirect: community.network.cnos_backup cnos_banner: redirect: community.network.cnos_banner cnos_bgp: redirect: community.network.cnos_bgp cnos_command: redirect: community.network.cnos_command cnos_conditional_command: redirect: community.network.cnos_conditional_command cnos_conditional_template: redirect: community.network.cnos_conditional_template cnos_config: redirect: community.network.cnos_config cnos_factory: redirect: community.network.cnos_factory cnos_facts: redirect: community.network.cnos_facts cnos_image: redirect: community.network.cnos_image cnos_interface: redirect: community.network.cnos_interface cnos_l2_interface: redirect: community.network.cnos_l2_interface cnos_l3_interface: redirect: community.network.cnos_l3_interface cnos_linkagg: redirect: community.network.cnos_linkagg cnos_lldp: redirect: community.network.cnos_lldp cnos_logging: redirect: community.network.cnos_logging cnos_reload: redirect: community.network.cnos_reload cnos_rollback: redirect: community.network.cnos_rollback cnos_save: redirect: community.network.cnos_save cnos_showrun: redirect: community.network.cnos_showrun cnos_static_route: redirect: community.network.cnos_static_route cnos_system: redirect: community.network.cnos_system cnos_template: redirect: community.network.cnos_template cnos_user: redirect: community.network.cnos_user cnos_vlag: redirect: community.network.cnos_vlag cnos_vlan: redirect: community.network.cnos_vlan cnos_vrf: redirect: community.network.cnos_vrf nclu: redirect: community.network.nclu edgeos_command: redirect: community.network.edgeos_command edgeos_config: redirect: community.network.edgeos_config edgeos_facts: redirect: community.network.edgeos_facts edgeswitch_facts: redirect: community.network.edgeswitch_facts edgeswitch_vlan: redirect: community.network.edgeswitch_vlan enos_command: redirect: community.network.enos_command enos_config: redirect: community.network.enos_config enos_facts: redirect: community.network.enos_facts eric_eccli_command: redirect: community.network.eric_eccli_command exos_command: redirect: community.network.exos_command exos_config: redirect: community.network.exos_config exos_facts: redirect: community.network.exos_facts exos_l2_interfaces: redirect: community.network.exos_l2_interfaces exos_lldp_global: redirect: community.network.exos_lldp_global exos_lldp_interfaces: redirect: community.network.exos_lldp_interfaces exos_vlans: redirect: community.network.exos_vlans bigip_asm_policy: tombstone: removal_date: "2019-11-06" warning_text: bigip_asm_policy has been removed please use bigip_asm_policy_manage instead. bigip_device_facts: redirect: f5networks.f5_modules.bigip_device_info bigip_iapplx_package: redirect: f5networks.f5_modules.bigip_lx_package bigip_security_address_list: redirect: f5networks.f5_modules.bigip_firewall_address_list bigip_security_port_list: redirect: f5networks.f5_modules.bigip_firewall_port_list bigip_traffic_group: redirect: f5networks.f5_modules.bigip_device_traffic_group bigip_facts: tombstone: removal_date: "2019-11-06" warning_text: bigip_facts has been removed please use bigip_device_info module. bigip_gtm_facts: tombstone: removal_date: "2019-11-06" warning_text: bigip_gtm_facts has been removed please use bigip_device_info module. faz_device: redirect: community.fortios.faz_device fmgr_device: redirect: community.fortios.fmgr_device fmgr_device_config: redirect: community.fortios.fmgr_device_config fmgr_device_group: redirect: community.fortios.fmgr_device_group fmgr_device_provision_template: redirect: community.fortios.fmgr_device_provision_template fmgr_fwobj_address: redirect: community.fortios.fmgr_fwobj_address fmgr_fwobj_ippool: redirect: community.fortios.fmgr_fwobj_ippool fmgr_fwobj_ippool6: redirect: community.fortios.fmgr_fwobj_ippool6 fmgr_fwobj_service: redirect: community.fortios.fmgr_fwobj_service fmgr_fwobj_vip: redirect: community.fortios.fmgr_fwobj_vip fmgr_fwpol_ipv4: redirect: community.fortios.fmgr_fwpol_ipv4 fmgr_fwpol_package: redirect: community.fortios.fmgr_fwpol_package fmgr_ha: redirect: community.fortios.fmgr_ha fmgr_provisioning: redirect: community.fortios.fmgr_provisioning fmgr_query: redirect: community.fortios.fmgr_query fmgr_script: redirect: community.fortios.fmgr_script fmgr_secprof_appctrl: redirect: community.fortios.fmgr_secprof_appctrl fmgr_secprof_av: redirect: community.fortios.fmgr_secprof_av fmgr_secprof_dns: redirect: community.fortios.fmgr_secprof_dns fmgr_secprof_ips: redirect: community.fortios.fmgr_secprof_ips fmgr_secprof_profile_group: redirect: community.fortios.fmgr_secprof_profile_group fmgr_secprof_proxy: redirect: community.fortios.fmgr_secprof_proxy fmgr_secprof_spam: redirect: community.fortios.fmgr_secprof_spam fmgr_secprof_ssl_ssh: redirect: community.fortios.fmgr_secprof_ssl_ssh fmgr_secprof_voip: redirect: community.fortios.fmgr_secprof_voip fmgr_secprof_waf: redirect: community.fortios.fmgr_secprof_waf fmgr_secprof_wanopt: redirect: community.fortios.fmgr_secprof_wanopt fmgr_secprof_web: redirect: community.fortios.fmgr_secprof_web ftd_configuration: redirect: community.network.ftd_configuration ftd_file_download: redirect: community.network.ftd_file_download ftd_file_upload: redirect: community.network.ftd_file_upload ftd_install: redirect: community.network.ftd_install icx_banner: redirect: community.network.icx_banner icx_command: redirect: community.network.icx_command icx_config: redirect: community.network.icx_config icx_copy: redirect: community.network.icx_copy icx_facts: redirect: community.network.icx_facts icx_interface: redirect: community.network.icx_interface icx_l3_interface: redirect: community.network.icx_l3_interface icx_linkagg: redirect: community.network.icx_linkagg icx_lldp: redirect: community.network.icx_lldp icx_logging: redirect: community.network.icx_logging icx_ping: redirect: community.network.icx_ping icx_static_route: redirect: community.network.icx_static_route icx_system: redirect: community.network.icx_system icx_user: redirect: community.network.icx_user icx_vlan: redirect: community.network.icx_vlan dladm_etherstub: redirect: community.network.dladm_etherstub dladm_iptun: redirect: community.network.dladm_iptun dladm_linkprop: redirect: community.network.dladm_linkprop dladm_vlan: redirect: community.network.dladm_vlan dladm_vnic: redirect: community.network.dladm_vnic flowadm: redirect: community.network.flowadm ipadm_addr: redirect: community.network.ipadm_addr ipadm_addrprop: redirect: community.network.ipadm_addrprop ipadm_if: redirect: community.network.ipadm_if ipadm_ifprop: redirect: community.network.ipadm_ifprop ipadm_prop: redirect: community.network.ipadm_prop ig_config: redirect: community.network.ig_config ig_unit_information: redirect: community.network.ig_unit_information ironware_command: redirect: community.network.ironware_command ironware_config: redirect: community.network.ironware_config ironware_facts: redirect: community.network.ironware_facts iap_start_workflow: redirect: community.network.iap_start_workflow iap_token: redirect: community.network.iap_token netact_cm_command: redirect: community.network.netact_cm_command netscaler_cs_action: redirect: community.network.netscaler_cs_action netscaler_cs_policy: redirect: community.network.netscaler_cs_policy netscaler_cs_vserver: redirect: community.network.netscaler_cs_vserver netscaler_gslb_service: redirect: community.network.netscaler_gslb_service netscaler_gslb_site: redirect: community.network.netscaler_gslb_site netscaler_gslb_vserver: redirect: community.network.netscaler_gslb_vserver netscaler_lb_monitor: redirect: community.network.netscaler_lb_monitor netscaler_lb_vserver: redirect: community.network.netscaler_lb_vserver netscaler_nitro_request: redirect: community.network.netscaler_nitro_request netscaler_save_config: redirect: community.network.netscaler_save_config netscaler_server: redirect: community.network.netscaler_server netscaler_service: redirect: community.network.netscaler_service netscaler_servicegroup: redirect: community.network.netscaler_servicegroup netscaler_ssl_certkey: redirect: community.network.netscaler_ssl_certkey pn_cluster: redirect: community.network.pn_cluster pn_ospf: redirect: community.network.pn_ospf pn_ospfarea: redirect: community.network.pn_ospfarea pn_show: redirect: community.network.pn_show pn_trunk: redirect: community.network.pn_trunk pn_vlag: redirect: community.network.pn_vlag pn_vlan: redirect: community.network.pn_vlan pn_vrouter: redirect: community.network.pn_vrouter pn_vrouterbgp: redirect: community.network.pn_vrouterbgp pn_vrouterif: redirect: community.network.pn_vrouterif pn_vrouterlbif: redirect: community.network.pn_vrouterlbif pn_access_list: redirect: community.network.pn_access_list pn_access_list_ip: redirect: community.network.pn_access_list_ip pn_admin_service: redirect: community.network.pn_admin_service pn_admin_session_timeout: redirect: community.network.pn_admin_session_timeout pn_admin_syslog: redirect: community.network.pn_admin_syslog pn_connection_stats_settings: redirect: community.network.pn_connection_stats_settings pn_cpu_class: redirect: community.network.pn_cpu_class pn_cpu_mgmt_class: redirect: community.network.pn_cpu_mgmt_class pn_dhcp_filter: redirect: community.network.pn_dhcp_filter pn_dscp_map: redirect: community.network.pn_dscp_map pn_dscp_map_pri_map: redirect: community.network.pn_dscp_map_pri_map pn_fabric_local: redirect: community.network.pn_fabric_local pn_igmp_snooping: redirect: community.network.pn_igmp_snooping pn_ipv6security_raguard: redirect: community.network.pn_ipv6security_raguard pn_ipv6security_raguard_port: redirect: community.network.pn_ipv6security_raguard_port pn_ipv6security_raguard_vlan: redirect: community.network.pn_ipv6security_raguard_vlan pn_log_audit_exception: redirect: community.network.pn_log_audit_exception pn_port_config: redirect: community.network.pn_port_config pn_port_cos_bw: redirect: community.network.pn_port_cos_bw pn_port_cos_rate_setting: redirect: community.network.pn_port_cos_rate_setting pn_prefix_list: redirect: community.network.pn_prefix_list pn_prefix_list_network: redirect: community.network.pn_prefix_list_network pn_role: redirect: community.network.pn_role pn_snmp_community: redirect: community.network.pn_snmp_community pn_snmp_trap_sink: redirect: community.network.pn_snmp_trap_sink pn_snmp_vacm: redirect: community.network.pn_snmp_vacm pn_stp: redirect: community.network.pn_stp pn_stp_port: redirect: community.network.pn_stp_port pn_switch_setup: redirect: community.network.pn_switch_setup pn_user: redirect: community.network.pn_user pn_vflow_table_profile: redirect: community.network.pn_vflow_table_profile pn_vrouter_bgp: redirect: community.network.pn_vrouter_bgp pn_vrouter_bgp_network: redirect: community.network.pn_vrouter_bgp_network pn_vrouter_interface_ip: redirect: community.network.pn_vrouter_interface_ip pn_vrouter_loopback_interface: redirect: community.network.pn_vrouter_loopback_interface pn_vrouter_ospf: redirect: community.network.pn_vrouter_ospf pn_vrouter_ospf6: redirect: community.network.pn_vrouter_ospf6 pn_vrouter_packet_relay: redirect: community.network.pn_vrouter_packet_relay pn_vrouter_pim_config: redirect: community.network.pn_vrouter_pim_config pn_vtep: redirect: community.network.pn_vtep nos_command: redirect: community.network.nos_command nos_config: redirect: community.network.nos_config nos_facts: redirect: community.network.nos_facts nso_action: redirect: cisco.nso.nso_action nso_config: redirect: cisco.nso.nso_config nso_query: redirect: cisco.nso.nso_query nso_show: redirect: cisco.nso.nso_show nso_verify: redirect: cisco.nso.nso_verify nuage_vspk: redirect: community.network.nuage_vspk onyx_aaa: redirect: mellanox.onyx.onyx_aaa onyx_bfd: redirect: mellanox.onyx.onyx_bfd onyx_bgp: redirect: mellanox.onyx.onyx_bgp onyx_buffer_pool: redirect: mellanox.onyx.onyx_buffer_pool onyx_command: redirect: mellanox.onyx.onyx_command onyx_config: redirect: mellanox.onyx.onyx_config onyx_facts: redirect: mellanox.onyx.onyx_facts onyx_igmp: redirect: mellanox.onyx.onyx_igmp onyx_igmp_interface: redirect: mellanox.onyx.onyx_igmp_interface onyx_igmp_vlan: redirect: mellanox.onyx.onyx_igmp_vlan onyx_interface: redirect: mellanox.onyx.onyx_interface onyx_l2_interface: redirect: mellanox.onyx.onyx_l2_interface onyx_l3_interface: redirect: mellanox.onyx.onyx_l3_interface onyx_linkagg: redirect: mellanox.onyx.onyx_linkagg onyx_lldp: redirect: mellanox.onyx.onyx_lldp onyx_lldp_interface: redirect: mellanox.onyx.onyx_lldp_interface onyx_magp: redirect: mellanox.onyx.onyx_magp onyx_mlag_ipl: redirect: mellanox.onyx.onyx_mlag_ipl onyx_mlag_vip: redirect: mellanox.onyx.onyx_mlag_vip onyx_ntp: redirect: mellanox.onyx.onyx_ntp onyx_ntp_servers_peers: redirect: mellanox.onyx.onyx_ntp_servers_peers onyx_ospf: redirect: mellanox.onyx.onyx_ospf onyx_pfc_interface: redirect: mellanox.onyx.onyx_pfc_interface onyx_protocol: redirect: mellanox.onyx.onyx_protocol onyx_ptp_global: redirect: mellanox.onyx.onyx_ptp_global onyx_ptp_interface: redirect: mellanox.onyx.onyx_ptp_interface onyx_qos: redirect: mellanox.onyx.onyx_qos onyx_snmp: redirect: mellanox.onyx.onyx_snmp onyx_snmp_hosts: redirect: mellanox.onyx.onyx_snmp_hosts onyx_snmp_users: redirect: mellanox.onyx.onyx_snmp_users onyx_syslog_files: redirect: mellanox.onyx.onyx_syslog_files onyx_syslog_remote: redirect: mellanox.onyx.onyx_syslog_remote onyx_traffic_class: redirect: mellanox.onyx.onyx_traffic_class onyx_username: redirect: mellanox.onyx.onyx_username onyx_vlan: redirect: mellanox.onyx.onyx_vlan onyx_vxlan: redirect: mellanox.onyx.onyx_vxlan onyx_wjh: redirect: mellanox.onyx.onyx_wjh opx_cps: redirect: community.network.opx_cps ordnance_config: redirect: community.network.ordnance_config ordnance_facts: redirect: community.network.ordnance_facts panos_admin: redirect: community.network.panos_admin panos_admpwd: redirect: community.network.panos_admpwd panos_cert_gen_ssh: redirect: community.network.panos_cert_gen_ssh panos_check: redirect: community.network.panos_check panos_commit: redirect: community.network.panos_commit panos_dag: redirect: community.network.panos_dag panos_dag_tags: redirect: community.network.panos_dag_tags panos_import: redirect: community.network.panos_import panos_interface: redirect: community.network.panos_interface panos_lic: redirect: community.network.panos_lic panos_loadcfg: redirect: community.network.panos_loadcfg panos_match_rule: redirect: community.network.panos_match_rule panos_mgtconfig: redirect: community.network.panos_mgtconfig panos_nat_rule: redirect: community.network.panos_nat_rule panos_object: redirect: community.network.panos_object panos_op: redirect: community.network.panos_op panos_pg: redirect: community.network.panos_pg panos_query_rules: redirect: community.network.panos_query_rules panos_restart: redirect: community.network.panos_restart panos_sag: redirect: community.network.panos_sag panos_security_rule: redirect: community.network.panos_security_rule panos_set: redirect: community.network.panos_set vdirect_commit: redirect: community.network.vdirect_commit vdirect_file: redirect: community.network.vdirect_file vdirect_runnable: redirect: community.network.vdirect_runnable routeros_command: redirect: community.routeros.command routeros_facts: redirect: community.routeros.facts slxos_command: redirect: community.network.slxos_command slxos_config: redirect: community.network.slxos_config slxos_facts: redirect: community.network.slxos_facts slxos_interface: redirect: community.network.slxos_interface slxos_l2_interface: redirect: community.network.slxos_l2_interface slxos_l3_interface: redirect: community.network.slxos_l3_interface slxos_linkagg: redirect: community.network.slxos_linkagg slxos_lldp: redirect: community.network.slxos_lldp slxos_vlan: redirect: community.network.slxos_vlan sros_command: redirect: community.network.sros_command sros_config: redirect: community.network.sros_config sros_rollback: redirect: community.network.sros_rollback voss_command: redirect: community.network.voss_command voss_config: redirect: community.network.voss_config voss_facts: redirect: community.network.voss_facts osx_say: redirect: community.general.say bearychat: redirect: community.general.bearychat campfire: redirect: community.general.campfire catapult: redirect: community.general.catapult cisco_spark: redirect: community.general.cisco_spark flowdock: redirect: community.general.flowdock grove: redirect: community.general.grove hipchat: redirect: community.general.hipchat irc: redirect: community.general.irc jabber: redirect: community.general.jabber logentries_msg: redirect: community.general.logentries_msg mail: redirect: community.general.mail matrix: redirect: community.general.matrix mattermost: redirect: community.general.mattermost mqtt: redirect: community.general.mqtt nexmo: redirect: community.general.nexmo office_365_connector_card: redirect: community.general.office_365_connector_card pushbullet: redirect: community.general.pushbullet pushover: redirect: community.general.pushover rabbitmq_publish: redirect: community.rabbitmq.rabbitmq_publish rocketchat: redirect: community.general.rocketchat say: redirect: community.general.say sendgrid: redirect: community.general.sendgrid slack: redirect: community.general.slack syslogger: redirect: community.general.syslogger telegram: redirect: community.general.telegram twilio: redirect: community.general.twilio typetalk: redirect: community.general.typetalk bower: redirect: community.general.bower bundler: redirect: community.general.bundler composer: redirect: community.general.composer cpanm: redirect: community.general.cpanm easy_install: redirect: community.general.easy_install gem: redirect: community.general.gem maven_artifact: redirect: community.general.maven_artifact npm: redirect: community.general.npm pear: redirect: community.general.pear pip_package_info: redirect: community.general.pip_package_info yarn: redirect: community.general.yarn apk: redirect: community.general.apk apt_rpm: redirect: community.general.apt_rpm flatpak: redirect: community.general.flatpak flatpak_remote: redirect: community.general.flatpak_remote homebrew: redirect: community.general.homebrew homebrew_cask: redirect: community.general.homebrew_cask homebrew_tap: redirect: community.general.homebrew_tap installp: redirect: community.general.installp layman: redirect: community.general.layman macports: redirect: community.general.macports mas: redirect: community.general.mas openbsd_pkg: redirect: community.general.openbsd_pkg opkg: redirect: community.general.opkg pacman: redirect: community.general.pacman pkg5: redirect: community.general.pkg5 pkg5_publisher: redirect: community.general.pkg5_publisher pkgin: redirect: community.general.pkgin pkgng: redirect: community.general.pkgng pkgutil: redirect: community.general.pkgutil portage: redirect: community.general.portage portinstall: redirect: community.general.portinstall pulp_repo: redirect: community.general.pulp_repo redhat_subscription: redirect: community.general.redhat_subscription rhn_channel: redirect: community.general.rhn_channel rhn_register: redirect: community.general.rhn_register rhsm_release: redirect: community.general.rhsm_release rhsm_repository: redirect: community.general.rhsm_repository slackpkg: redirect: community.general.slackpkg snap: redirect: community.general.snap sorcery: redirect: community.general.sorcery svr4pkg: redirect: community.general.svr4pkg swdepot: redirect: community.general.swdepot swupd: redirect: community.general.swupd urpmi: redirect: community.general.urpmi xbps: redirect: community.general.xbps zypper: redirect: community.general.zypper zypper_repository: redirect: community.general.zypper_repository cobbler_sync: redirect: community.general.cobbler_sync cobbler_system: redirect: community.general.cobbler_system idrac_firmware: redirect: dellemc.openmanage.idrac_firmware idrac_server_config_profile: redirect: dellemc.openmanage.idrac_server_config_profile ome_device_info: redirect: dellemc.openmanage.ome_device_info foreman: redirect: community.general.foreman katello: redirect: community.general.katello hpilo_facts: redirect: community.general.hpilo_facts hpilo_boot: redirect: community.general.hpilo_boot hpilo_info: redirect: community.general.hpilo_info hponcfg: redirect: community.general.hponcfg imc_rest: redirect: community.general.imc_rest ipmi_boot: redirect: community.general.ipmi_boot ipmi_power: redirect: community.general.ipmi_power lxca_cmms: redirect: community.general.lxca_cmms lxca_nodes: redirect: community.general.lxca_nodes manageiq_alert_profiles: redirect: community.general.manageiq_alert_profiles manageiq_alerts: redirect: community.general.manageiq_alerts manageiq_group: redirect: community.general.manageiq_group manageiq_policies: redirect: community.general.manageiq_policies manageiq_provider: redirect: community.general.manageiq_provider manageiq_tags: redirect: community.general.manageiq_tags manageiq_tenant: redirect: community.general.manageiq_tenant manageiq_user: redirect: community.general.manageiq_user oneview_datacenter_facts: redirect: community.general.oneview_datacenter_facts oneview_enclosure_facts: redirect: community.general.oneview_enclosure_facts oneview_ethernet_network_facts: redirect: community.general.oneview_ethernet_network_facts oneview_fc_network_facts: redirect: community.general.oneview_fc_network_facts oneview_fcoe_network_facts: redirect: community.general.oneview_fcoe_network_facts oneview_logical_interconnect_group_facts: redirect: community.general.oneview_logical_interconnect_group_facts oneview_network_set_facts: redirect: community.general.oneview_network_set_facts oneview_san_manager_facts: redirect: community.general.oneview_san_manager_facts oneview_datacenter_info: redirect: community.general.oneview_datacenter_info oneview_enclosure_info: redirect: community.general.oneview_enclosure_info oneview_ethernet_network: redirect: community.general.oneview_ethernet_network oneview_ethernet_network_info: redirect: community.general.oneview_ethernet_network_info oneview_fc_network: redirect: community.general.oneview_fc_network oneview_fc_network_info: redirect: community.general.oneview_fc_network_info oneview_fcoe_network: redirect: community.general.oneview_fcoe_network oneview_fcoe_network_info: redirect: community.general.oneview_fcoe_network_info oneview_logical_interconnect_group: redirect: community.general.oneview_logical_interconnect_group oneview_logical_interconnect_group_info: redirect: community.general.oneview_logical_interconnect_group_info oneview_network_set: redirect: community.general.oneview_network_set oneview_network_set_info: redirect: community.general.oneview_network_set_info oneview_san_manager: redirect: community.general.oneview_san_manager oneview_san_manager_info: redirect: community.general.oneview_san_manager_info idrac_redfish_facts: redirect: community.general.idrac_redfish_facts redfish_facts: redirect: community.general.redfish_facts idrac_redfish_command: redirect: community.general.idrac_redfish_command idrac_redfish_config: redirect: community.general.idrac_redfish_config idrac_redfish_info: redirect: community.general.idrac_redfish_info redfish_command: redirect: community.general.redfish_command redfish_config: redirect: community.general.redfish_config redfish_info: redirect: community.general.redfish_info stacki_host: redirect: community.general.stacki_host wakeonlan: redirect: community.general.wakeonlan bitbucket_access_key: redirect: community.general.bitbucket_access_key bitbucket_pipeline_key_pair: redirect: community.general.bitbucket_pipeline_key_pair bitbucket_pipeline_known_host: redirect: community.general.bitbucket_pipeline_known_host bitbucket_pipeline_variable: redirect: community.general.bitbucket_pipeline_variable bzr: redirect: community.general.bzr git_config: redirect: community.general.git_config github_hooks: redirect: community.general.github_hooks github_webhook_facts: redirect: community.general.github_webhook_info github_deploy_key: redirect: community.general.github_deploy_key github_issue: redirect: community.general.github_issue github_key: redirect: community.general.github_key github_release: redirect: community.general.github_release github_webhook: redirect: community.general.github_webhook github_webhook_info: redirect: community.general.github_webhook_info gitlab_hooks: redirect: community.general.gitlab_hook gitlab_deploy_key: redirect: community.general.gitlab_deploy_key gitlab_group: redirect: community.general.gitlab_group gitlab_hook: redirect: community.general.gitlab_hook gitlab_project: redirect: community.general.gitlab_project gitlab_project_variable: redirect: community.general.gitlab_project_variable gitlab_runner: redirect: community.general.gitlab_runner gitlab_user: redirect: community.general.gitlab_user hg: redirect: community.general.hg emc_vnx_sg_member: redirect: community.general.emc_vnx_sg_member gluster_heal_facts: redirect: gluster.gluster.gluster_heal_info gluster_heal_info: redirect: gluster.gluster.gluster_heal_info gluster_peer: redirect: gluster.gluster.gluster_peer gluster_volume: redirect: gluster.gluster.gluster_volume ss_3par_cpg: redirect: community.general.ss_3par_cpg ibm_sa_domain: redirect: community.general.ibm_sa_domain ibm_sa_host: redirect: community.general.ibm_sa_host ibm_sa_host_ports: redirect: community.general.ibm_sa_host_ports ibm_sa_pool: redirect: community.general.ibm_sa_pool ibm_sa_vol: redirect: community.general.ibm_sa_vol ibm_sa_vol_map: redirect: community.general.ibm_sa_vol_map infini_export: redirect: infinidat.infinibox.infini_export infini_export_client: redirect: infinidat.infinibox.infini_export_client infini_fs: redirect: infinidat.infinibox.infini_fs infini_host: redirect: infinidat.infinibox.infini_host infini_pool: redirect: infinidat.infinibox.infini_pool infini_vol: redirect: infinidat.infinibox.infini_vol na_cdot_aggregate: redirect: community.general.na_cdot_aggregate na_cdot_license: redirect: community.general.na_cdot_license na_cdot_lun: redirect: community.general.na_cdot_lun na_cdot_qtree: redirect: community.general.na_cdot_qtree na_cdot_svm: redirect: community.general.na_cdot_svm na_cdot_user: redirect: community.general.na_cdot_user na_cdot_user_role: redirect: community.general.na_cdot_user_role na_cdot_volume: redirect: community.general.na_cdot_volume na_ontap_gather_facts: redirect: community.general.na_ontap_gather_facts sf_account_manager: redirect: community.general.sf_account_manager sf_check_connections: redirect: community.general.sf_check_connections sf_snapshot_schedule_manager: redirect: community.general.sf_snapshot_schedule_manager sf_volume_access_group_manager: redirect: community.general.sf_volume_access_group_manager sf_volume_manager: redirect: community.general.sf_volume_manager netapp_e_alerts: redirect: netapp_eseries.santricity.netapp_e_alerts netapp_e_amg: redirect: netapp_eseries.santricity.netapp_e_amg netapp_e_amg_role: redirect: netapp_eseries.santricity.netapp_e_amg_role netapp_e_amg_sync: redirect: netapp_eseries.santricity.netapp_e_amg_sync netapp_e_asup: redirect: netapp_eseries.santricity.netapp_e_asup netapp_e_auditlog: redirect: netapp_eseries.santricity.netapp_e_auditlog netapp_e_auth: redirect: netapp_eseries.santricity.netapp_e_auth netapp_e_drive_firmware: redirect: netapp_eseries.santricity.netapp_e_drive_firmware netapp_e_facts: redirect: netapp_eseries.santricity.netapp_e_facts netapp_e_firmware: redirect: netapp_eseries.santricity.netapp_e_firmware netapp_e_flashcache: redirect: netapp_eseries.santricity.netapp_e_flashcache netapp_e_global: redirect: netapp_eseries.santricity.netapp_e_global netapp_e_host: redirect: netapp_eseries.santricity.netapp_e_host netapp_e_hostgroup: redirect: netapp_eseries.santricity.netapp_e_hostgroup netapp_e_iscsi_interface: redirect: netapp_eseries.santricity.netapp_e_iscsi_interface netapp_e_iscsi_target: redirect: netapp_eseries.santricity.netapp_e_iscsi_target netapp_e_ldap: redirect: netapp_eseries.santricity.netapp_e_ldap netapp_e_lun_mapping: redirect: netapp_eseries.santricity.netapp_e_lun_mapping netapp_e_mgmt_interface: redirect: netapp_eseries.santricity.netapp_e_mgmt_interface netapp_e_snapshot_group: redirect: netapp_eseries.santricity.netapp_e_snapshot_group netapp_e_snapshot_images: redirect: netapp_eseries.santricity.netapp_e_snapshot_images netapp_e_snapshot_volume: redirect: netapp_eseries.santricity.netapp_e_snapshot_volume netapp_e_storage_system: redirect: netapp_eseries.santricity.netapp_e_storage_system netapp_e_storagepool: redirect: netapp_eseries.santricity.netapp_e_storagepool netapp_e_syslog: redirect: netapp_eseries.santricity.netapp_e_syslog netapp_e_volume: redirect: netapp_eseries.santricity.netapp_e_volume netapp_e_volume_copy: redirect: netapp_eseries.santricity.netapp_e_volume_copy purefa_facts: redirect: community.general.purefa_facts purefb_facts: redirect: community.general.purefb_facts vexata_eg: redirect: community.general.vexata_eg vexata_volume: redirect: community.general.vexata_volume zfs: redirect: community.general.zfs zfs_delegate_admin: redirect: community.general.zfs_delegate_admin zfs_facts: redirect: community.general.zfs_facts zpool_facts: redirect: community.general.zpool_facts python_requirements_facts: redirect: community.general.python_requirements_facts aix_devices: redirect: community.general.aix_devices aix_filesystem: redirect: community.general.aix_filesystem aix_inittab: redirect: community.general.aix_inittab aix_lvg: redirect: community.general.aix_lvg aix_lvol: redirect: community.general.aix_lvol alternatives: redirect: community.general.alternatives awall: redirect: community.general.awall beadm: redirect: community.general.beadm capabilities: redirect: community.general.capabilities cronvar: redirect: community.general.cronvar crypttab: redirect: community.general.crypttab dconf: redirect: community.general.dconf facter: redirect: community.general.facter filesystem: redirect: community.general.filesystem firewalld: redirect: ansible.posix.firewalld gconftool2: redirect: community.general.gconftool2 interfaces_file: redirect: community.general.interfaces_file java_cert: redirect: community.general.java_cert java_keystore: redirect: community.general.java_keystore kernel_blacklist: redirect: community.general.kernel_blacklist lbu: redirect: community.general.lbu listen_ports_facts: redirect: community.general.listen_ports_facts locale_gen: redirect: community.general.locale_gen lvg: redirect: community.general.lvg lvol: redirect: community.general.lvol make: redirect: community.general.make mksysb: redirect: community.general.mksysb modprobe: redirect: community.general.modprobe nosh: redirect: community.general.nosh ohai: redirect: community.general.ohai open_iscsi: redirect: community.general.open_iscsi openwrt_init: redirect: community.general.openwrt_init osx_defaults: redirect: community.general.osx_defaults pam_limits: redirect: community.general.pam_limits pamd: redirect: community.general.pamd parted: redirect: community.general.parted pids: redirect: community.general.pids puppet: redirect: community.general.puppet python_requirements_info: redirect: community.general.python_requirements_info runit: redirect: community.general.runit sefcontext: redirect: community.general.sefcontext selinux_permissive: redirect: community.general.selinux_permissive selogin: redirect: community.general.selogin seport: redirect: community.general.seport solaris_zone: redirect: community.general.solaris_zone svc: redirect: community.general.svc syspatch: redirect: community.general.syspatch timezone: redirect: community.general.timezone ufw: redirect: community.general.ufw vdo: redirect: community.general.vdo xfconf: redirect: community.general.xfconf xfs_quota: redirect: community.general.xfs_quota jenkins_job_facts: redirect: community.general.jenkins_job_facts nginx_status_facts: redirect: community.general.nginx_status_facts apache2_mod_proxy: redirect: community.general.apache2_mod_proxy apache2_module: redirect: community.general.apache2_module deploy_helper: redirect: community.general.deploy_helper django_manage: redirect: community.general.django_manage ejabberd_user: redirect: community.general.ejabberd_user gunicorn: redirect: community.general.gunicorn htpasswd: redirect: community.general.htpasswd jboss: redirect: community.general.jboss jenkins_job: redirect: community.general.jenkins_job jenkins_job_info: redirect: community.general.jenkins_job_info jenkins_plugin: redirect: community.general.jenkins_plugin jenkins_script: redirect: community.general.jenkins_script jira: redirect: community.general.jira nginx_status_info: redirect: community.general.nginx_status_info rundeck_acl_policy: redirect: community.general.rundeck_acl_policy rundeck_project: redirect: community.general.rundeck_project utm_aaa_group: redirect: community.general.utm_aaa_group utm_aaa_group_info: redirect: community.general.utm_aaa_group_info utm_ca_host_key_cert: redirect: community.general.utm_ca_host_key_cert utm_ca_host_key_cert_info: redirect: community.general.utm_ca_host_key_cert_info utm_dns_host: redirect: community.general.utm_dns_host utm_network_interface_address: redirect: community.general.utm_network_interface_address utm_network_interface_address_info: redirect: community.general.utm_network_interface_address_info utm_proxy_auth_profile: redirect: community.general.utm_proxy_auth_profile utm_proxy_exception: redirect: community.general.utm_proxy_exception utm_proxy_frontend: redirect: community.general.utm_proxy_frontend utm_proxy_frontend_info: redirect: community.general.utm_proxy_frontend_info utm_proxy_location: redirect: community.general.utm_proxy_location utm_proxy_location_info: redirect: community.general.utm_proxy_location_info supervisorctl: redirect: community.general.supervisorctl taiga_issue: redirect: community.general.taiga_issue grafana_dashboard: redirect: community.grafana.grafana_dashboard grafana_datasource: redirect: community.grafana.grafana_datasource grafana_plugin: redirect: community.grafana.grafana_plugin k8s_facts: redirect: kubernetes.core.k8s_facts k8s_raw: redirect: kubernetes.core.k8s_raw k8s: redirect: kubernetes.core.k8s k8s_auth: redirect: kubernetes.core.k8s_auth k8s_info: redirect: kubernetes.core.k8s_info k8s_scale: redirect: kubernetes.core.k8s_scale k8s_service: redirect: kubernetes.core.k8s_service openshift_raw: redirect: kubernetes.core.openshift_raw openshift_scale: redirect: kubernetes.core.openshift_scale openssh_cert: redirect: community.crypto.openssh_cert openssl_pkcs12: redirect: community.crypto.openssl_pkcs12 openssl_csr: redirect: community.crypto.openssl_csr openssl_certificate: redirect: community.crypto.x509_certificate openssl_certificate_info: redirect: community.crypto.x509_certificate_info x509_crl: redirect: community.crypto.x509_crl openssl_privatekey_info: redirect: community.crypto.openssl_privatekey_info x509_crl_info: redirect: community.crypto.x509_crl_info get_certificate: redirect: community.crypto.get_certificate openssh_keypair: redirect: community.crypto.openssh_keypair openssl_publickey: redirect: community.crypto.openssl_publickey openssl_csr_info: redirect: community.crypto.openssl_csr_info luks_device: redirect: community.crypto.luks_device openssl_dhparam: redirect: community.crypto.openssl_dhparam openssl_privatekey: redirect: community.crypto.openssl_privatekey certificate_complete_chain: redirect: community.crypto.certificate_complete_chain acme_inspect: redirect: community.crypto.acme_inspect acme_certificate_revoke: redirect: community.crypto.acme_certificate_revoke acme_certificate: redirect: community.crypto.acme_certificate acme_account: redirect: community.crypto.acme_account acme_account_facts: redirect: community.crypto.acme_account_facts acme_challenge_cert_helper: redirect: community.crypto.acme_challenge_cert_helper acme_account_info: redirect: community.crypto.acme_account_info ecs_domain: redirect: community.crypto.ecs_domain ecs_certificate: redirect: community.crypto.ecs_certificate mongodb_parameter: redirect: community.mongodb.mongodb_parameter mongodb_info: redirect: community.mongodb.mongodb_info mongodb_replicaset: redirect: community.mongodb.mongodb_replicaset mongodb_user: redirect: community.mongodb.mongodb_user mongodb_shard: redirect: community.mongodb.mongodb_shard vmware_appliance_access_info: redirect: vmware.vmware_rest.vmware_appliance_access_info vmware_appliance_health_info: redirect: vmware.vmware_rest.vmware_appliance_health_info vmware_cis_category_info: redirect: vmware.vmware_rest.vmware_cis_category_info vmware_core_info: redirect: vmware.vmware_rest.vmware_core_info vcenter_extension_facts: redirect: community.vmware.vcenter_extension_facts vmware_about_facts: redirect: community.vmware.vmware_about_facts vmware_category_facts: redirect: community.vmware.vmware_category_facts vmware_cluster_facts: redirect: community.vmware.vmware_cluster_facts vmware_datastore_facts: redirect: community.vmware.vmware_datastore_facts vmware_dns_config: redirect: community.vmware.vmware_dns_config vmware_drs_group_facts: redirect: community.vmware.vmware_drs_group_facts vmware_drs_rule_facts: redirect: community.vmware.vmware_drs_rule_facts vmware_dvs_portgroup_facts: redirect: community.vmware.vmware_dvs_portgroup_facts vmware_guest_boot_facts: redirect: community.vmware.vmware_guest_boot_facts vmware_guest_customization_facts: redirect: community.vmware.vmware_guest_customization_facts vmware_guest_disk_facts: redirect: community.vmware.vmware_guest_disk_facts vmware_guest_facts: redirect: community.vmware.vmware_guest_facts vmware_guest_snapshot_facts: redirect: community.vmware.vmware_guest_snapshot_facts vmware_host_capability_facts: redirect: community.vmware.vmware_host_capability_facts vmware_host_config_facts: redirect: community.vmware.vmware_host_config_facts vmware_host_dns_facts: redirect: community.vmware.vmware_host_dns_facts vmware_host_feature_facts: redirect: community.vmware.vmware_host_feature_facts vmware_host_firewall_facts: redirect: community.vmware.vmware_host_firewall_facts vmware_host_ntp_facts: redirect: community.vmware.vmware_host_ntp_facts vmware_host_package_facts: redirect: community.vmware.vmware_host_package_facts vmware_host_service_facts: redirect: community.vmware.vmware_host_service_facts vmware_host_ssl_facts: redirect: community.vmware.vmware_host_ssl_facts vmware_host_vmhba_facts: redirect: community.vmware.vmware_host_vmhba_facts vmware_host_vmnic_facts: redirect: community.vmware.vmware_host_vmnic_facts vmware_local_role_facts: redirect: community.vmware.vmware_local_role_facts vmware_local_user_facts: redirect: community.vmware.vmware_local_user_facts vmware_portgroup_facts: redirect: community.vmware.vmware_portgroup_facts vmware_resource_pool_facts: redirect: community.vmware.vmware_resource_pool_facts vmware_tag_facts: redirect: community.vmware.vmware_tag_facts vmware_target_canonical_facts: redirect: community.vmware.vmware_target_canonical_facts vmware_vm_facts: redirect: community.vmware.vmware_vm_facts vmware_vmkernel_facts: redirect: community.vmware.vmware_vmkernel_facts vmware_vswitch_facts: redirect: community.vmware.vmware_vswitch_facts vca_fw: redirect: community.vmware.vca_fw vca_nat: redirect: community.vmware.vca_nat vca_vapp: redirect: community.vmware.vca_vapp vcenter_extension: redirect: community.vmware.vcenter_extension vcenter_extension_info: redirect: community.vmware.vcenter_extension_info vcenter_folder: redirect: community.vmware.vcenter_folder vcenter_license: redirect: community.vmware.vcenter_license vmware_about_info: redirect: community.vmware.vmware_about_info vmware_category: redirect: community.vmware.vmware_category vmware_category_info: redirect: community.vmware.vmware_category_info vmware_cfg_backup: redirect: community.vmware.vmware_cfg_backup vmware_cluster: redirect: community.vmware.vmware_cluster vmware_cluster_drs: redirect: community.vmware.vmware_cluster_drs vmware_cluster_ha: redirect: community.vmware.vmware_cluster_ha vmware_cluster_info: redirect: community.vmware.vmware_cluster_info vmware_cluster_vsan: redirect: community.vmware.vmware_cluster_vsan vmware_content_deploy_template: redirect: community.vmware.vmware_content_deploy_template vmware_content_library_info: redirect: community.vmware.vmware_content_library_info vmware_content_library_manager: redirect: community.vmware.vmware_content_library_manager vmware_datacenter: redirect: community.vmware.vmware_datacenter vmware_datastore_cluster: redirect: community.vmware.vmware_datastore_cluster vmware_datastore_info: redirect: community.vmware.vmware_datastore_info vmware_datastore_maintenancemode: redirect: community.vmware.vmware_datastore_maintenancemode vmware_deploy_ovf: redirect: community.vmware.vmware_deploy_ovf vmware_drs_group: redirect: community.vmware.vmware_drs_group vmware_drs_group_info: redirect: community.vmware.vmware_drs_group_info vmware_drs_rule_info: redirect: community.vmware.vmware_drs_rule_info vmware_dvs_host: redirect: community.vmware.vmware_dvs_host vmware_dvs_portgroup: redirect: community.vmware.vmware_dvs_portgroup vmware_dvs_portgroup_find: redirect: community.vmware.vmware_dvs_portgroup_find vmware_dvs_portgroup_info: redirect: community.vmware.vmware_dvs_portgroup_info vmware_dvswitch: redirect: community.vmware.vmware_dvswitch vmware_dvswitch_lacp: redirect: community.vmware.vmware_dvswitch_lacp vmware_dvswitch_nioc: redirect: community.vmware.vmware_dvswitch_nioc vmware_dvswitch_pvlans: redirect: community.vmware.vmware_dvswitch_pvlans vmware_dvswitch_uplink_pg: redirect: community.vmware.vmware_dvswitch_uplink_pg vmware_evc_mode: redirect: community.vmware.vmware_evc_mode vmware_export_ovf: redirect: community.vmware.vmware_export_ovf vmware_folder_info: redirect: community.vmware.vmware_folder_info vmware_guest: redirect: community.vmware.vmware_guest vmware_guest_boot_info: redirect: community.vmware.vmware_guest_boot_info vmware_guest_boot_manager: redirect: community.vmware.vmware_guest_boot_manager vmware_guest_controller: redirect: community.vmware.vmware_guest_controller vmware_guest_cross_vc_clone: redirect: community.vmware.vmware_guest_cross_vc_clone vmware_guest_custom_attribute_defs: redirect: community.vmware.vmware_guest_custom_attribute_defs vmware_guest_custom_attributes: redirect: community.vmware.vmware_guest_custom_attributes vmware_guest_customization_info: redirect: community.vmware.vmware_guest_customization_info vmware_guest_disk: redirect: community.vmware.vmware_guest_disk vmware_guest_disk_info: redirect: community.vmware.vmware_guest_disk_info vmware_guest_file_operation: redirect: community.vmware.vmware_guest_file_operation vmware_guest_find: redirect: community.vmware.vmware_guest_find vmware_guest_info: redirect: community.vmware.vmware_guest_info vmware_guest_move: redirect: community.vmware.vmware_guest_move vmware_guest_network: redirect: community.vmware.vmware_guest_network vmware_guest_powerstate: redirect: community.vmware.vmware_guest_powerstate vmware_guest_register_operation: redirect: community.vmware.vmware_guest_register_operation vmware_guest_screenshot: redirect: community.vmware.vmware_guest_screenshot vmware_guest_sendkey: redirect: community.vmware.vmware_guest_sendkey vmware_guest_serial_port: redirect: community.vmware.vmware_guest_serial_port vmware_guest_snapshot: redirect: community.vmware.vmware_guest_snapshot vmware_guest_snapshot_info: redirect: community.vmware.vmware_guest_snapshot_info vmware_guest_tools_info: redirect: community.vmware.vmware_guest_tools_info vmware_guest_tools_upgrade: redirect: community.vmware.vmware_guest_tools_upgrade vmware_guest_tools_wait: redirect: community.vmware.vmware_guest_tools_wait vmware_guest_video: redirect: community.vmware.vmware_guest_video vmware_guest_vnc: redirect: community.vmware.vmware_guest_vnc vmware_host: redirect: community.vmware.vmware_host vmware_host_acceptance: redirect: community.vmware.vmware_host_acceptance vmware_host_active_directory: redirect: community.vmware.vmware_host_active_directory vmware_host_auto_start: redirect: community.vmware.vmware_host_auto_start vmware_host_capability_info: redirect: community.vmware.vmware_host_capability_info vmware_host_config_info: redirect: community.vmware.vmware_host_config_info vmware_host_config_manager: redirect: community.vmware.vmware_host_config_manager vmware_host_datastore: redirect: community.vmware.vmware_host_datastore vmware_host_dns: redirect: community.vmware.vmware_host_dns vmware_host_dns_info: redirect: community.vmware.vmware_host_dns_info vmware_host_facts: redirect: community.vmware.vmware_host_facts vmware_host_feature_info: redirect: community.vmware.vmware_host_feature_info vmware_host_firewall_info: redirect: community.vmware.vmware_host_firewall_info vmware_host_firewall_manager: redirect: community.vmware.vmware_host_firewall_manager vmware_host_hyperthreading: redirect: community.vmware.vmware_host_hyperthreading vmware_host_ipv6: redirect: community.vmware.vmware_host_ipv6 vmware_host_kernel_manager: redirect: community.vmware.vmware_host_kernel_manager vmware_host_lockdown: redirect: community.vmware.vmware_host_lockdown vmware_host_ntp: redirect: community.vmware.vmware_host_ntp vmware_host_ntp_info: redirect: community.vmware.vmware_host_ntp_info vmware_host_package_info: redirect: community.vmware.vmware_host_package_info vmware_host_powermgmt_policy: redirect: community.vmware.vmware_host_powermgmt_policy vmware_host_powerstate: redirect: community.vmware.vmware_host_powerstate vmware_host_scanhba: redirect: community.vmware.vmware_host_scanhba vmware_host_service_info: redirect: community.vmware.vmware_host_service_info vmware_host_service_manager: redirect: community.vmware.vmware_host_service_manager vmware_host_snmp: redirect: community.vmware.vmware_host_snmp vmware_host_ssl_info: redirect: community.vmware.vmware_host_ssl_info vmware_host_vmhba_info: redirect: community.vmware.vmware_host_vmhba_info vmware_host_vmnic_info: redirect: community.vmware.vmware_host_vmnic_info vmware_local_role_info: redirect: community.vmware.vmware_local_role_info vmware_local_role_manager: redirect: community.vmware.vmware_local_role_manager vmware_local_user_info: redirect: community.vmware.vmware_local_user_info vmware_local_user_manager: redirect: community.vmware.vmware_local_user_manager vmware_maintenancemode: redirect: community.vmware.vmware_maintenancemode vmware_migrate_vmk: redirect: community.vmware.vmware_migrate_vmk vmware_object_role_permission: redirect: community.vmware.vmware_object_role_permission vmware_portgroup: redirect: community.vmware.vmware_portgroup vmware_portgroup_info: redirect: community.vmware.vmware_portgroup_info vmware_resource_pool: redirect: community.vmware.vmware_resource_pool vmware_resource_pool_info: redirect: community.vmware.vmware_resource_pool_info vmware_tag: redirect: community.vmware.vmware_tag vmware_tag_info: redirect: community.vmware.vmware_tag_info vmware_tag_manager: redirect: community.vmware.vmware_tag_manager vmware_target_canonical_info: redirect: community.vmware.vmware_target_canonical_info vmware_vcenter_settings: redirect: community.vmware.vmware_vcenter_settings vmware_vcenter_statistics: redirect: community.vmware.vmware_vcenter_statistics vmware_vm_host_drs_rule: redirect: community.vmware.vmware_vm_host_drs_rule vmware_vm_info: redirect: community.vmware.vmware_vm_info vmware_vm_shell: redirect: community.vmware.vmware_vm_shell vmware_vm_storage_policy_info: redirect: community.vmware.vmware_vm_storage_policy_info vmware_vm_vm_drs_rule: redirect: community.vmware.vmware_vm_vm_drs_rule vmware_vm_vss_dvs_migrate: redirect: community.vmware.vmware_vm_vss_dvs_migrate vmware_vmkernel: redirect: community.vmware.vmware_vmkernel vmware_vmkernel_info: redirect: community.vmware.vmware_vmkernel_info vmware_vmkernel_ip_config: redirect: community.vmware.vmware_vmkernel_ip_config vmware_vmotion: redirect: community.vmware.vmware_vmotion vmware_vsan_cluster: redirect: community.vmware.vmware_vsan_cluster vmware_vsan_health_info: redirect: community.vmware.vmware_vsan_health_info vmware_vspan_session: redirect: community.vmware.vmware_vspan_session vmware_vswitch: redirect: community.vmware.vmware_vswitch vmware_vswitch_info: redirect: community.vmware.vmware_vswitch_info vsphere_copy: redirect: community.vmware.vsphere_copy vsphere_file: redirect: community.vmware.vsphere_file psexec: redirect: community.windows.psexec win_audit_policy_system: redirect: community.windows.win_audit_policy_system win_audit_rule: redirect: community.windows.win_audit_rule win_chocolatey: redirect: chocolatey.chocolatey.win_chocolatey win_chocolatey_config: redirect: chocolatey.chocolatey.win_chocolatey_config win_chocolatey_facts: redirect: chocolatey.chocolatey.win_chocolatey_facts win_chocolatey_feature: redirect: chocolatey.chocolatey.win_chocolatey_feature win_chocolatey_source: redirect: chocolatey.chocolatey.win_chocolatey_source win_credential: redirect: community.windows.win_credential win_defrag: redirect: community.windows.win_defrag win_disk_facts: redirect: community.windows.win_disk_facts win_disk_image: redirect: community.windows.win_disk_image win_dns_record: redirect: community.windows.win_dns_record win_domain_computer: redirect: community.windows.win_domain_computer win_domain_group: redirect: community.windows.win_domain_group win_domain_group_membership: redirect: community.windows.win_domain_group_membership win_domain_user: redirect: community.windows.win_domain_user win_dotnet_ngen: redirect: community.windows.win_dotnet_ngen win_eventlog: redirect: community.windows.win_eventlog win_eventlog_entry: redirect: community.windows.win_eventlog_entry win_file_version: redirect: community.windows.win_file_version win_firewall: redirect: community.windows.win_firewall win_firewall_rule: redirect: community.windows.win_firewall_rule win_format: redirect: community.windows.win_format win_hosts: redirect: community.windows.win_hosts win_hotfix: redirect: community.windows.win_hotfix win_http_proxy: redirect: community.windows.win_http_proxy win_iis_virtualdirectory: redirect: community.windows.win_iis_virtualdirectory win_iis_webapplication: redirect: community.windows.win_iis_webapplication win_iis_webapppool: redirect: community.windows.win_iis_webapppool win_iis_webbinding: redirect: community.windows.win_iis_webbinding win_iis_website: redirect: community.windows.win_iis_website win_inet_proxy: redirect: community.windows.win_inet_proxy win_initialize_disk: redirect: community.windows.win_initialize_disk win_lineinfile: redirect: community.windows.win_lineinfile win_mapped_drive: redirect: community.windows.win_mapped_drive win_msg: redirect: community.windows.win_msg win_netbios: redirect: community.windows.win_netbios win_nssm: redirect: community.windows.win_nssm win_pagefile: redirect: community.windows.win_pagefile win_partition: redirect: community.windows.win_partition win_pester: redirect: community.windows.win_pester win_power_plan: redirect: community.windows.win_power_plan win_product_facts: redirect: community.windows.win_product_facts win_psexec: redirect: community.windows.win_psexec win_psmodule: redirect: community.windows.win_psmodule win_psrepository: redirect: community.windows.win_psrepository win_rabbitmq_plugin: redirect: community.windows.win_rabbitmq_plugin win_rds_cap: redirect: community.windows.win_rds_cap win_rds_rap: redirect: community.windows.win_rds_rap win_rds_settings: redirect: community.windows.win_rds_settings win_region: redirect: community.windows.win_region win_regmerge: redirect: community.windows.win_regmerge win_robocopy: redirect: community.windows.win_robocopy win_route: redirect: community.windows.win_route win_say: redirect: community.windows.win_say win_scheduled_task: redirect: community.windows.win_scheduled_task win_scheduled_task_stat: redirect: community.windows.win_scheduled_task_stat win_security_policy: redirect: community.windows.win_security_policy win_shortcut: redirect: community.windows.win_shortcut win_snmp: redirect: community.windows.win_snmp win_timezone: redirect: community.windows.win_timezone win_toast: redirect: community.windows.win_toast win_unzip: redirect: community.windows.win_unzip win_user_profile: redirect: community.windows.win_user_profile win_wait_for_process: redirect: community.windows.win_wait_for_process win_wakeonlan: redirect: community.windows.win_wakeonlan win_webpicmd: redirect: community.windows.win_webpicmd win_xml: redirect: community.windows.win_xml azure_rm_aks_facts: redirect: community.azure.azure_rm_aks_facts azure_rm_dnsrecordset_facts: redirect: community.azure.azure_rm_dnsrecordset_facts azure_rm_dnszone_facts: redirect: community.azure.azure_rm_dnszone_facts azure_rm_networkinterface_facts: redirect: community.azure.azure_rm_networkinterface_facts azure_rm_publicipaddress_facts: redirect: community.azure.azure_rm_publicipaddress_facts azure_rm_securitygroup_facts: redirect: community.azure.azure_rm_securitygroup_facts azure_rm_storageaccount_facts: redirect: community.azure.azure_rm_storageaccount_facts azure_rm_virtualmachine_facts: redirect: community.azure.azure_rm_virtualmachine_facts azure_rm_virtualnetwork_facts: redirect: community.azure.azure_rm_virtualnetwork_facts azure_rm_roledefinition_facts: redirect: community.azure.azure_rm_roledefinition_facts azure_rm_autoscale_facts: redirect: community.azure.azure_rm_autoscale_facts azure_rm_mysqldatabase_facts: redirect: community.azure.azure_rm_mysqldatabase_facts azure_rm_devtestlabschedule_facts: redirect: community.azure.azure_rm_devtestlabschedule_facts azure_rm_virtualmachinescaleset_facts: redirect: community.azure.azure_rm_virtualmachinescaleset_facts azure_rm_devtestlabcustomimage_facts: redirect: community.azure.azure_rm_devtestlabcustomimage_facts azure_rm_cosmosdbaccount_facts: redirect: community.azure.azure_rm_cosmosdbaccount_facts azure_rm_subnet_facts: redirect: community.azure.azure_rm_subnet_facts azure_rm_aksversion_facts: redirect: community.azure.azure_rm_aksversion_facts azure_rm_hdinsightcluster_facts: redirect: community.azure.azure_rm_hdinsightcluster_facts azure_rm_virtualmachinescalesetextension_facts: redirect: community.azure.azure_rm_virtualmachinescalesetextension_facts azure_rm_loadbalancer_facts: redirect: community.azure.azure_rm_loadbalancer_facts azure_rm_roleassignment_facts: redirect: community.azure.azure_rm_roleassignment_facts azure_rm_manageddisk_facts: redirect: community.azure.azure_rm_manageddisk_facts azure_rm_mysqlserver_facts: redirect: community.azure.azure_rm_mysqlserver_facts azure_rm_servicebus_facts: redirect: community.azure.azure_rm_servicebus_facts azure_rm_rediscache_facts: redirect: community.azure.azure_rm_rediscache_facts azure_rm_resource_facts: redirect: community.azure.azure_rm_resource_facts azure_rm_routetable_facts: redirect: community.azure.azure_rm_routetable_facts azure_rm_virtualmachine_extension: redirect: community.azure.azure_rm_virtualmachine_extension azure_rm_loganalyticsworkspace_facts: redirect: community.azure.azure_rm_loganalyticsworkspace_facts azure_rm_sqldatabase_facts: redirect: community.azure.azure_rm_sqldatabase_facts azure_rm_devtestlabartifactsource_facts: redirect: community.azure.azure_rm_devtestlabartifactsource_facts azure_rm_deployment_facts: redirect: community.azure.azure_rm_deployment_facts azure_rm_virtualmachineextension_facts: redirect: community.azure.azure_rm_virtualmachineextension_facts azure_rm_applicationsecuritygroup_facts: redirect: community.azure.azure_rm_applicationsecuritygroup_facts azure_rm_availabilityset_facts: redirect: community.azure.azure_rm_availabilityset_facts azure_rm_mariadbdatabase_facts: redirect: community.azure.azure_rm_mariadbdatabase_facts azure_rm_devtestlabenvironment_facts: redirect: community.azure.azure_rm_devtestlabenvironment_facts azure_rm_appserviceplan_facts: redirect: community.azure.azure_rm_appserviceplan_facts azure_rm_containerinstance_facts: redirect: community.azure.azure_rm_containerinstance_facts azure_rm_devtestlabarmtemplate_facts: redirect: community.azure.azure_rm_devtestlabarmtemplate_facts azure_rm_devtestlabartifact_facts: redirect: community.azure.azure_rm_devtestlabartifact_facts azure_rm_virtualmachinescalesetinstance_facts: redirect: community.azure.azure_rm_virtualmachinescalesetinstance_facts azure_rm_cdnendpoint_facts: redirect: community.azure.azure_rm_cdnendpoint_facts azure_rm_trafficmanagerprofile_facts: redirect: community.azure.azure_rm_trafficmanagerprofile_facts azure_rm_functionapp_facts: redirect: community.azure.azure_rm_functionapp_facts azure_rm_virtualmachineimage_facts: redirect: community.azure.azure_rm_virtualmachineimage_facts azure_rm_mariadbconfiguration_facts: redirect: community.azure.azure_rm_mariadbconfiguration_facts azure_rm_virtualnetworkpeering_facts: redirect: community.azure.azure_rm_virtualnetworkpeering_facts azure_rm_sqlserver_facts: redirect: community.azure.azure_rm_sqlserver_facts azure_rm_mariadbfirewallrule_facts: redirect: community.azure.azure_rm_mariadbfirewallrule_facts azure_rm_mysqlconfiguration_facts: redirect: community.azure.azure_rm_mysqlconfiguration_facts azure_rm_mysqlfirewallrule_facts: redirect: community.azure.azure_rm_mysqlfirewallrule_facts azure_rm_postgresqlfirewallrule_facts: redirect: community.azure.azure_rm_postgresqlfirewallrule_facts azure_rm_mariadbserver_facts: redirect: community.azure.azure_rm_mariadbserver_facts azure_rm_postgresqldatabase_facts: redirect: community.azure.azure_rm_postgresqldatabase_facts azure_rm_devtestlabvirtualnetwork_facts: redirect: community.azure.azure_rm_devtestlabvirtualnetwork_facts azure_rm_devtestlabpolicy_facts: redirect: community.azure.azure_rm_devtestlabpolicy_facts azure_rm_trafficmanagerendpoint_facts: redirect: community.azure.azure_rm_trafficmanagerendpoint_facts azure_rm_sqlfirewallrule_facts: redirect: community.azure.azure_rm_sqlfirewallrule_facts azure_rm_containerregistry_facts: redirect: community.azure.azure_rm_containerregistry_facts azure_rm_postgresqlconfiguration_facts: redirect: community.azure.azure_rm_postgresqlconfiguration_facts azure_rm_postgresqlserver_facts: redirect: community.azure.azure_rm_postgresqlserver_facts azure_rm_devtestlab_facts: redirect: community.azure.azure_rm_devtestlab_facts azure_rm_cdnprofile_facts: redirect: community.azure.azure_rm_cdnprofile_facts azure_rm_virtualmachine_scaleset: redirect: community.azure.azure_rm_virtualmachine_scaleset azure_rm_webapp_facts: redirect: community.azure.azure_rm_webapp_facts azure_rm_devtestlabvirtualmachine_facts: redirect: community.azure.azure_rm_devtestlabvirtualmachine_facts azure_rm_image_facts: redirect: community.azure.azure_rm_image_facts azure_rm_managed_disk: redirect: community.azure.azure_rm_managed_disk azure_rm_automationaccount_facts: redirect: community.azure.azure_rm_automationaccount_facts azure_rm_lock_facts: redirect: community.azure.azure_rm_lock_facts azure_rm_managed_disk_facts: redirect: community.azure.azure_rm_managed_disk_facts azure_rm_resourcegroup_facts: redirect: community.azure.azure_rm_resourcegroup_facts azure_rm_virtualmachine_scaleset_facts: redirect: community.azure.azure_rm_virtualmachine_scaleset_facts snow_record: redirect: servicenow.servicenow.snow_record snow_record_find: redirect: servicenow.servicenow.snow_record_find aws_az_facts: redirect: amazon.aws.aws_az_facts aws_caller_facts: redirect: amazon.aws.aws_caller_facts cloudformation_facts: redirect: amazon.aws.cloudformation_facts ec2_ami_facts: redirect: amazon.aws.ec2_ami_facts ec2_eni_facts: redirect: amazon.aws.ec2_eni_facts ec2_group_facts: redirect: amazon.aws.ec2_group_facts ec2_snapshot_facts: redirect: amazon.aws.ec2_snapshot_facts ec2_vol_facts: redirect: amazon.aws.ec2_vol_facts ec2_vpc_dhcp_option_facts: redirect: amazon.aws.ec2_vpc_dhcp_option_facts ec2_vpc_net_facts: redirect: amazon.aws.ec2_vpc_net_facts ec2_vpc_subnet_facts: redirect: amazon.aws.ec2_vpc_subnet_facts aws_az_info: redirect: amazon.aws.aws_az_info aws_caller_info: redirect: amazon.aws.aws_caller_info aws_s3: redirect: amazon.aws.aws_s3 cloudformation: redirect: amazon.aws.cloudformation cloudformation_info: redirect: amazon.aws.cloudformation_info ec2: redirect: amazon.aws.ec2 ec2_ami: redirect: amazon.aws.ec2_ami ec2_ami_info: redirect: amazon.aws.ec2_ami_info ec2_elb_lb: redirect: amazon.aws.ec2_elb_lb ec2_eni: redirect: amazon.aws.ec2_eni ec2_eni_info: redirect: amazon.aws.ec2_eni_info ec2_group: redirect: amazon.aws.ec2_group ec2_group_info: redirect: amazon.aws.ec2_group_info ec2_key: redirect: amazon.aws.ec2_key ec2_metadata_facts: redirect: amazon.aws.ec2_metadata_facts ec2_snapshot: redirect: amazon.aws.ec2_snapshot ec2_snapshot_info: redirect: amazon.aws.ec2_snapshot_info ec2_tag: redirect: amazon.aws.ec2_tag ec2_tag_info: redirect: amazon.aws.ec2_tag_info ec2_vol: redirect: amazon.aws.ec2_vol ec2_vol_info: redirect: amazon.aws.ec2_vol_info ec2_vpc_dhcp_option: redirect: amazon.aws.ec2_vpc_dhcp_option ec2_vpc_dhcp_option_info: redirect: amazon.aws.ec2_vpc_dhcp_option_info ec2_vpc_net: redirect: amazon.aws.ec2_vpc_net ec2_vpc_net_info: redirect: amazon.aws.ec2_vpc_net_info ec2_vpc_subnet: redirect: amazon.aws.ec2_vpc_subnet ec2_vpc_subnet_info: redirect: amazon.aws.ec2_vpc_subnet_info s3_bucket: redirect: amazon.aws.s3_bucket telnet: redirect: ansible.netcommon.telnet cli_command: redirect: ansible.netcommon.cli_command cli_config: redirect: ansible.netcommon.cli_config net_put: redirect: ansible.netcommon.net_put net_get: redirect: ansible.netcommon.net_get net_linkagg: redirect: ansible.netcommon.net_linkagg net_interface: redirect: ansible.netcommon.net_interface net_lldp_interface: redirect: ansible.netcommon.net_lldp_interface net_vlan: redirect: ansible.netcommon.net_vlan net_l2_interface: redirect: ansible.netcommon.net_l2_interface net_l3_interface: redirect: ansible.netcommon.net_l3_interface net_vrf: redirect: ansible.netcommon.net_vrf netconf_config: redirect: ansible.netcommon.netconf_config netconf_rpc: redirect: ansible.netcommon.netconf_rpc netconf_get: redirect: ansible.netcommon.netconf_get net_lldp: redirect: ansible.netcommon.net_lldp restconf_get: redirect: ansible.netcommon.restconf_get restconf_config: redirect: ansible.netcommon.restconf_config net_static_route: redirect: ansible.netcommon.net_static_route net_system: redirect: ansible.netcommon.net_system net_logging: redirect: ansible.netcommon.net_logging net_user: redirect: ansible.netcommon.net_user net_ping: redirect: ansible.netcommon.net_ping net_banner: redirect: ansible.netcommon.net_banner acl: redirect: ansible.posix.acl synchronize: redirect: ansible.posix.synchronize at: redirect: ansible.posix.at authorized_key: redirect: ansible.posix.authorized_key mount: redirect: ansible.posix.mount seboolean: redirect: ansible.posix.seboolean selinux: redirect: ansible.posix.selinux sysctl: redirect: ansible.posix.sysctl async_status.ps1: redirect: ansible.windows.async_status setup.ps1: redirect: ansible.windows.setup slurp.ps1: redirect: ansible.windows.slurp win_acl: redirect: ansible.windows.win_acl win_acl_inheritance: redirect: ansible.windows.win_acl_inheritance win_certificate_store: redirect: ansible.windows.win_certificate_store win_command: redirect: ansible.windows.win_command win_copy: redirect: ansible.windows.win_copy win_dns_client: redirect: ansible.windows.win_dns_client win_domain: redirect: ansible.windows.win_domain win_domain_controller: redirect: ansible.windows.win_domain_controller win_domain_membership: redirect: ansible.windows.win_domain_membership win_dsc: redirect: ansible.windows.win_dsc win_environment: redirect: ansible.windows.win_environment win_feature: redirect: ansible.windows.win_feature win_file: redirect: ansible.windows.win_file win_find: redirect: ansible.windows.win_find win_get_url: redirect: ansible.windows.win_get_url win_group: redirect: ansible.windows.win_group win_group_membership: redirect: ansible.windows.win_group_membership win_hostname: redirect: ansible.windows.win_hostname win_optional_feature: redirect: ansible.windows.win_optional_feature win_owner: redirect: ansible.windows.win_owner win_package: redirect: ansible.windows.win_package win_path: redirect: ansible.windows.win_path win_ping: redirect: ansible.windows.win_ping win_reboot: redirect: ansible.windows.win_reboot win_reg_stat: redirect: ansible.windows.win_reg_stat win_regedit: redirect: ansible.windows.win_regedit win_service: redirect: ansible.windows.win_service win_share: redirect: ansible.windows.win_share win_shell: redirect: ansible.windows.win_shell win_stat: redirect: ansible.windows.win_stat win_tempfile: redirect: ansible.windows.win_tempfile win_template: redirect: ansible.windows.win_template win_updates: redirect: ansible.windows.win_updates win_uri: redirect: ansible.windows.win_uri win_user: redirect: ansible.windows.win_user win_user_right: redirect: ansible.windows.win_user_right win_wait_for: redirect: ansible.windows.win_wait_for win_whoami: redirect: ansible.windows.win_whoami fortios_address: redirect: fortinet.fortios.fortios_address fortios_alertemail_setting: redirect: fortinet.fortios.fortios_alertemail_setting fortios_antivirus_heuristic: redirect: fortinet.fortios.fortios_antivirus_heuristic fortios_antivirus_profile: redirect: fortinet.fortios.fortios_antivirus_profile fortios_antivirus_quarantine: redirect: fortinet.fortios.fortios_antivirus_quarantine fortios_antivirus_settings: redirect: fortinet.fortios.fortios_antivirus_settings fortios_application_custom: redirect: fortinet.fortios.fortios_application_custom fortios_application_group: redirect: fortinet.fortios.fortios_application_group fortios_application_list: redirect: fortinet.fortios.fortios_application_list fortios_application_name: redirect: fortinet.fortios.fortios_application_name fortios_application_rule_settings: redirect: fortinet.fortios.fortios_application_rule_settings fortios_authentication_rule: redirect: fortinet.fortios.fortios_authentication_rule fortios_authentication_scheme: redirect: fortinet.fortios.fortios_authentication_scheme fortios_authentication_setting: redirect: fortinet.fortios.fortios_authentication_setting fortios_config: redirect: fortinet.fortios.fortios_config fortios_dlp_filepattern: redirect: fortinet.fortios.fortios_dlp_filepattern fortios_dlp_fp_doc_source: redirect: fortinet.fortios.fortios_dlp_fp_doc_source fortios_dlp_fp_sensitivity: redirect: fortinet.fortios.fortios_dlp_fp_sensitivity fortios_dlp_sensor: redirect: fortinet.fortios.fortios_dlp_sensor fortios_dlp_settings: redirect: fortinet.fortios.fortios_dlp_settings fortios_dnsfilter_domain_filter: redirect: fortinet.fortios.fortios_dnsfilter_domain_filter fortios_dnsfilter_profile: redirect: fortinet.fortios.fortios_dnsfilter_profile fortios_endpoint_control_client: redirect: fortinet.fortios.fortios_endpoint_control_client fortios_endpoint_control_forticlient_ems: redirect: fortinet.fortios.fortios_endpoint_control_forticlient_ems fortios_endpoint_control_forticlient_registration_sync: redirect: fortinet.fortios.fortios_endpoint_control_forticlient_registration_sync fortios_endpoint_control_profile: redirect: fortinet.fortios.fortios_endpoint_control_profile fortios_endpoint_control_settings: redirect: fortinet.fortios.fortios_endpoint_control_settings fortios_extender_controller_extender: redirect: fortinet.fortios.fortios_extender_controller_extender fortios_facts: redirect: fortinet.fortios.fortios_facts fortios_firewall_address: redirect: fortinet.fortios.fortios_firewall_address fortios_firewall_address6: redirect: fortinet.fortios.fortios_firewall_address6 fortios_firewall_address6_template: redirect: fortinet.fortios.fortios_firewall_address6_template fortios_firewall_addrgrp: redirect: fortinet.fortios.fortios_firewall_addrgrp fortios_firewall_addrgrp6: redirect: fortinet.fortios.fortios_firewall_addrgrp6 fortios_firewall_auth_portal: redirect: fortinet.fortios.fortios_firewall_auth_portal fortios_firewall_central_snat_map: redirect: fortinet.fortios.fortios_firewall_central_snat_map fortios_firewall_DoS_policy: redirect: fortinet.fortios.fortios_firewall_DoS_policy fortios_firewall_DoS_policy6: redirect: fortinet.fortios.fortios_firewall_DoS_policy6 fortios_firewall_dnstranslation: redirect: fortinet.fortios.fortios_firewall_dnstranslation fortios_firewall_identity_based_route: redirect: fortinet.fortios.fortios_firewall_identity_based_route fortios_firewall_interface_policy: redirect: fortinet.fortios.fortios_firewall_interface_policy fortios_firewall_interface_policy6: redirect: fortinet.fortios.fortios_firewall_interface_policy6 fortios_firewall_internet_service: redirect: fortinet.fortios.fortios_firewall_internet_service fortios_firewall_internet_service_custom: redirect: fortinet.fortios.fortios_firewall_internet_service_custom fortios_firewall_internet_service_group: redirect: fortinet.fortios.fortios_firewall_internet_service_group fortios_firewall_ip_translation: redirect: fortinet.fortios.fortios_firewall_ip_translation fortios_firewall_ipmacbinding_setting: redirect: fortinet.fortios.fortios_firewall_ipmacbinding_setting fortios_firewall_ipmacbinding_table: redirect: fortinet.fortios.fortios_firewall_ipmacbinding_table fortios_firewall_ippool: redirect: fortinet.fortios.fortios_firewall_ippool fortios_firewall_ippool6: redirect: fortinet.fortios.fortios_firewall_ippool6 fortios_firewall_ipv6_eh_filter: redirect: fortinet.fortios.fortios_firewall_ipv6_eh_filter fortios_firewall_ldb_monitor: redirect: fortinet.fortios.fortios_firewall_ldb_monitor fortios_firewall_local_in_policy: redirect: fortinet.fortios.fortios_firewall_local_in_policy fortios_firewall_local_in_policy6: redirect: fortinet.fortios.fortios_firewall_local_in_policy6 fortios_firewall_multicast_address: redirect: fortinet.fortios.fortios_firewall_multicast_address fortios_firewall_multicast_address6: redirect: fortinet.fortios.fortios_firewall_multicast_address6 fortios_firewall_multicast_policy: redirect: fortinet.fortios.fortios_firewall_multicast_policy fortios_firewall_multicast_policy6: redirect: fortinet.fortios.fortios_firewall_multicast_policy6 fortios_firewall_policy: redirect: fortinet.fortios.fortios_firewall_policy fortios_firewall_policy46: redirect: fortinet.fortios.fortios_firewall_policy46 fortios_firewall_policy6: redirect: fortinet.fortios.fortios_firewall_policy6 fortios_firewall_policy64: redirect: fortinet.fortios.fortios_firewall_policy64 fortios_firewall_profile_group: redirect: fortinet.fortios.fortios_firewall_profile_group fortios_firewall_profile_protocol_options: redirect: fortinet.fortios.fortios_firewall_profile_protocol_options fortios_firewall_proxy_address: redirect: fortinet.fortios.fortios_firewall_proxy_address fortios_firewall_proxy_addrgrp: redirect: fortinet.fortios.fortios_firewall_proxy_addrgrp fortios_firewall_proxy_policy: redirect: fortinet.fortios.fortios_firewall_proxy_policy fortios_firewall_schedule_group: redirect: fortinet.fortios.fortios_firewall_schedule_group fortios_firewall_schedule_onetime: redirect: fortinet.fortios.fortios_firewall_schedule_onetime fortios_firewall_schedule_recurring: redirect: fortinet.fortios.fortios_firewall_schedule_recurring fortios_firewall_service_category: redirect: fortinet.fortios.fortios_firewall_service_category fortios_firewall_service_custom: redirect: fortinet.fortios.fortios_firewall_service_custom fortios_firewall_service_group: redirect: fortinet.fortios.fortios_firewall_service_group fortios_firewall_shaper_per_ip_shaper: redirect: fortinet.fortios.fortios_firewall_shaper_per_ip_shaper fortios_firewall_shaper_traffic_shaper: redirect: fortinet.fortios.fortios_firewall_shaper_traffic_shaper fortios_firewall_shaping_policy: redirect: fortinet.fortios.fortios_firewall_shaping_policy fortios_firewall_shaping_profile: redirect: fortinet.fortios.fortios_firewall_shaping_profile fortios_firewall_sniffer: redirect: fortinet.fortios.fortios_firewall_sniffer fortios_firewall_ssh_host_key: redirect: fortinet.fortios.fortios_firewall_ssh_host_key fortios_firewall_ssh_local_ca: redirect: fortinet.fortios.fortios_firewall_ssh_local_ca fortios_firewall_ssh_local_key: redirect: fortinet.fortios.fortios_firewall_ssh_local_key fortios_firewall_ssh_setting: redirect: fortinet.fortios.fortios_firewall_ssh_setting fortios_firewall_ssl_server: redirect: fortinet.fortios.fortios_firewall_ssl_server fortios_firewall_ssl_setting: redirect: fortinet.fortios.fortios_firewall_ssl_setting fortios_firewall_ssl_ssh_profile: redirect: fortinet.fortios.fortios_firewall_ssl_ssh_profile fortios_firewall_ttl_policy: redirect: fortinet.fortios.fortios_firewall_ttl_policy fortios_firewall_vip: redirect: fortinet.fortios.fortios_firewall_vip fortios_firewall_vip46: redirect: fortinet.fortios.fortios_firewall_vip46 fortios_firewall_vip6: redirect: fortinet.fortios.fortios_firewall_vip6 fortios_firewall_vip64: redirect: fortinet.fortios.fortios_firewall_vip64 fortios_firewall_vipgrp: redirect: fortinet.fortios.fortios_firewall_vipgrp fortios_firewall_vipgrp46: redirect: fortinet.fortios.fortios_firewall_vipgrp46 fortios_firewall_vipgrp6: redirect: fortinet.fortios.fortios_firewall_vipgrp6 fortios_firewall_vipgrp64: redirect: fortinet.fortios.fortios_firewall_vipgrp64 fortios_firewall_wildcard_fqdn_custom: redirect: fortinet.fortios.fortios_firewall_wildcard_fqdn_custom fortios_firewall_wildcard_fqdn_group: redirect: fortinet.fortios.fortios_firewall_wildcard_fqdn_group fortios_ftp_proxy_explicit: redirect: fortinet.fortios.fortios_ftp_proxy_explicit fortios_icap_profile: redirect: fortinet.fortios.fortios_icap_profile fortios_icap_server: redirect: fortinet.fortios.fortios_icap_server fortios_ips_custom: redirect: fortinet.fortios.fortios_ips_custom fortios_ips_decoder: redirect: fortinet.fortios.fortios_ips_decoder fortios_ips_global: redirect: fortinet.fortios.fortios_ips_global fortios_ips_rule: redirect: fortinet.fortios.fortios_ips_rule fortios_ips_rule_settings: redirect: fortinet.fortios.fortios_ips_rule_settings fortios_ips_sensor: redirect: fortinet.fortios.fortios_ips_sensor fortios_ips_settings: redirect: fortinet.fortios.fortios_ips_settings fortios_ipv4_policy: redirect: fortinet.fortios.fortios_ipv4_policy fortios_log_custom_field: redirect: fortinet.fortios.fortios_log_custom_field fortios_log_disk_filter: redirect: fortinet.fortios.fortios_log_disk_filter fortios_log_disk_setting: redirect: fortinet.fortios.fortios_log_disk_setting fortios_log_eventfilter: redirect: fortinet.fortios.fortios_log_eventfilter fortios_log_fortianalyzer2_filter: redirect: fortinet.fortios.fortios_log_fortianalyzer2_filter fortios_log_fortianalyzer2_setting: redirect: fortinet.fortios.fortios_log_fortianalyzer2_setting fortios_log_fortianalyzer3_filter: redirect: fortinet.fortios.fortios_log_fortianalyzer3_filter fortios_log_fortianalyzer3_setting: redirect: fortinet.fortios.fortios_log_fortianalyzer3_setting fortios_log_fortianalyzer_filter: redirect: fortinet.fortios.fortios_log_fortianalyzer_filter fortios_log_fortianalyzer_override_filter: redirect: fortinet.fortios.fortios_log_fortianalyzer_override_filter fortios_log_fortianalyzer_override_setting: redirect: fortinet.fortios.fortios_log_fortianalyzer_override_setting fortios_log_fortianalyzer_setting: redirect: fortinet.fortios.fortios_log_fortianalyzer_setting fortios_log_fortiguard_filter: redirect: fortinet.fortios.fortios_log_fortiguard_filter fortios_log_fortiguard_override_filter: redirect: fortinet.fortios.fortios_log_fortiguard_override_filter fortios_log_fortiguard_override_setting: redirect: fortinet.fortios.fortios_log_fortiguard_override_setting fortios_log_fortiguard_setting: redirect: fortinet.fortios.fortios_log_fortiguard_setting fortios_log_gui_display: redirect: fortinet.fortios.fortios_log_gui_display fortios_log_memory_filter: redirect: fortinet.fortios.fortios_log_memory_filter fortios_log_memory_global_setting: redirect: fortinet.fortios.fortios_log_memory_global_setting fortios_log_memory_setting: redirect: fortinet.fortios.fortios_log_memory_setting fortios_log_null_device_filter: redirect: fortinet.fortios.fortios_log_null_device_filter fortios_log_null_device_setting: redirect: fortinet.fortios.fortios_log_null_device_setting fortios_log_setting: redirect: fortinet.fortios.fortios_log_setting fortios_log_syslogd2_filter: redirect: fortinet.fortios.fortios_log_syslogd2_filter fortios_log_syslogd2_setting: redirect: fortinet.fortios.fortios_log_syslogd2_setting fortios_log_syslogd3_filter: redirect: fortinet.fortios.fortios_log_syslogd3_filter fortios_log_syslogd3_setting: redirect: fortinet.fortios.fortios_log_syslogd3_setting fortios_log_syslogd4_filter: redirect: fortinet.fortios.fortios_log_syslogd4_filter fortios_log_syslogd4_setting: redirect: fortinet.fortios.fortios_log_syslogd4_setting fortios_log_syslogd_filter: redirect: fortinet.fortios.fortios_log_syslogd_filter fortios_log_syslogd_override_filter: redirect: fortinet.fortios.fortios_log_syslogd_override_filter fortios_log_syslogd_override_setting: redirect: fortinet.fortios.fortios_log_syslogd_override_setting fortios_log_syslogd_setting: redirect: fortinet.fortios.fortios_log_syslogd_setting fortios_log_threat_weight: redirect: fortinet.fortios.fortios_log_threat_weight fortios_log_webtrends_filter: redirect: fortinet.fortios.fortios_log_webtrends_filter fortios_log_webtrends_setting: redirect: fortinet.fortios.fortios_log_webtrends_setting fortios_report_chart: redirect: fortinet.fortios.fortios_report_chart fortios_report_dataset: redirect: fortinet.fortios.fortios_report_dataset fortios_report_layout: redirect: fortinet.fortios.fortios_report_layout fortios_report_setting: redirect: fortinet.fortios.fortios_report_setting fortios_report_style: redirect: fortinet.fortios.fortios_report_style fortios_report_theme: redirect: fortinet.fortios.fortios_report_theme fortios_router_access_list: redirect: fortinet.fortios.fortios_router_access_list fortios_router_access_list6: redirect: fortinet.fortios.fortios_router_access_list6 fortios_router_aspath_list: redirect: fortinet.fortios.fortios_router_aspath_list fortios_router_auth_path: redirect: fortinet.fortios.fortios_router_auth_path fortios_router_bfd: redirect: fortinet.fortios.fortios_router_bfd fortios_router_bfd6: redirect: fortinet.fortios.fortios_router_bfd6 fortios_router_bgp: redirect: fortinet.fortios.fortios_router_bgp fortios_router_community_list: redirect: fortinet.fortios.fortios_router_community_list fortios_router_isis: redirect: fortinet.fortios.fortios_router_isis fortios_router_key_chain: redirect: fortinet.fortios.fortios_router_key_chain fortios_router_multicast: redirect: fortinet.fortios.fortios_router_multicast fortios_router_multicast6: redirect: fortinet.fortios.fortios_router_multicast6 fortios_router_multicast_flow: redirect: fortinet.fortios.fortios_router_multicast_flow fortios_router_ospf: redirect: fortinet.fortios.fortios_router_ospf fortios_router_ospf6: redirect: fortinet.fortios.fortios_router_ospf6 fortios_router_policy: redirect: fortinet.fortios.fortios_router_policy fortios_router_policy6: redirect: fortinet.fortios.fortios_router_policy6 fortios_router_prefix_list: redirect: fortinet.fortios.fortios_router_prefix_list fortios_router_prefix_list6: redirect: fortinet.fortios.fortios_router_prefix_list6 fortios_router_rip: redirect: fortinet.fortios.fortios_router_rip fortios_router_ripng: redirect: fortinet.fortios.fortios_router_ripng fortios_router_route_map: redirect: fortinet.fortios.fortios_router_route_map fortios_router_setting: redirect: fortinet.fortios.fortios_router_setting fortios_router_static: redirect: fortinet.fortios.fortios_router_static fortios_router_static6: redirect: fortinet.fortios.fortios_router_static6 fortios_spamfilter_bwl: redirect: fortinet.fortios.fortios_spamfilter_bwl fortios_spamfilter_bword: redirect: fortinet.fortios.fortios_spamfilter_bword fortios_spamfilter_dnsbl: redirect: fortinet.fortios.fortios_spamfilter_dnsbl fortios_spamfilter_fortishield: redirect: fortinet.fortios.fortios_spamfilter_fortishield fortios_spamfilter_iptrust: redirect: fortinet.fortios.fortios_spamfilter_iptrust fortios_spamfilter_mheader: redirect: fortinet.fortios.fortios_spamfilter_mheader fortios_spamfilter_options: redirect: fortinet.fortios.fortios_spamfilter_options fortios_spamfilter_profile: redirect: fortinet.fortios.fortios_spamfilter_profile fortios_ssh_filter_profile: redirect: fortinet.fortios.fortios_ssh_filter_profile fortios_switch_controller_802_1X_settings: redirect: fortinet.fortios.fortios_switch_controller_802_1X_settings fortios_switch_controller_custom_command: redirect: fortinet.fortios.fortios_switch_controller_custom_command fortios_switch_controller_global: redirect: fortinet.fortios.fortios_switch_controller_global fortios_switch_controller_igmp_snooping: redirect: fortinet.fortios.fortios_switch_controller_igmp_snooping fortios_switch_controller_lldp_profile: redirect: fortinet.fortios.fortios_switch_controller_lldp_profile fortios_switch_controller_lldp_settings: redirect: fortinet.fortios.fortios_switch_controller_lldp_settings fortios_switch_controller_mac_sync_settings: redirect: fortinet.fortios.fortios_switch_controller_mac_sync_settings fortios_switch_controller_managed_switch: redirect: fortinet.fortios.fortios_switch_controller_managed_switch fortios_switch_controller_network_monitor_settings: redirect: fortinet.fortios.fortios_switch_controller_network_monitor_settings fortios_switch_controller_qos_dot1p_map: redirect: fortinet.fortios.fortios_switch_controller_qos_dot1p_map fortios_switch_controller_qos_ip_dscp_map: redirect: fortinet.fortios.fortios_switch_controller_qos_ip_dscp_map fortios_switch_controller_qos_qos_policy: redirect: fortinet.fortios.fortios_switch_controller_qos_qos_policy fortios_switch_controller_qos_queue_policy: redirect: fortinet.fortios.fortios_switch_controller_qos_queue_policy fortios_switch_controller_quarantine: redirect: fortinet.fortios.fortios_switch_controller_quarantine fortios_switch_controller_security_policy_802_1X: redirect: fortinet.fortios.fortios_switch_controller_security_policy_802_1X fortios_switch_controller_security_policy_captive_portal: redirect: fortinet.fortios.fortios_switch_controller_security_policy_captive_portal fortios_switch_controller_sflow: redirect: fortinet.fortios.fortios_switch_controller_sflow fortios_switch_controller_storm_control: redirect: fortinet.fortios.fortios_switch_controller_storm_control fortios_switch_controller_stp_settings: redirect: fortinet.fortios.fortios_switch_controller_stp_settings fortios_switch_controller_switch_group: redirect: fortinet.fortios.fortios_switch_controller_switch_group fortios_switch_controller_switch_interface_tag: redirect: fortinet.fortios.fortios_switch_controller_switch_interface_tag fortios_switch_controller_switch_log: redirect: fortinet.fortios.fortios_switch_controller_switch_log fortios_switch_controller_switch_profile: redirect: fortinet.fortios.fortios_switch_controller_switch_profile fortios_switch_controller_system: redirect: fortinet.fortios.fortios_switch_controller_system fortios_switch_controller_virtual_port_pool: redirect: fortinet.fortios.fortios_switch_controller_virtual_port_pool fortios_switch_controller_vlan: redirect: fortinet.fortios.fortios_switch_controller_vlan fortios_system_accprofile: redirect: fortinet.fortios.fortios_system_accprofile fortios_system_admin: redirect: fortinet.fortios.fortios_system_admin fortios_system_affinity_interrupt: redirect: fortinet.fortios.fortios_system_affinity_interrupt fortios_system_affinity_packet_redistribution: redirect: fortinet.fortios.fortios_system_affinity_packet_redistribution fortios_system_alarm: redirect: fortinet.fortios.fortios_system_alarm fortios_system_alias: redirect: fortinet.fortios.fortios_system_alias fortios_system_api_user: redirect: fortinet.fortios.fortios_system_api_user fortios_system_arp_table: redirect: fortinet.fortios.fortios_system_arp_table fortios_system_auto_install: redirect: fortinet.fortios.fortios_system_auto_install fortios_system_auto_script: redirect: fortinet.fortios.fortios_system_auto_script fortios_system_automation_action: redirect: fortinet.fortios.fortios_system_automation_action fortios_system_automation_destination: redirect: fortinet.fortios.fortios_system_automation_destination fortios_system_automation_stitch: redirect: fortinet.fortios.fortios_system_automation_stitch fortios_system_automation_trigger: redirect: fortinet.fortios.fortios_system_automation_trigger fortios_system_autoupdate_push_update: redirect: fortinet.fortios.fortios_system_autoupdate_push_update fortios_system_autoupdate_schedule: redirect: fortinet.fortios.fortios_system_autoupdate_schedule fortios_system_autoupdate_tunneling: redirect: fortinet.fortios.fortios_system_autoupdate_tunneling fortios_system_central_management: redirect: fortinet.fortios.fortios_system_central_management fortios_system_cluster_sync: redirect: fortinet.fortios.fortios_system_cluster_sync fortios_system_console: redirect: fortinet.fortios.fortios_system_console fortios_system_csf: redirect: fortinet.fortios.fortios_system_csf fortios_system_custom_language: redirect: fortinet.fortios.fortios_system_custom_language fortios_system_ddns: redirect: fortinet.fortios.fortios_system_ddns fortios_system_dedicated_mgmt: redirect: fortinet.fortios.fortios_system_dedicated_mgmt fortios_system_dhcp6_server: redirect: fortinet.fortios.fortios_system_dhcp6_server fortios_system_dhcp_server: redirect: fortinet.fortios.fortios_system_dhcp_server fortios_system_dns: redirect: fortinet.fortios.fortios_system_dns fortios_system_dns_database: redirect: fortinet.fortios.fortios_system_dns_database fortios_system_dns_server: redirect: fortinet.fortios.fortios_system_dns_server fortios_system_dscp_based_priority: redirect: fortinet.fortios.fortios_system_dscp_based_priority fortios_system_email_server: redirect: fortinet.fortios.fortios_system_email_server fortios_system_external_resource: redirect: fortinet.fortios.fortios_system_external_resource fortios_system_fips_cc: redirect: fortinet.fortios.fortios_system_fips_cc fortios_system_firmware_upgrade: redirect: fortinet.fortios.fortios_system_firmware_upgrade fortios_system_fm: redirect: fortinet.fortios.fortios_system_fm fortios_system_fortiguard: redirect: fortinet.fortios.fortios_system_fortiguard fortios_system_fortimanager: redirect: fortinet.fortios.fortios_system_fortimanager fortios_system_fortisandbox: redirect: fortinet.fortios.fortios_system_fortisandbox fortios_system_fsso_polling: redirect: fortinet.fortios.fortios_system_fsso_polling fortios_system_ftm_push: redirect: fortinet.fortios.fortios_system_ftm_push fortios_system_geoip_override: redirect: fortinet.fortios.fortios_system_geoip_override fortios_system_global: redirect: fortinet.fortios.fortios_system_global fortios_system_gre_tunnel: redirect: fortinet.fortios.fortios_system_gre_tunnel fortios_system_ha: redirect: fortinet.fortios.fortios_system_ha fortios_system_ha_monitor: redirect: fortinet.fortios.fortios_system_ha_monitor fortios_system_interface: redirect: fortinet.fortios.fortios_system_interface fortios_system_ipip_tunnel: redirect: fortinet.fortios.fortios_system_ipip_tunnel fortios_system_ips_urlfilter_dns: redirect: fortinet.fortios.fortios_system_ips_urlfilter_dns fortios_system_ips_urlfilter_dns6: redirect: fortinet.fortios.fortios_system_ips_urlfilter_dns6 fortios_system_ipv6_neighbor_cache: redirect: fortinet.fortios.fortios_system_ipv6_neighbor_cache fortios_system_ipv6_tunnel: redirect: fortinet.fortios.fortios_system_ipv6_tunnel fortios_system_link_monitor: redirect: fortinet.fortios.fortios_system_link_monitor fortios_system_mac_address_table: redirect: fortinet.fortios.fortios_system_mac_address_table fortios_system_management_tunnel: redirect: fortinet.fortios.fortios_system_management_tunnel fortios_system_mobile_tunnel: redirect: fortinet.fortios.fortios_system_mobile_tunnel fortios_system_nat64: redirect: fortinet.fortios.fortios_system_nat64 fortios_system_nd_proxy: redirect: fortinet.fortios.fortios_system_nd_proxy fortios_system_netflow: redirect: fortinet.fortios.fortios_system_netflow fortios_system_network_visibility: redirect: fortinet.fortios.fortios_system_network_visibility fortios_system_ntp: redirect: fortinet.fortios.fortios_system_ntp fortios_system_object_tagging: redirect: fortinet.fortios.fortios_system_object_tagging fortios_system_password_policy: redirect: fortinet.fortios.fortios_system_password_policy fortios_system_password_policy_guest_admin: redirect: fortinet.fortios.fortios_system_password_policy_guest_admin fortios_system_pppoe_interface: redirect: fortinet.fortios.fortios_system_pppoe_interface fortios_system_probe_response: redirect: fortinet.fortios.fortios_system_probe_response fortios_system_proxy_arp: redirect: fortinet.fortios.fortios_system_proxy_arp fortios_system_replacemsg_admin: redirect: fortinet.fortios.fortios_system_replacemsg_admin fortios_system_replacemsg_alertmail: redirect: fortinet.fortios.fortios_system_replacemsg_alertmail fortios_system_replacemsg_auth: redirect: fortinet.fortios.fortios_system_replacemsg_auth fortios_system_replacemsg_device_detection_portal: redirect: fortinet.fortios.fortios_system_replacemsg_device_detection_portal fortios_system_replacemsg_ec: redirect: fortinet.fortios.fortios_system_replacemsg_ec fortios_system_replacemsg_fortiguard_wf: redirect: fortinet.fortios.fortios_system_replacemsg_fortiguard_wf fortios_system_replacemsg_ftp: redirect: fortinet.fortios.fortios_system_replacemsg_ftp fortios_system_replacemsg_group: redirect: fortinet.fortios.fortios_system_replacemsg_group fortios_system_replacemsg_http: redirect: fortinet.fortios.fortios_system_replacemsg_http fortios_system_replacemsg_icap: redirect: fortinet.fortios.fortios_system_replacemsg_icap fortios_system_replacemsg_image: redirect: fortinet.fortios.fortios_system_replacemsg_image fortios_system_replacemsg_mail: redirect: fortinet.fortios.fortios_system_replacemsg_mail fortios_system_replacemsg_nac_quar: redirect: fortinet.fortios.fortios_system_replacemsg_nac_quar fortios_system_replacemsg_nntp: redirect: fortinet.fortios.fortios_system_replacemsg_nntp fortios_system_replacemsg_spam: redirect: fortinet.fortios.fortios_system_replacemsg_spam fortios_system_replacemsg_sslvpn: redirect: fortinet.fortios.fortios_system_replacemsg_sslvpn fortios_system_replacemsg_traffic_quota: redirect: fortinet.fortios.fortios_system_replacemsg_traffic_quota fortios_system_replacemsg_utm: redirect: fortinet.fortios.fortios_system_replacemsg_utm fortios_system_replacemsg_webproxy: redirect: fortinet.fortios.fortios_system_replacemsg_webproxy fortios_system_resource_limits: redirect: fortinet.fortios.fortios_system_resource_limits fortios_system_sdn_connector: redirect: fortinet.fortios.fortios_system_sdn_connector fortios_system_session_helper: redirect: fortinet.fortios.fortios_system_session_helper fortios_system_session_ttl: redirect: fortinet.fortios.fortios_system_session_ttl fortios_system_settings: redirect: fortinet.fortios.fortios_system_settings fortios_system_sflow: redirect: fortinet.fortios.fortios_system_sflow fortios_system_sit_tunnel: redirect: fortinet.fortios.fortios_system_sit_tunnel fortios_system_sms_server: redirect: fortinet.fortios.fortios_system_sms_server fortios_system_snmp_community: redirect: fortinet.fortios.fortios_system_snmp_community fortios_system_snmp_sysinfo: redirect: fortinet.fortios.fortios_system_snmp_sysinfo fortios_system_snmp_user: redirect: fortinet.fortios.fortios_system_snmp_user fortios_system_storage: redirect: fortinet.fortios.fortios_system_storage fortios_system_switch_interface: redirect: fortinet.fortios.fortios_system_switch_interface fortios_system_tos_based_priority: redirect: fortinet.fortios.fortios_system_tos_based_priority fortios_system_vdom: redirect: fortinet.fortios.fortios_system_vdom fortios_system_vdom_dns: redirect: fortinet.fortios.fortios_system_vdom_dns fortios_system_vdom_exception: redirect: fortinet.fortios.fortios_system_vdom_exception fortios_system_vdom_link: redirect: fortinet.fortios.fortios_system_vdom_link fortios_system_vdom_netflow: redirect: fortinet.fortios.fortios_system_vdom_netflow fortios_system_vdom_property: redirect: fortinet.fortios.fortios_system_vdom_property fortios_system_vdom_radius_server: redirect: fortinet.fortios.fortios_system_vdom_radius_server fortios_system_vdom_sflow: redirect: fortinet.fortios.fortios_system_vdom_sflow fortios_system_virtual_wan_link: redirect: fortinet.fortios.fortios_system_virtual_wan_link fortios_system_virtual_wire_pair: redirect: fortinet.fortios.fortios_system_virtual_wire_pair fortios_system_vxlan: redirect: fortinet.fortios.fortios_system_vxlan fortios_system_wccp: redirect: fortinet.fortios.fortios_system_wccp fortios_system_zone: redirect: fortinet.fortios.fortios_system_zone fortios_user_adgrp: redirect: fortinet.fortios.fortios_user_adgrp fortios_user_device: redirect: fortinet.fortios.fortios_user_device fortios_user_device_access_list: redirect: fortinet.fortios.fortios_user_device_access_list fortios_user_device_category: redirect: fortinet.fortios.fortios_user_device_category fortios_user_device_group: redirect: fortinet.fortios.fortios_user_device_group fortios_user_domain_controller: redirect: fortinet.fortios.fortios_user_domain_controller fortios_user_fortitoken: redirect: fortinet.fortios.fortios_user_fortitoken fortios_user_fsso: redirect: fortinet.fortios.fortios_user_fsso fortios_user_fsso_polling: redirect: fortinet.fortios.fortios_user_fsso_polling fortios_user_group: redirect: fortinet.fortios.fortios_user_group fortios_user_krb_keytab: redirect: fortinet.fortios.fortios_user_krb_keytab fortios_user_ldap: redirect: fortinet.fortios.fortios_user_ldap fortios_user_local: redirect: fortinet.fortios.fortios_user_local fortios_user_password_policy: redirect: fortinet.fortios.fortios_user_password_policy fortios_user_peer: redirect: fortinet.fortios.fortios_user_peer fortios_user_peergrp: redirect: fortinet.fortios.fortios_user_peergrp fortios_user_pop3: redirect: fortinet.fortios.fortios_user_pop3 fortios_user_quarantine: redirect: fortinet.fortios.fortios_user_quarantine fortios_user_radius: redirect: fortinet.fortios.fortios_user_radius fortios_user_security_exempt_list: redirect: fortinet.fortios.fortios_user_security_exempt_list fortios_user_setting: redirect: fortinet.fortios.fortios_user_setting fortios_user_tacacsplus: redirect: fortinet.fortios.fortios_user_tacacsplus fortios_voip_profile: redirect: fortinet.fortios.fortios_voip_profile fortios_vpn_certificate_ca: redirect: fortinet.fortios.fortios_vpn_certificate_ca fortios_vpn_certificate_crl: redirect: fortinet.fortios.fortios_vpn_certificate_crl fortios_vpn_certificate_local: redirect: fortinet.fortios.fortios_vpn_certificate_local fortios_vpn_certificate_ocsp_server: redirect: fortinet.fortios.fortios_vpn_certificate_ocsp_server fortios_vpn_certificate_remote: redirect: fortinet.fortios.fortios_vpn_certificate_remote fortios_vpn_certificate_setting: redirect: fortinet.fortios.fortios_vpn_certificate_setting fortios_vpn_ipsec_concentrator: redirect: fortinet.fortios.fortios_vpn_ipsec_concentrator fortios_vpn_ipsec_forticlient: redirect: fortinet.fortios.fortios_vpn_ipsec_forticlient fortios_vpn_ipsec_manualkey: redirect: fortinet.fortios.fortios_vpn_ipsec_manualkey fortios_vpn_ipsec_manualkey_interface: redirect: fortinet.fortios.fortios_vpn_ipsec_manualkey_interface fortios_vpn_ipsec_phase1: redirect: fortinet.fortios.fortios_vpn_ipsec_phase1 fortios_vpn_ipsec_phase1_interface: redirect: fortinet.fortios.fortios_vpn_ipsec_phase1_interface fortios_vpn_ipsec_phase2: redirect: fortinet.fortios.fortios_vpn_ipsec_phase2 fortios_vpn_ipsec_phase2_interface: redirect: fortinet.fortios.fortios_vpn_ipsec_phase2_interface fortios_vpn_l2tp: redirect: fortinet.fortios.fortios_vpn_l2tp fortios_vpn_pptp: redirect: fortinet.fortios.fortios_vpn_pptp fortios_vpn_ssl_settings: redirect: fortinet.fortios.fortios_vpn_ssl_settings fortios_vpn_ssl_web_host_check_software: redirect: fortinet.fortios.fortios_vpn_ssl_web_host_check_software fortios_vpn_ssl_web_portal: redirect: fortinet.fortios.fortios_vpn_ssl_web_portal fortios_vpn_ssl_web_realm: redirect: fortinet.fortios.fortios_vpn_ssl_web_realm fortios_vpn_ssl_web_user_bookmark: redirect: fortinet.fortios.fortios_vpn_ssl_web_user_bookmark fortios_vpn_ssl_web_user_group_bookmark: redirect: fortinet.fortios.fortios_vpn_ssl_web_user_group_bookmark fortios_waf_main_class: redirect: fortinet.fortios.fortios_waf_main_class fortios_waf_profile: redirect: fortinet.fortios.fortios_waf_profile fortios_waf_signature: redirect: fortinet.fortios.fortios_waf_signature fortios_waf_sub_class: redirect: fortinet.fortios.fortios_waf_sub_class fortios_wanopt_auth_group: redirect: fortinet.fortios.fortios_wanopt_auth_group fortios_wanopt_cache_service: redirect: fortinet.fortios.fortios_wanopt_cache_service fortios_wanopt_content_delivery_network_rule: redirect: fortinet.fortios.fortios_wanopt_content_delivery_network_rule fortios_wanopt_peer: redirect: fortinet.fortios.fortios_wanopt_peer fortios_wanopt_profile: redirect: fortinet.fortios.fortios_wanopt_profile fortios_wanopt_remote_storage: redirect: fortinet.fortios.fortios_wanopt_remote_storage fortios_wanopt_settings: redirect: fortinet.fortios.fortios_wanopt_settings fortios_wanopt_webcache: redirect: fortinet.fortios.fortios_wanopt_webcache fortios_web_proxy_debug_url: redirect: fortinet.fortios.fortios_web_proxy_debug_url fortios_web_proxy_explicit: redirect: fortinet.fortios.fortios_web_proxy_explicit fortios_web_proxy_forward_server: redirect: fortinet.fortios.fortios_web_proxy_forward_server fortios_web_proxy_forward_server_group: redirect: fortinet.fortios.fortios_web_proxy_forward_server_group fortios_web_proxy_global: redirect: fortinet.fortios.fortios_web_proxy_global fortios_web_proxy_profile: redirect: fortinet.fortios.fortios_web_proxy_profile fortios_web_proxy_url_match: redirect: fortinet.fortios.fortios_web_proxy_url_match fortios_web_proxy_wisp: redirect: fortinet.fortios.fortios_web_proxy_wisp fortios_webfilter: redirect: fortinet.fortios.fortios_webfilter fortios_webfilter_content: redirect: fortinet.fortios.fortios_webfilter_content fortios_webfilter_content_header: redirect: fortinet.fortios.fortios_webfilter_content_header fortios_webfilter_fortiguard: redirect: fortinet.fortios.fortios_webfilter_fortiguard fortios_webfilter_ftgd_local_cat: redirect: fortinet.fortios.fortios_webfilter_ftgd_local_cat fortios_webfilter_ftgd_local_rating: redirect: fortinet.fortios.fortios_webfilter_ftgd_local_rating fortios_webfilter_ips_urlfilter_cache_setting: redirect: fortinet.fortios.fortios_webfilter_ips_urlfilter_cache_setting fortios_webfilter_ips_urlfilter_setting: redirect: fortinet.fortios.fortios_webfilter_ips_urlfilter_setting fortios_webfilter_ips_urlfilter_setting6: redirect: fortinet.fortios.fortios_webfilter_ips_urlfilter_setting6 fortios_webfilter_override: redirect: fortinet.fortios.fortios_webfilter_override fortios_webfilter_profile: redirect: fortinet.fortios.fortios_webfilter_profile fortios_webfilter_search_engine: redirect: fortinet.fortios.fortios_webfilter_search_engine fortios_webfilter_urlfilter: redirect: fortinet.fortios.fortios_webfilter_urlfilter fortios_wireless_controller_ap_status: redirect: fortinet.fortios.fortios_wireless_controller_ap_status fortios_wireless_controller_ble_profile: redirect: fortinet.fortios.fortios_wireless_controller_ble_profile fortios_wireless_controller_bonjour_profile: redirect: fortinet.fortios.fortios_wireless_controller_bonjour_profile fortios_wireless_controller_global: redirect: fortinet.fortios.fortios_wireless_controller_global fortios_wireless_controller_hotspot20_anqp_3gpp_cellular: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_3gpp_cellular fortios_wireless_controller_hotspot20_anqp_ip_address_type: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_ip_address_type fortios_wireless_controller_hotspot20_anqp_nai_realm: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_nai_realm fortios_wireless_controller_hotspot20_anqp_network_auth_type: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_network_auth_type fortios_wireless_controller_hotspot20_anqp_roaming_consortium: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_roaming_consortium fortios_wireless_controller_hotspot20_anqp_venue_name: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_anqp_venue_name fortios_wireless_controller_hotspot20_h2qp_conn_capability: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_h2qp_conn_capability fortios_wireless_controller_hotspot20_h2qp_operator_name: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_h2qp_operator_name fortios_wireless_controller_hotspot20_h2qp_osu_provider: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_h2qp_osu_provider fortios_wireless_controller_hotspot20_h2qp_wan_metric: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_h2qp_wan_metric fortios_wireless_controller_hotspot20_hs_profile: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_hs_profile fortios_wireless_controller_hotspot20_icon: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_icon fortios_wireless_controller_hotspot20_qos_map: redirect: fortinet.fortios.fortios_wireless_controller_hotspot20_qos_map fortios_wireless_controller_inter_controller: redirect: fortinet.fortios.fortios_wireless_controller_inter_controller fortios_wireless_controller_qos_profile: redirect: fortinet.fortios.fortios_wireless_controller_qos_profile fortios_wireless_controller_setting: redirect: fortinet.fortios.fortios_wireless_controller_setting fortios_wireless_controller_timers: redirect: fortinet.fortios.fortios_wireless_controller_timers fortios_wireless_controller_utm_profile: redirect: fortinet.fortios.fortios_wireless_controller_utm_profile fortios_wireless_controller_vap: redirect: fortinet.fortios.fortios_wireless_controller_vap fortios_wireless_controller_vap_group: redirect: fortinet.fortios.fortios_wireless_controller_vap_group fortios_wireless_controller_wids_profile: redirect: fortinet.fortios.fortios_wireless_controller_wids_profile fortios_wireless_controller_wtp: redirect: fortinet.fortios.fortios_wireless_controller_wtp fortios_wireless_controller_wtp_group: redirect: fortinet.fortios.fortios_wireless_controller_wtp_group fortios_wireless_controller_wtp_profile: redirect: fortinet.fortios.fortios_wireless_controller_wtp_profile netbox_device: redirect: netbox.netbox.netbox_device netbox_ip_address: redirect: netbox.netbox.netbox_ip_address netbox_interface: redirect: netbox.netbox.netbox_interface netbox_prefix: redirect: netbox.netbox.netbox_prefix netbox_site: redirect: netbox.netbox.netbox_site aws_netapp_cvs_FileSystems: redirect: netapp.aws.aws_netapp_cvs_filesystems aws_netapp_cvs_active_directory: redirect: netapp.aws.aws_netapp_cvs_active_directory aws_netapp_cvs_pool: redirect: netapp.aws.aws_netapp_cvs_pool aws_netapp_cvs_snapshots: redirect: netapp.aws.aws_netapp_cvs_snapshots na_elementsw_access_group: redirect: netapp.elementsw.na_elementsw_access_group na_elementsw_account: redirect: netapp.elementsw.na_elementsw_account na_elementsw_admin_users: redirect: netapp.elementsw.na_elementsw_admin_users na_elementsw_backup: redirect: netapp.elementsw.na_elementsw_backup na_elementsw_check_connections: redirect: netapp.elementsw.na_elementsw_check_connections na_elementsw_cluster: redirect: netapp.elementsw.na_elementsw_cluster na_elementsw_cluster_config: redirect: netapp.elementsw.na_elementsw_cluster_config na_elementsw_cluster_pair: redirect: netapp.elementsw.na_elementsw_cluster_pair na_elementsw_cluster_snmp: redirect: netapp.elementsw.na_elementsw_cluster_snmp na_elementsw_drive: redirect: netapp.elementsw.na_elementsw_drive na_elementsw_initiators: redirect: netapp.elementsw.na_elementsw_initiators na_elementsw_ldap: redirect: netapp.elementsw.na_elementsw_ldap na_elementsw_network_interfaces: redirect: netapp.elementsw.na_elementsw_network_interfaces na_elementsw_node: redirect: netapp.elementsw.na_elementsw_node na_elementsw_snapshot: redirect: netapp.elementsw.na_elementsw_snapshot na_elementsw_snapshot_restore: redirect: netapp.elementsw.na_elementsw_snapshot_restore na_elementsw_snapshot_schedule: redirect: netapp.elementsw.na_elementsw_snapshot_schedule na_elementsw_vlan: redirect: netapp.elementsw.na_elementsw_vlan na_elementsw_volume: redirect: netapp.elementsw.na_elementsw_volume na_elementsw_volume_clone: redirect: netapp.elementsw.na_elementsw_volume_clone na_elementsw_volume_pair: redirect: netapp.elementsw.na_elementsw_volume_pair na_ontap_aggregate: redirect: netapp.ontap.na_ontap_aggregate na_ontap_autosupport: redirect: netapp.ontap.na_ontap_autosupport na_ontap_broadcast_domain: redirect: netapp.ontap.na_ontap_broadcast_domain na_ontap_broadcast_domain_ports: redirect: netapp.ontap.na_ontap_broadcast_domain_ports na_ontap_cg_snapshot: redirect: netapp.ontap.na_ontap_cg_snapshot na_ontap_cifs: redirect: netapp.ontap.na_ontap_cifs na_ontap_cifs_acl: redirect: netapp.ontap.na_ontap_cifs_acl na_ontap_cifs_server: redirect: netapp.ontap.na_ontap_cifs_server na_ontap_cluster: redirect: netapp.ontap.na_ontap_cluster na_ontap_cluster_ha: redirect: netapp.ontap.na_ontap_cluster_ha na_ontap_cluster_peer: redirect: netapp.ontap.na_ontap_cluster_peer na_ontap_command: redirect: netapp.ontap.na_ontap_command na_ontap_disks: redirect: netapp.ontap.na_ontap_disks na_ontap_dns: redirect: netapp.ontap.na_ontap_dns na_ontap_export_policy: redirect: netapp.ontap.na_ontap_export_policy na_ontap_export_policy_rule: redirect: netapp.ontap.na_ontap_export_policy_rule na_ontap_fcp: redirect: netapp.ontap.na_ontap_fcp na_ontap_firewall_policy: redirect: netapp.ontap.na_ontap_firewall_policy na_ontap_firmware_upgrade: redirect: netapp.ontap.na_ontap_firmware_upgrade na_ontap_flexcache: redirect: netapp.ontap.na_ontap_flexcache na_ontap_igroup: redirect: netapp.ontap.na_ontap_igroup na_ontap_igroup_initiator: redirect: netapp.ontap.na_ontap_igroup_initiator na_ontap_info: redirect: netapp.ontap.na_ontap_info na_ontap_interface: redirect: netapp.ontap.na_ontap_interface na_ontap_ipspace: redirect: netapp.ontap.na_ontap_ipspace na_ontap_iscsi: redirect: netapp.ontap.na_ontap_iscsi na_ontap_job_schedule: redirect: netapp.ontap.na_ontap_job_schedule na_ontap_kerberos_realm: redirect: netapp.ontap.na_ontap_kerberos_realm na_ontap_ldap: redirect: netapp.ontap.na_ontap_ldap na_ontap_ldap_client: redirect: netapp.ontap.na_ontap_ldap_client na_ontap_license: redirect: netapp.ontap.na_ontap_license na_ontap_lun: redirect: netapp.ontap.na_ontap_lun na_ontap_lun_copy: redirect: netapp.ontap.na_ontap_lun_copy na_ontap_lun_map: redirect: netapp.ontap.na_ontap_lun_map na_ontap_motd: redirect: netapp.ontap.na_ontap_motd na_ontap_ndmp: redirect: netapp.ontap.na_ontap_ndmp na_ontap_net_ifgrp: redirect: netapp.ontap.na_ontap_net_ifgrp na_ontap_net_port: redirect: netapp.ontap.na_ontap_net_port na_ontap_net_routes: redirect: netapp.ontap.na_ontap_net_routes na_ontap_net_subnet: redirect: netapp.ontap.na_ontap_net_subnet na_ontap_net_vlan: redirect: netapp.ontap.na_ontap_net_vlan na_ontap_nfs: redirect: netapp.ontap.na_ontap_nfs na_ontap_node: redirect: netapp.ontap.na_ontap_node na_ontap_ntp: redirect: netapp.ontap.na_ontap_ntp na_ontap_nvme: redirect: netapp.ontap.na_ontap_nvme na_ontap_nvme_namespace: redirect: netapp.ontap.na_ontap_nvme_namespace na_ontap_nvme_subsystem: redirect: netapp.ontap.na_ontap_nvme_subsystem na_ontap_object_store: redirect: netapp.ontap.na_ontap_object_store na_ontap_ports: redirect: netapp.ontap.na_ontap_ports na_ontap_portset: redirect: netapp.ontap.na_ontap_portset na_ontap_qos_adaptive_policy_group: redirect: netapp.ontap.na_ontap_qos_adaptive_policy_group na_ontap_qos_policy_group: redirect: netapp.ontap.na_ontap_qos_policy_group na_ontap_qtree: redirect: netapp.ontap.na_ontap_qtree na_ontap_quotas: redirect: netapp.ontap.na_ontap_quotas na_ontap_security_key_manager: redirect: netapp.ontap.na_ontap_security_key_manager na_ontap_service_processor_network: redirect: netapp.ontap.na_ontap_service_processor_network na_ontap_snapmirror: redirect: netapp.ontap.na_ontap_snapmirror na_ontap_snapshot: redirect: netapp.ontap.na_ontap_snapshot na_ontap_snapshot_policy: redirect: netapp.ontap.na_ontap_snapshot_policy na_ontap_snmp: redirect: netapp.ontap.na_ontap_snmp na_ontap_software_update: redirect: netapp.ontap.na_ontap_software_update na_ontap_svm: redirect: netapp.ontap.na_ontap_svm na_ontap_svm_options: redirect: netapp.ontap.na_ontap_svm_options na_ontap_ucadapter: redirect: netapp.ontap.na_ontap_ucadapter na_ontap_unix_group: redirect: netapp.ontap.na_ontap_unix_group na_ontap_unix_user: redirect: netapp.ontap.na_ontap_unix_user na_ontap_user: redirect: netapp.ontap.na_ontap_user na_ontap_user_role: redirect: netapp.ontap.na_ontap_user_role na_ontap_volume: redirect: netapp.ontap.na_ontap_volume na_ontap_volume_autosize: redirect: netapp.ontap.na_ontap_volume_autosize na_ontap_volume_clone: redirect: netapp.ontap.na_ontap_volume_clone na_ontap_vscan: redirect: netapp.ontap.na_ontap_vscan na_ontap_vscan_on_access_policy: redirect: netapp.ontap.na_ontap_vscan_on_access_policy na_ontap_vscan_on_demand_task: redirect: netapp.ontap.na_ontap_vscan_on_demand_task na_ontap_vscan_scanner_pool: redirect: netapp.ontap.na_ontap_vscan_scanner_pool na_ontap_vserver_cifs_security: redirect: netapp.ontap.na_ontap_vserver_cifs_security na_ontap_vserver_peer: redirect: netapp.ontap.na_ontap_vserver_peer cp_mgmt_access_layer: redirect: check_point.mgmt.cp_mgmt_access_layer cp_mgmt_access_layer_facts: redirect: check_point.mgmt.cp_mgmt_access_layer_facts cp_mgmt_access_role: redirect: check_point.mgmt.cp_mgmt_access_role cp_mgmt_access_role_facts: redirect: check_point.mgmt.cp_mgmt_access_role_facts cp_mgmt_access_rule: redirect: check_point.mgmt.cp_mgmt_access_rule cp_mgmt_access_rule_facts: redirect: check_point.mgmt.cp_mgmt_access_rule_facts cp_mgmt_address_range: redirect: check_point.mgmt.cp_mgmt_address_range cp_mgmt_address_range_facts: redirect: check_point.mgmt.cp_mgmt_address_range_facts cp_mgmt_administrator: redirect: check_point.mgmt.cp_mgmt_administrator cp_mgmt_administrator_facts: redirect: check_point.mgmt.cp_mgmt_administrator_facts cp_mgmt_application_site: redirect: check_point.mgmt.cp_mgmt_application_site cp_mgmt_application_site_category: redirect: check_point.mgmt.cp_mgmt_application_site_category cp_mgmt_application_site_category_facts: redirect: check_point.mgmt.cp_mgmt_application_site_category_facts cp_mgmt_application_site_facts: redirect: check_point.mgmt.cp_mgmt_application_site_facts cp_mgmt_application_site_group: redirect: check_point.mgmt.cp_mgmt_application_site_group cp_mgmt_application_site_group_facts: redirect: check_point.mgmt.cp_mgmt_application_site_group_facts cp_mgmt_assign_global_assignment: redirect: check_point.mgmt.cp_mgmt_assign_global_assignment cp_mgmt_discard: redirect: check_point.mgmt.cp_mgmt_discard cp_mgmt_dns_domain: redirect: check_point.mgmt.cp_mgmt_dns_domain cp_mgmt_dns_domain_facts: redirect: check_point.mgmt.cp_mgmt_dns_domain_facts cp_mgmt_dynamic_object: redirect: check_point.mgmt.cp_mgmt_dynamic_object cp_mgmt_dynamic_object_facts: redirect: check_point.mgmt.cp_mgmt_dynamic_object_facts cp_mgmt_exception_group: redirect: check_point.mgmt.cp_mgmt_exception_group cp_mgmt_exception_group_facts: redirect: check_point.mgmt.cp_mgmt_exception_group_facts cp_mgmt_global_assignment: redirect: check_point.mgmt.cp_mgmt_global_assignment cp_mgmt_global_assignment_facts: redirect: check_point.mgmt.cp_mgmt_global_assignment_facts cp_mgmt_group: redirect: check_point.mgmt.cp_mgmt_group cp_mgmt_group_facts: redirect: check_point.mgmt.cp_mgmt_group_facts cp_mgmt_group_with_exclusion: redirect: check_point.mgmt.cp_mgmt_group_with_exclusion cp_mgmt_group_with_exclusion_facts: redirect: check_point.mgmt.cp_mgmt_group_with_exclusion_facts cp_mgmt_host: redirect: check_point.mgmt.cp_mgmt_host cp_mgmt_host_facts: redirect: check_point.mgmt.cp_mgmt_host_facts cp_mgmt_install_policy: redirect: check_point.mgmt.cp_mgmt_install_policy cp_mgmt_mds_facts: redirect: check_point.mgmt.cp_mgmt_mds_facts cp_mgmt_multicast_address_range: redirect: check_point.mgmt.cp_mgmt_multicast_address_range cp_mgmt_multicast_address_range_facts: redirect: check_point.mgmt.cp_mgmt_multicast_address_range_facts cp_mgmt_network: redirect: check_point.mgmt.cp_mgmt_network cp_mgmt_network_facts: redirect: check_point.mgmt.cp_mgmt_network_facts cp_mgmt_package: redirect: check_point.mgmt.cp_mgmt_package cp_mgmt_package_facts: redirect: check_point.mgmt.cp_mgmt_package_facts cp_mgmt_publish: redirect: check_point.mgmt.cp_mgmt_publish cp_mgmt_put_file: redirect: check_point.mgmt.cp_mgmt_put_file cp_mgmt_run_ips_update: redirect: check_point.mgmt.cp_mgmt_run_ips_update cp_mgmt_run_script: redirect: check_point.mgmt.cp_mgmt_run_script cp_mgmt_security_zone: redirect: check_point.mgmt.cp_mgmt_security_zone cp_mgmt_security_zone_facts: redirect: check_point.mgmt.cp_mgmt_security_zone_facts cp_mgmt_service_dce_rpc: redirect: check_point.mgmt.cp_mgmt_service_dce_rpc cp_mgmt_service_dce_rpc_facts: redirect: check_point.mgmt.cp_mgmt_service_dce_rpc_facts cp_mgmt_service_group: redirect: check_point.mgmt.cp_mgmt_service_group cp_mgmt_service_group_facts: redirect: check_point.mgmt.cp_mgmt_service_group_facts cp_mgmt_service_icmp: redirect: check_point.mgmt.cp_mgmt_service_icmp cp_mgmt_service_icmp6: redirect: check_point.mgmt.cp_mgmt_service_icmp6 cp_mgmt_service_icmp6_facts: redirect: check_point.mgmt.cp_mgmt_service_icmp6_facts cp_mgmt_service_icmp_facts: redirect: check_point.mgmt.cp_mgmt_service_icmp_facts cp_mgmt_service_other: redirect: check_point.mgmt.cp_mgmt_service_other cp_mgmt_service_other_facts: redirect: check_point.mgmt.cp_mgmt_service_other_facts cp_mgmt_service_rpc: redirect: check_point.mgmt.cp_mgmt_service_rpc cp_mgmt_service_rpc_facts: redirect: check_point.mgmt.cp_mgmt_service_rpc_facts cp_mgmt_service_sctp: redirect: check_point.mgmt.cp_mgmt_service_sctp cp_mgmt_service_sctp_facts: redirect: check_point.mgmt.cp_mgmt_service_sctp_facts cp_mgmt_service_tcp: redirect: check_point.mgmt.cp_mgmt_service_tcp cp_mgmt_service_tcp_facts: redirect: check_point.mgmt.cp_mgmt_service_tcp_facts cp_mgmt_service_udp: redirect: check_point.mgmt.cp_mgmt_service_udp cp_mgmt_service_udp_facts: redirect: check_point.mgmt.cp_mgmt_service_udp_facts cp_mgmt_session_facts: redirect: check_point.mgmt.cp_mgmt_session_facts cp_mgmt_simple_gateway: redirect: check_point.mgmt.cp_mgmt_simple_gateway cp_mgmt_simple_gateway_facts: redirect: check_point.mgmt.cp_mgmt_simple_gateway_facts cp_mgmt_tag: redirect: check_point.mgmt.cp_mgmt_tag cp_mgmt_tag_facts: redirect: check_point.mgmt.cp_mgmt_tag_facts cp_mgmt_threat_exception: redirect: check_point.mgmt.cp_mgmt_threat_exception cp_mgmt_threat_exception_facts: redirect: check_point.mgmt.cp_mgmt_threat_exception_facts cp_mgmt_threat_indicator: redirect: check_point.mgmt.cp_mgmt_threat_indicator cp_mgmt_threat_indicator_facts: redirect: check_point.mgmt.cp_mgmt_threat_indicator_facts cp_mgmt_threat_layer: redirect: check_point.mgmt.cp_mgmt_threat_layer cp_mgmt_threat_layer_facts: redirect: check_point.mgmt.cp_mgmt_threat_layer_facts cp_mgmt_threat_profile: redirect: check_point.mgmt.cp_mgmt_threat_profile cp_mgmt_threat_profile_facts: redirect: check_point.mgmt.cp_mgmt_threat_profile_facts cp_mgmt_threat_protection_override: redirect: check_point.mgmt.cp_mgmt_threat_protection_override cp_mgmt_threat_rule: redirect: check_point.mgmt.cp_mgmt_threat_rule cp_mgmt_threat_rule_facts: redirect: check_point.mgmt.cp_mgmt_threat_rule_facts cp_mgmt_time: redirect: check_point.mgmt.cp_mgmt_time cp_mgmt_time_facts: redirect: check_point.mgmt.cp_mgmt_time_facts cp_mgmt_verify_policy: redirect: check_point.mgmt.cp_mgmt_verify_policy cp_mgmt_vpn_community_meshed: redirect: check_point.mgmt.cp_mgmt_vpn_community_meshed cp_mgmt_vpn_community_meshed_facts: redirect: check_point.mgmt.cp_mgmt_vpn_community_meshed_facts cp_mgmt_vpn_community_star: redirect: check_point.mgmt.cp_mgmt_vpn_community_star cp_mgmt_vpn_community_star_facts: redirect: check_point.mgmt.cp_mgmt_vpn_community_star_facts cp_mgmt_wildcard: redirect: check_point.mgmt.cp_mgmt_wildcard cp_mgmt_wildcard_facts: redirect: check_point.mgmt.cp_mgmt_wildcard_facts eos_ospfv2: redirect: arista.eos.eos_ospfv2 eos_static_route: redirect: arista.eos.eos_static_route eos_acls: redirect: arista.eos.eos_acls eos_interfaces: redirect: arista.eos.eos_interfaces eos_facts: redirect: arista.eos.eos_facts eos_logging: redirect: arista.eos.eos_logging eos_lag_interfaces: redirect: arista.eos.eos_lag_interfaces eos_l2_interfaces: redirect: arista.eos.eos_l2_interfaces eos_l3_interface: redirect: arista.eos.eos_l3_interface eos_lacp: redirect: arista.eos.eos_lacp eos_lldp_global: redirect: arista.eos.eos_lldp_global eos_static_routes: redirect: arista.eos.eos_static_routes eos_lacp_interfaces: redirect: arista.eos.eos_lacp_interfaces eos_system: redirect: arista.eos.eos_system eos_vlan: redirect: arista.eos.eos_vlan eos_eapi: redirect: arista.eos.eos_eapi eos_acl_interfaces: redirect: arista.eos.eos_acl_interfaces eos_l2_interface: redirect: arista.eos.eos_l2_interface eos_lldp_interfaces: redirect: arista.eos.eos_lldp_interfaces eos_command: redirect: arista.eos.eos_command eos_linkagg: redirect: arista.eos.eos_linkagg eos_l3_interfaces: redirect: arista.eos.eos_l3_interfaces eos_vlans: redirect: arista.eos.eos_vlans eos_user: redirect: arista.eos.eos_user eos_banner: redirect: arista.eos.eos_banner eos_lldp: redirect: arista.eos.eos_lldp eos_interface: redirect: arista.eos.eos_interface eos_config: redirect: arista.eos.eos_config eos_bgp: redirect: arista.eos.eos_bgp eos_vrf: redirect: arista.eos.eos_vrf aci_aaa_user: redirect: cisco.aci.aci_aaa_user aci_aaa_user_certificate: redirect: cisco.aci.aci_aaa_user_certificate aci_access_port_block_to_access_port: redirect: cisco.aci.aci_access_port_block_to_access_port aci_access_port_to_interface_policy_leaf_profile: redirect: cisco.aci.aci_access_port_to_interface_policy_leaf_profile aci_access_sub_port_block_to_access_port: redirect: cisco.aci.aci_access_sub_port_block_to_access_port aci_aep: redirect: cisco.aci.aci_aep aci_aep_to_domain: redirect: cisco.aci.aci_aep_to_domain aci_ap: redirect: cisco.aci.aci_ap aci_bd: redirect: cisco.aci.aci_bd aci_bd_subnet: redirect: cisco.aci.aci_bd_subnet aci_bd_to_l3out: redirect: cisco.aci.aci_bd_to_l3out aci_config_rollback: redirect: cisco.aci.aci_config_rollback aci_config_snapshot: redirect: cisco.aci.aci_config_snapshot aci_contract: redirect: cisco.aci.aci_contract aci_contract_subject: redirect: cisco.aci.aci_contract_subject aci_contract_subject_to_filter: redirect: cisco.aci.aci_contract_subject_to_filter aci_domain: redirect: cisco.aci.aci_domain aci_domain_to_encap_pool: redirect: cisco.aci.aci_domain_to_encap_pool aci_domain_to_vlan_pool: redirect: cisco.aci.aci_domain_to_vlan_pool aci_encap_pool: redirect: cisco.aci.aci_encap_pool aci_encap_pool_range: redirect: cisco.aci.aci_encap_pool_range aci_epg: redirect: cisco.aci.aci_epg aci_epg_monitoring_policy: redirect: cisco.aci.aci_epg_monitoring_policy aci_epg_to_contract: redirect: cisco.aci.aci_epg_to_contract aci_epg_to_domain: redirect: cisco.aci.aci_epg_to_domain aci_fabric_node: redirect: cisco.aci.aci_fabric_node aci_fabric_scheduler: redirect: cisco.aci.aci_fabric_scheduler aci_filter: redirect: cisco.aci.aci_filter aci_filter_entry: redirect: cisco.aci.aci_filter_entry aci_firmware_group: redirect: cisco.aci.aci_firmware_group aci_firmware_group_node: redirect: cisco.aci.aci_firmware_group_node aci_firmware_policy: redirect: cisco.aci.aci_firmware_policy aci_firmware_source: redirect: cisco.aci.aci_firmware_source aci_interface_policy_cdp: redirect: cisco.aci.aci_interface_policy_cdp aci_interface_policy_fc: redirect: cisco.aci.aci_interface_policy_fc aci_interface_policy_l2: redirect: cisco.aci.aci_interface_policy_l2 aci_interface_policy_leaf_policy_group: redirect: cisco.aci.aci_interface_policy_leaf_policy_group aci_interface_policy_leaf_profile: redirect: cisco.aci.aci_interface_policy_leaf_profile aci_interface_policy_lldp: redirect: cisco.aci.aci_interface_policy_lldp aci_interface_policy_mcp: redirect: cisco.aci.aci_interface_policy_mcp aci_interface_policy_ospf: redirect: cisco.aci.aci_interface_policy_ospf aci_interface_policy_port_channel: redirect: cisco.aci.aci_interface_policy_port_channel aci_interface_policy_port_security: redirect: cisco.aci.aci_interface_policy_port_security aci_interface_selector_to_switch_policy_leaf_profile: redirect: cisco.aci.aci_interface_selector_to_switch_policy_leaf_profile aci_l3out: redirect: cisco.aci.aci_l3out aci_l3out_extepg: redirect: cisco.aci.aci_l3out_extepg aci_l3out_extsubnet: redirect: cisco.aci.aci_l3out_extsubnet aci_l3out_route_tag_policy: redirect: cisco.aci.aci_l3out_route_tag_policy aci_maintenance_group: redirect: cisco.aci.aci_maintenance_group aci_maintenance_group_node: redirect: cisco.aci.aci_maintenance_group_node aci_maintenance_policy: redirect: cisco.aci.aci_maintenance_policy aci_rest: redirect: cisco.aci.aci_rest aci_static_binding_to_epg: redirect: cisco.aci.aci_static_binding_to_epg aci_switch_leaf_selector: redirect: cisco.aci.aci_switch_leaf_selector aci_switch_policy_leaf_profile: redirect: cisco.aci.aci_switch_policy_leaf_profile aci_switch_policy_vpc_protection_group: redirect: cisco.aci.aci_switch_policy_vpc_protection_group aci_taboo_contract: redirect: cisco.aci.aci_taboo_contract aci_tenant: redirect: cisco.aci.aci_tenant aci_tenant_action_rule_profile: redirect: cisco.aci.aci_tenant_action_rule_profile aci_tenant_ep_retention_policy: redirect: cisco.aci.aci_tenant_ep_retention_policy aci_tenant_span_dst_group: redirect: cisco.aci.aci_tenant_span_dst_group aci_tenant_span_src_group: redirect: cisco.aci.aci_tenant_span_src_group aci_tenant_span_src_group_to_dst_group: redirect: cisco.aci.aci_tenant_span_src_group_to_dst_group aci_vlan_pool: redirect: cisco.aci.aci_vlan_pool aci_vlan_pool_encap_block: redirect: cisco.aci.aci_vlan_pool_encap_block aci_vmm_credential: redirect: cisco.aci.aci_vmm_credential aci_vrf: redirect: cisco.aci.aci_vrf asa_acl: redirect: cisco.asa.asa_acl asa_config: redirect: cisco.asa.asa_config asa_og: redirect: cisco.asa.asa_og asa_command: redirect: cisco.asa.asa_command intersight_facts: redirect: cisco.intersight.intersight_info intersight_info: redirect: cisco.intersight.intersight_info intersight_rest_api: redirect: cisco.intersight.intersight_rest_api ios_ospfv2: redirect: cisco.ios.ios_ospfv2 ios_l3_interfaces: redirect: cisco.ios.ios_l3_interfaces ios_lldp: redirect: cisco.ios.ios_lldp ios_interface: redirect: cisco.ios.ios_interface ios_lldp_interfaces: redirect: cisco.ios.ios_lldp_interfaces ios_l3_interface: redirect: cisco.ios.ios_l3_interface ios_acl_interfaces: redirect: cisco.ios.ios_acl_interfaces ios_static_routes: redirect: cisco.ios.ios_static_routes ios_l2_interfaces: redirect: cisco.ios.ios_l2_interfaces ios_logging: redirect: cisco.ios.ios_logging ios_vlan: redirect: cisco.ios.ios_vlan ios_command: redirect: cisco.ios.ios_command ios_static_route: redirect: cisco.ios.ios_static_route ios_lldp_global: redirect: cisco.ios.ios_lldp_global ios_banner: redirect: cisco.ios.ios_banner ios_lag_interfaces: redirect: cisco.ios.ios_lag_interfaces ios_linkagg: redirect: cisco.ios.ios_linkagg ios_user: redirect: cisco.ios.ios_user ios_system: redirect: cisco.ios.ios_system ios_facts: redirect: cisco.ios.ios_facts ios_ping: redirect: cisco.ios.ios_ping ios_vlans: redirect: cisco.ios.ios_vlans ios_vrf: redirect: cisco.ios.ios_vrf ios_bgp: redirect: cisco.ios.ios_bgp ios_ntp: redirect: cisco.ios.ios_ntp ios_lacp_interfaces: redirect: cisco.ios.ios_lacp_interfaces ios_lacp: redirect: cisco.ios.ios_lacp ios_config: redirect: cisco.ios.ios_config ios_l2_interface: redirect: cisco.ios.ios_l2_interface ios_acls: redirect: cisco.ios.ios_acls ios_interfaces: redirect: cisco.ios.ios_interfaces iosxr_ospfv2: redirect: cisco.iosxr.iosxr_ospfv2 iosxr_bgp: redirect: cisco.iosxr.iosxr_bgp iosxr_lldp_interfaces: redirect: cisco.iosxr.iosxr_lldp_interfaces iosxr_l3_interfaces: redirect: cisco.iosxr.iosxr_l3_interfaces iosxr_netconf: redirect: cisco.iosxr.iosxr_netconf iosxr_static_routes: redirect: cisco.iosxr.iosxr_static_routes iosxr_lldp_global: redirect: cisco.iosxr.iosxr_lldp_global iosxr_config: redirect: cisco.iosxr.iosxr_config iosxr_lag_interfaces: redirect: cisco.iosxr.iosxr_lag_interfaces iosxr_interface: redirect: cisco.iosxr.iosxr_interface iosxr_user: redirect: cisco.iosxr.iosxr_user iosxr_facts: redirect: cisco.iosxr.iosxr_facts iosxr_interfaces: redirect: cisco.iosxr.iosxr_interfaces iosxr_acl_interfaces: redirect: cisco.iosxr.iosxr_acl_interfaces iosxr_l2_interfaces: redirect: cisco.iosxr.iosxr_l2_interfaces iosxr_logging: redirect: cisco.iosxr.iosxr_logging iosxr_lacp: redirect: cisco.iosxr.iosxr_lacp iosxr_acls: redirect: cisco.iosxr.iosxr_acls iosxr_system: redirect: cisco.iosxr.iosxr_system iosxr_command: redirect: cisco.iosxr.iosxr_command iosxr_lacp_interfaces: redirect: cisco.iosxr.iosxr_lacp_interfaces iosxr_banner: redirect: cisco.iosxr.iosxr_banner meraki_admin: redirect: cisco.meraki.meraki_admin meraki_config_template: redirect: cisco.meraki.meraki_config_template meraki_content_filtering: redirect: cisco.meraki.meraki_content_filtering meraki_device: redirect: cisco.meraki.meraki_device meraki_firewalled_services: redirect: cisco.meraki.meraki_firewalled_services meraki_malware: redirect: cisco.meraki.meraki_malware meraki_mr_l3_firewall: redirect: cisco.meraki.meraki_mr_l3_firewall meraki_mx_l3_firewall: redirect: cisco.meraki.meraki_mx_l3_firewall meraki_mx_l7_firewall: redirect: cisco.meraki.meraki_mx_l7_firewall meraki_nat: redirect: cisco.meraki.meraki_nat meraki_network: redirect: cisco.meraki.meraki_network meraki_organization: redirect: cisco.meraki.meraki_organization meraki_snmp: redirect: cisco.meraki.meraki_snmp meraki_ssid: redirect: cisco.meraki.meraki_ssid meraki_static_route: redirect: cisco.meraki.meraki_static_route meraki_switchport: redirect: cisco.meraki.meraki_switchport meraki_syslog: redirect: cisco.meraki.meraki_syslog meraki_vlan: redirect: cisco.meraki.meraki_vlan meraki_webhook: redirect: cisco.meraki.meraki_webhook mso_label: redirect: cisco.mso.mso_label mso_role: redirect: cisco.mso.mso_role mso_schema: redirect: cisco.mso.mso_schema mso_schema_site: redirect: cisco.mso.mso_schema_site mso_schema_site_anp: redirect: cisco.mso.mso_schema_site_anp mso_schema_site_anp_epg: redirect: cisco.mso.mso_schema_site_anp_epg mso_schema_site_anp_epg_domain: redirect: cisco.mso.mso_schema_site_anp_epg_domain mso_schema_site_anp_epg_staticleaf: redirect: cisco.mso.mso_schema_site_anp_epg_staticleaf mso_schema_site_anp_epg_staticport: redirect: cisco.mso.mso_schema_site_anp_epg_staticport mso_schema_site_anp_epg_subnet: redirect: cisco.mso.mso_schema_site_anp_epg_subnet mso_schema_site_bd: redirect: cisco.mso.mso_schema_site_bd mso_schema_site_bd_l3out: redirect: cisco.mso.mso_schema_site_bd_l3out mso_schema_site_bd_subnet: redirect: cisco.mso.mso_schema_site_bd_subnet mso_schema_site_vrf: redirect: cisco.mso.mso_schema_site_vrf mso_schema_site_vrf_region: redirect: cisco.mso.mso_schema_site_vrf_region mso_schema_site_vrf_region_cidr: redirect: cisco.mso.mso_schema_site_vrf_region_cidr mso_schema_site_vrf_region_cidr_subnet: redirect: cisco.mso.mso_schema_site_vrf_region_cidr_subnet mso_schema_template: redirect: cisco.mso.mso_schema_template mso_schema_template_anp: redirect: cisco.mso.mso_schema_template_anp mso_schema_template_anp_epg: redirect: cisco.mso.mso_schema_template_anp_epg mso_schema_template_anp_epg_contract: redirect: cisco.mso.mso_schema_template_anp_epg_contract mso_schema_template_anp_epg_subnet: redirect: cisco.mso.mso_schema_template_anp_epg_subnet mso_schema_template_bd: redirect: cisco.mso.mso_schema_template_bd mso_schema_template_bd_subnet: redirect: cisco.mso.mso_schema_template_bd_subnet mso_schema_template_contract_filter: redirect: cisco.mso.mso_schema_template_contract_filter mso_schema_template_deploy: redirect: cisco.mso.mso_schema_template_deploy mso_schema_template_externalepg: redirect: cisco.mso.mso_schema_template_externalepg mso_schema_template_filter_entry: redirect: cisco.mso.mso_schema_template_filter_entry mso_schema_template_l3out: redirect: cisco.mso.mso_schema_template_l3out mso_schema_template_vrf: redirect: cisco.mso.mso_schema_template_vrf mso_site: redirect: cisco.mso.mso_site mso_tenant: redirect: cisco.mso.mso_tenant mso_user: redirect: cisco.mso.mso_user nxos_telemetry: redirect: cisco.nxos.nxos_telemetry nxos_user: redirect: cisco.nxos.nxos_user nxos_bfd_interfaces: redirect: cisco.nxos.nxos_bfd_interfaces nxos_ospf: redirect: cisco.nxos.nxos_ospf nxos_ospfv2: redirect: cisco.nxos.nxos_ospfv2 nxos_system: redirect: cisco.nxos.nxos_system nxos_l3_interface: redirect: cisco.nxos.nxos_l3_interface nxos_smu: redirect: cisco.nxos.nxos_smu nxos_reboot: redirect: cisco.nxos.nxos_reboot nxos_static_routes: redirect: cisco.nxos.nxos_static_routes nxos_static_route: redirect: cisco.nxos.nxos_static_route nxos_acl_interfaces: redirect: cisco.nxos.nxos_acl_interfaces nxos_vpc: redirect: cisco.nxos.nxos_vpc nxos_linkagg: redirect: cisco.nxos.nxos_linkagg nxos_vxlan_vtep_vni: redirect: cisco.nxos.nxos_vxlan_vtep_vni nxos_vrrp: redirect: cisco.nxos.nxos_vrrp nxos_lldp: redirect: cisco.nxos.nxos_lldp nxos_interface: redirect: cisco.nxos.nxos_interface nxos_lacp_interfaces: redirect: cisco.nxos.nxos_lacp_interfaces nxos_gir_profile_management: redirect: cisco.nxos.nxos_gir_profile_management nxos_snmp_community: redirect: cisco.nxos.nxos_snmp_community nxos_lag_interfaces: redirect: cisco.nxos.nxos_lag_interfaces nxos_acl: redirect: cisco.nxos.nxos_acl nxos_hsrp_interfaces: redirect: cisco.nxos.nxos_hsrp_interfaces nxos_lldp_global: redirect: cisco.nxos.nxos_lldp_global nxos_snmp_contact: redirect: cisco.nxos.nxos_snmp_contact nxos_vrf_interface: redirect: cisco.nxos.nxos_vrf_interface nxos_rpm: redirect: cisco.nxos.nxos_rpm nxos_ntp_options: redirect: cisco.nxos.nxos_ntp_options nxos_ospf_vrf: redirect: cisco.nxos.nxos_ospf_vrf nxos_vtp_version: redirect: cisco.nxos.nxos_vtp_version nxos_igmp_interface: redirect: cisco.nxos.nxos_igmp_interface nxos_bgp_neighbor: redirect: cisco.nxos.nxos_bgp_neighbor nxos_bgp: redirect: cisco.nxos.nxos_bgp nxos_rollback: redirect: cisco.nxos.nxos_rollback nxos_aaa_server: redirect: cisco.nxos.nxos_aaa_server nxos_udld_interface: redirect: cisco.nxos.nxos_udld_interface nxos_bgp_af: redirect: cisco.nxos.nxos_bgp_af nxos_feature: redirect: cisco.nxos.nxos_feature nxos_snmp_traps: redirect: cisco.nxos.nxos_snmp_traps nxos_evpn_global: redirect: cisco.nxos.nxos_evpn_global nxos_igmp: redirect: cisco.nxos.nxos_igmp nxos_aaa_server_host: redirect: cisco.nxos.nxos_aaa_server_host nxos_vrf_af: redirect: cisco.nxos.nxos_vrf_af nxos_snapshot: redirect: cisco.nxos.nxos_snapshot nxos_gir: redirect: cisco.nxos.nxos_gir nxos_command: redirect: cisco.nxos.nxos_command nxos_vxlan_vtep: redirect: cisco.nxos.nxos_vxlan_vtep nxos_snmp_location: redirect: cisco.nxos.nxos_snmp_location nxos_evpn_vni: redirect: cisco.nxos.nxos_evpn_vni nxos_vpc_interface: redirect: cisco.nxos.nxos_vpc_interface nxos_logging: redirect: cisco.nxos.nxos_logging nxos_pim: redirect: cisco.nxos.nxos_pim nxos_ping: redirect: cisco.nxos.nxos_ping nxos_pim_rp_address: redirect: cisco.nxos.nxos_pim_rp_address nxos_pim_interface: redirect: cisco.nxos.nxos_pim_interface nxos_install_os: redirect: cisco.nxos.nxos_install_os nxos_nxapi: redirect: cisco.nxos.nxos_nxapi nxos_l2_interface: redirect: cisco.nxos.nxos_l2_interface nxos_bgp_neighbor_af: redirect: cisco.nxos.nxos_bgp_neighbor_af nxos_lacp: redirect: cisco.nxos.nxos_lacp nxos_lldp_interfaces: redirect: cisco.nxos.nxos_lldp_interfaces nxos_acl_interface: redirect: cisco.nxos.nxos_acl_interface nxos_vrf: redirect: cisco.nxos.nxos_vrf nxos_interface_ospf: redirect: cisco.nxos.nxos_interface_ospf nxos_acls: redirect: cisco.nxos.nxos_acls nxos_vtp_password: redirect: cisco.nxos.nxos_vtp_password nxos_l3_interfaces: redirect: cisco.nxos.nxos_l3_interfaces nxos_igmp_snooping: redirect: cisco.nxos.nxos_igmp_snooping nxos_banner: redirect: cisco.nxos.nxos_banner nxos_bfd_global: redirect: cisco.nxos.nxos_bfd_global nxos_udld: redirect: cisco.nxos.nxos_udld nxos_vtp_domain: redirect: cisco.nxos.nxos_vtp_domain nxos_snmp_host: redirect: cisco.nxos.nxos_snmp_host nxos_l2_interfaces: redirect: cisco.nxos.nxos_l2_interfaces nxos_hsrp: redirect: cisco.nxos.nxos_hsrp nxos_interfaces: redirect: cisco.nxos.nxos_interfaces nxos_overlay_global: redirect: cisco.nxos.nxos_overlay_global nxos_snmp_user: redirect: cisco.nxos.nxos_snmp_user nxos_vlans: redirect: cisco.nxos.nxos_vlans nxos_ntp: redirect: cisco.nxos.nxos_ntp nxos_file_copy: redirect: cisco.nxos.nxos_file_copy nxos_ntp_auth: redirect: cisco.nxos.nxos_ntp_auth nxos_config: redirect: cisco.nxos.nxos_config nxos_vlan: redirect: cisco.nxos.nxos_vlan nxos_facts: redirect: cisco.nxos.nxos_facts nxos_zone_zoneset: redirect: cisco.nxos.nxos_zone_zoneset nxos_vsan: redirect: cisco.nxos.nxos_vsan nxos_devicealias: redirect: cisco.nxos.nxos_devicealias ucs_managed_objects: redirect: cisco.ucs.ucs_managed_objects ucs_vnic_template: redirect: cisco.ucs.ucs_vnic_template ucs_query: redirect: cisco.ucs.ucs_query ucs_dns_server: redirect: cisco.ucs.ucs_dns_server ucs_lan_connectivity: redirect: cisco.ucs.ucs_lan_connectivity ucs_vhba_template: redirect: cisco.ucs.ucs_vhba_template ucs_san_connectivity: redirect: cisco.ucs.ucs_san_connectivity ucs_disk_group_policy: redirect: cisco.ucs.ucs_disk_group_policy ucs_uuid_pool: redirect: cisco.ucs.ucs_uuid_pool ucs_vlan_find: redirect: cisco.ucs.ucs_vlan_find ucs_vlans: redirect: cisco.ucs.ucs_vlans ucs_service_profile_template: redirect: cisco.ucs.ucs_service_profile_template ucs_ip_pool: redirect: cisco.ucs.ucs_ip_pool ucs_timezone: redirect: cisco.ucs.ucs_timezone ucs_ntp_server: redirect: cisco.ucs.ucs_ntp_server ucs_mac_pool: redirect: cisco.ucs.ucs_mac_pool ucs_storage_profile: redirect: cisco.ucs.ucs_storage_profile ucs_org: redirect: cisco.ucs.ucs_org ucs_vsans: redirect: cisco.ucs.ucs_vsans ucs_wwn_pool: redirect: cisco.ucs.ucs_wwn_pool bigip_apm_acl: redirect: f5networks.f5_modules.bigip_apm_acl bigip_apm_network_access: redirect: f5networks.f5_modules.bigip_apm_network_access bigip_apm_policy_fetch: redirect: f5networks.f5_modules.bigip_apm_policy_fetch bigip_apm_policy_import: redirect: f5networks.f5_modules.bigip_apm_policy_import bigip_appsvcs_extension: redirect: f5networks.f5_modules.bigip_appsvcs_extension bigip_asm_dos_application: redirect: f5networks.f5_modules.bigip_asm_dos_application bigip_asm_policy_fetch: redirect: f5networks.f5_modules.bigip_asm_policy_fetch bigip_asm_policy_import: redirect: f5networks.f5_modules.bigip_asm_policy_import bigip_asm_policy_manage: redirect: f5networks.f5_modules.bigip_asm_policy_manage bigip_asm_policy_server_technology: redirect: f5networks.f5_modules.bigip_asm_policy_server_technology bigip_asm_policy_signature_set: redirect: f5networks.f5_modules.bigip_asm_policy_signature_set bigip_cli_alias: redirect: f5networks.f5_modules.bigip_cli_alias bigip_cli_script: redirect: f5networks.f5_modules.bigip_cli_script bigip_command: redirect: f5networks.f5_modules.bigip_command bigip_config: redirect: f5networks.f5_modules.bigip_config bigip_configsync_action: redirect: f5networks.f5_modules.bigip_configsync_action bigip_data_group: redirect: f5networks.f5_modules.bigip_data_group bigip_device_auth: redirect: f5networks.f5_modules.bigip_device_auth bigip_device_auth_ldap: redirect: f5networks.f5_modules.bigip_device_auth_ldap bigip_device_certificate: redirect: f5networks.f5_modules.bigip_device_certificate bigip_device_connectivity: redirect: f5networks.f5_modules.bigip_device_connectivity bigip_device_dns: redirect: f5networks.f5_modules.bigip_device_dns bigip_device_group: redirect: f5networks.f5_modules.bigip_device_group bigip_device_group_member: redirect: f5networks.f5_modules.bigip_device_group_member bigip_device_ha_group: redirect: f5networks.f5_modules.bigip_device_ha_group bigip_device_httpd: redirect: f5networks.f5_modules.bigip_device_httpd bigip_device_info: redirect: f5networks.f5_modules.bigip_device_info bigip_device_license: redirect: f5networks.f5_modules.bigip_device_license bigip_device_ntp: redirect: f5networks.f5_modules.bigip_device_ntp bigip_device_sshd: redirect: f5networks.f5_modules.bigip_device_sshd bigip_device_syslog: redirect: f5networks.f5_modules.bigip_device_syslog bigip_device_traffic_group: redirect: f5networks.f5_modules.bigip_device_traffic_group bigip_device_trust: redirect: f5networks.f5_modules.bigip_device_trust bigip_dns_cache_resolver: redirect: f5networks.f5_modules.bigip_dns_cache_resolver bigip_dns_nameserver: redirect: f5networks.f5_modules.bigip_dns_nameserver bigip_dns_resolver: redirect: f5networks.f5_modules.bigip_dns_resolver bigip_dns_zone: redirect: f5networks.f5_modules.bigip_dns_zone bigip_file_copy: redirect: f5networks.f5_modules.bigip_file_copy bigip_firewall_address_list: redirect: f5networks.f5_modules.bigip_firewall_address_list bigip_firewall_dos_profile: redirect: f5networks.f5_modules.bigip_firewall_dos_profile bigip_firewall_dos_vector: redirect: f5networks.f5_modules.bigip_firewall_dos_vector bigip_firewall_global_rules: redirect: f5networks.f5_modules.bigip_firewall_global_rules bigip_firewall_log_profile: redirect: f5networks.f5_modules.bigip_firewall_log_profile bigip_firewall_log_profile_network: redirect: f5networks.f5_modules.bigip_firewall_log_profile_network bigip_firewall_policy: redirect: f5networks.f5_modules.bigip_firewall_policy bigip_firewall_port_list: redirect: f5networks.f5_modules.bigip_firewall_port_list bigip_firewall_rule: redirect: f5networks.f5_modules.bigip_firewall_rule bigip_firewall_rule_list: redirect: f5networks.f5_modules.bigip_firewall_rule_list bigip_firewall_schedule: redirect: f5networks.f5_modules.bigip_firewall_schedule bigip_gtm_datacenter: redirect: f5networks.f5_modules.bigip_gtm_datacenter bigip_gtm_global: redirect: f5networks.f5_modules.bigip_gtm_global bigip_gtm_monitor_bigip: redirect: f5networks.f5_modules.bigip_gtm_monitor_bigip bigip_gtm_monitor_external: redirect: f5networks.f5_modules.bigip_gtm_monitor_external bigip_gtm_monitor_firepass: redirect: f5networks.f5_modules.bigip_gtm_monitor_firepass bigip_gtm_monitor_http: redirect: f5networks.f5_modules.bigip_gtm_monitor_http bigip_gtm_monitor_https: redirect: f5networks.f5_modules.bigip_gtm_monitor_https bigip_gtm_monitor_tcp: redirect: f5networks.f5_modules.bigip_gtm_monitor_tcp bigip_gtm_monitor_tcp_half_open: redirect: f5networks.f5_modules.bigip_gtm_monitor_tcp_half_open bigip_gtm_pool: redirect: f5networks.f5_modules.bigip_gtm_pool bigip_gtm_pool_member: redirect: f5networks.f5_modules.bigip_gtm_pool_member bigip_gtm_server: redirect: f5networks.f5_modules.bigip_gtm_server bigip_gtm_topology_record: redirect: f5networks.f5_modules.bigip_gtm_topology_record bigip_gtm_topology_region: redirect: f5networks.f5_modules.bigip_gtm_topology_region bigip_gtm_virtual_server: redirect: f5networks.f5_modules.bigip_gtm_virtual_server bigip_gtm_wide_ip: redirect: f5networks.f5_modules.bigip_gtm_wide_ip bigip_hostname: redirect: f5networks.f5_modules.bigip_hostname bigip_iapp_service: redirect: f5networks.f5_modules.bigip_iapp_service bigip_iapp_template: redirect: f5networks.f5_modules.bigip_iapp_template bigip_ike_peer: redirect: f5networks.f5_modules.bigip_ike_peer bigip_imish_config: redirect: f5networks.f5_modules.bigip_imish_config bigip_ipsec_policy: redirect: f5networks.f5_modules.bigip_ipsec_policy bigip_irule: redirect: f5networks.f5_modules.bigip_irule bigip_log_destination: redirect: f5networks.f5_modules.bigip_log_destination bigip_log_publisher: redirect: f5networks.f5_modules.bigip_log_publisher bigip_lx_package: redirect: f5networks.f5_modules.bigip_lx_package bigip_management_route: redirect: f5networks.f5_modules.bigip_management_route bigip_message_routing_peer: redirect: f5networks.f5_modules.bigip_message_routing_peer bigip_message_routing_protocol: redirect: f5networks.f5_modules.bigip_message_routing_protocol bigip_message_routing_route: redirect: f5networks.f5_modules.bigip_message_routing_route bigip_message_routing_router: redirect: f5networks.f5_modules.bigip_message_routing_router bigip_message_routing_transport_config: redirect: f5networks.f5_modules.bigip_message_routing_transport_config bigip_monitor_dns: redirect: f5networks.f5_modules.bigip_monitor_dns bigip_monitor_external: redirect: f5networks.f5_modules.bigip_monitor_external bigip_monitor_gateway_icmp: redirect: f5networks.f5_modules.bigip_monitor_gateway_icmp bigip_monitor_http: redirect: f5networks.f5_modules.bigip_monitor_http bigip_monitor_https: redirect: f5networks.f5_modules.bigip_monitor_https bigip_monitor_ldap: redirect: f5networks.f5_modules.bigip_monitor_ldap bigip_monitor_snmp_dca: redirect: f5networks.f5_modules.bigip_monitor_snmp_dca bigip_monitor_tcp: redirect: f5networks.f5_modules.bigip_monitor_tcp bigip_monitor_tcp_echo: redirect: f5networks.f5_modules.bigip_monitor_tcp_echo bigip_monitor_tcp_half_open: redirect: f5networks.f5_modules.bigip_monitor_tcp_half_open bigip_monitor_udp: redirect: f5networks.f5_modules.bigip_monitor_udp bigip_node: redirect: f5networks.f5_modules.bigip_node bigip_partition: redirect: f5networks.f5_modules.bigip_partition bigip_password_policy: redirect: f5networks.f5_modules.bigip_password_policy bigip_policy: redirect: f5networks.f5_modules.bigip_policy bigip_policy_rule: redirect: f5networks.f5_modules.bigip_policy_rule bigip_pool: redirect: f5networks.f5_modules.bigip_pool bigip_pool_member: redirect: f5networks.f5_modules.bigip_pool_member bigip_profile_analytics: redirect: f5networks.f5_modules.bigip_profile_analytics bigip_profile_client_ssl: redirect: f5networks.f5_modules.bigip_profile_client_ssl bigip_profile_dns: redirect: f5networks.f5_modules.bigip_profile_dns bigip_profile_fastl4: redirect: f5networks.f5_modules.bigip_profile_fastl4 bigip_profile_http: redirect: f5networks.f5_modules.bigip_profile_http bigip_profile_http2: redirect: f5networks.f5_modules.bigip_profile_http2 bigip_profile_http_compression: redirect: f5networks.f5_modules.bigip_profile_http_compression bigip_profile_oneconnect: redirect: f5networks.f5_modules.bigip_profile_oneconnect bigip_profile_persistence_cookie: redirect: f5networks.f5_modules.bigip_profile_persistence_cookie bigip_profile_persistence_src_addr: redirect: f5networks.f5_modules.bigip_profile_persistence_src_addr bigip_profile_server_ssl: redirect: f5networks.f5_modules.bigip_profile_server_ssl bigip_profile_tcp: redirect: f5networks.f5_modules.bigip_profile_tcp bigip_profile_udp: redirect: f5networks.f5_modules.bigip_profile_udp bigip_provision: redirect: f5networks.f5_modules.bigip_provision bigip_qkview: redirect: f5networks.f5_modules.bigip_qkview bigip_remote_role: redirect: f5networks.f5_modules.bigip_remote_role bigip_remote_syslog: redirect: f5networks.f5_modules.bigip_remote_syslog bigip_remote_user: redirect: f5networks.f5_modules.bigip_remote_user bigip_routedomain: redirect: f5networks.f5_modules.bigip_routedomain bigip_selfip: redirect: f5networks.f5_modules.bigip_selfip bigip_service_policy: redirect: f5networks.f5_modules.bigip_service_policy bigip_smtp: redirect: f5networks.f5_modules.bigip_smtp bigip_snat_pool: redirect: f5networks.f5_modules.bigip_snat_pool bigip_snat_translation: redirect: f5networks.f5_modules.bigip_snat_translation bigip_snmp: redirect: f5networks.f5_modules.bigip_snmp bigip_snmp_community: redirect: f5networks.f5_modules.bigip_snmp_community bigip_snmp_trap: redirect: f5networks.f5_modules.bigip_snmp_trap bigip_software_image: redirect: f5networks.f5_modules.bigip_software_image bigip_software_install: redirect: f5networks.f5_modules.bigip_software_install bigip_software_update: redirect: f5networks.f5_modules.bigip_software_update bigip_ssl_certificate: redirect: f5networks.f5_modules.bigip_ssl_certificate bigip_ssl_key: redirect: f5networks.f5_modules.bigip_ssl_key bigip_ssl_ocsp: redirect: f5networks.f5_modules.bigip_ssl_ocsp bigip_static_route: redirect: f5networks.f5_modules.bigip_static_route bigip_sys_daemon_log_tmm: redirect: f5networks.f5_modules.bigip_sys_daemon_log_tmm bigip_sys_db: redirect: f5networks.f5_modules.bigip_sys_db bigip_sys_global: redirect: f5networks.f5_modules.bigip_sys_global bigip_timer_policy: redirect: f5networks.f5_modules.bigip_timer_policy bigip_traffic_selector: redirect: f5networks.f5_modules.bigip_traffic_selector bigip_trunk: redirect: f5networks.f5_modules.bigip_trunk bigip_tunnel: redirect: f5networks.f5_modules.bigip_tunnel bigip_ucs: redirect: f5networks.f5_modules.bigip_ucs bigip_ucs_fetch: redirect: f5networks.f5_modules.bigip_ucs_fetch bigip_user: redirect: f5networks.f5_modules.bigip_user bigip_vcmp_guest: redirect: f5networks.f5_modules.bigip_vcmp_guest bigip_virtual_address: redirect: f5networks.f5_modules.bigip_virtual_address bigip_virtual_server: redirect: f5networks.f5_modules.bigip_virtual_server bigip_vlan: redirect: f5networks.f5_modules.bigip_vlan bigip_wait: redirect: f5networks.f5_modules.bigip_wait bigiq_application_fasthttp: redirect: f5networks.f5_modules.bigiq_application_fasthttp bigiq_application_fastl4_tcp: redirect: f5networks.f5_modules.bigiq_application_fastl4_tcp bigiq_application_fastl4_udp: redirect: f5networks.f5_modules.bigiq_application_fastl4_udp bigiq_application_http: redirect: f5networks.f5_modules.bigiq_application_http bigiq_application_https_offload: redirect: f5networks.f5_modules.bigiq_application_https_offload bigiq_application_https_waf: redirect: f5networks.f5_modules.bigiq_application_https_waf bigiq_device_discovery: redirect: f5networks.f5_modules.bigiq_device_discovery bigiq_device_info: redirect: f5networks.f5_modules.bigiq_device_info bigiq_regkey_license: redirect: f5networks.f5_modules.bigiq_regkey_license bigiq_regkey_license_assignment: redirect: f5networks.f5_modules.bigiq_regkey_license_assignment bigiq_regkey_pool: redirect: f5networks.f5_modules.bigiq_regkey_pool bigiq_utility_license: redirect: f5networks.f5_modules.bigiq_utility_license bigiq_utility_license_assignment: redirect: f5networks.f5_modules.bigiq_utility_license_assignment os_auth: redirect: openstack.cloud.auth os_client_config: redirect: openstack.cloud.config os_coe_cluster: redirect: openstack.cloud.coe_cluster os_coe_cluster_template: redirect: openstack.cloud.coe_cluster_template os_flavor_info: redirect: openstack.cloud.compute_flavor_info os_floating_ip: redirect: openstack.cloud.floating_ip os_group: redirect: openstack.cloud.identity_group os_group_info: redirect: openstack.cloud.identity_group_info os_image: redirect: openstack.cloud.image os_image_info: redirect: openstack.cloud.image_info os_ironic: redirect: openstack.cloud.baremetal_node os_ironic_inspect: redirect: openstack.cloud.baremetal_inspect os_ironic_node: redirect: openstack.cloud.baremetal_node_action os_keypair: redirect: openstack.cloud.keypair os_keystone_domain: redirect: openstack.cloud.identity_domain os_keystone_domain_info: redirect: openstack.cloud.identity_domain_info os_keystone_endpoint: redirect: openstack.cloud.endpoint os_keystone_role: redirect: openstack.cloud.identity_role os_keystone_service: redirect: openstack.cloud.catalog_service os_listener: redirect: openstack.cloud.lb_listener os_loadbalancer: redirect: openstack.cloud.loadbalancer os_member: redirect: openstack.cloud.lb_member os_network: redirect: openstack.cloud.network os_networks_info: redirect: openstack.cloud.networks_info os_nova_flavor: redirect: openstack.cloud.compute_flavor os_nova_host_aggregate: redirect: openstack.cloud.host_aggregate os_object: redirect: openstack.cloud.object os_pool: redirect: openstack.cloud.lb_pool os_port: redirect: openstack.cloud.port os_port_info: redirect: openstack.cloud.port_info os_project: redirect: openstack.cloud.project os_project_access: redirect: openstack.cloud.project_access os_project_info: redirect: openstack.cloud.project_info os_quota: redirect: openstack.cloud.quota os_recordset: redirect: openstack.cloud.recordset os_router: redirect: openstack.cloud.router os_security_group: redirect: openstack.cloud.security_group os_security_group_rule: redirect: openstack.cloud.security_group_rule os_server: redirect: openstack.cloud.server os_server_action: redirect: openstack.cloud.server_action os_server_group: redirect: openstack.cloud.server_group os_server_info: redirect: openstack.cloud.server_info os_server_metadata: redirect: openstack.cloud.server_metadata os_server_volume: redirect: openstack.cloud.server_volume os_stack: redirect: openstack.cloud.stack os_subnet: redirect: openstack.cloud.subnet os_subnets_info: redirect: openstack.cloud.subnets_info os_user: redirect: openstack.cloud.identity_user os_user_group: redirect: openstack.cloud.group_assignment os_user_info: redirect: openstack.cloud.identity_user_info os_user_role: redirect: openstack.cloud.role_assignment os_volume: redirect: openstack.cloud.volume os_volume_snapshot: redirect: openstack.cloud.volume_snapshot os_zone: redirect: openstack.cloud.dns_zone junos_acls: redirect: junipernetworks.junos.junos_acls junos_acl_interfaces: redirect: junipernetworks.junos.junos_acl_interfaces junos_ospfv2: redirect: junipernetworks.junos.junos_ospfv2 junos_user: redirect: junipernetworks.junos.junos_user junos_l2_interface: redirect: junipernetworks.junos.junos_l2_interface junos_lldp: redirect: junipernetworks.junos.junos_lldp junos_rpc: redirect: junipernetworks.junos.junos_rpc junos_l2_interfaces: redirect: junipernetworks.junos.junos_l2_interfaces junos_lldp_interface: redirect: junipernetworks.junos.junos_lldp_interface junos_static_route: redirect: junipernetworks.junos.junos_static_route junos_lacp: redirect: junipernetworks.junos.junos_lacp junos_lacp_interfaces: redirect: junipernetworks.junos.junos_lacp_interfaces junos_vlans: redirect: junipernetworks.junos.junos_vlans junos_linkagg: redirect: junipernetworks.junos.junos_linkagg junos_scp: redirect: junipernetworks.junos.junos_scp junos_banner: redirect: junipernetworks.junos.junos_banner junos_l3_interface: redirect: junipernetworks.junos.junos_l3_interface junos_logging: redirect: junipernetworks.junos.junos_logging junos_package: redirect: junipernetworks.junos.junos_package junos_netconf: redirect: junipernetworks.junos.junos_netconf junos_facts: redirect: junipernetworks.junos.junos_facts junos_ping: redirect: junipernetworks.junos.junos_ping junos_interface: redirect: junipernetworks.junos.junos_interface junos_lldp_global: redirect: junipernetworks.junos.junos_lldp_global junos_config: redirect: junipernetworks.junos.junos_config junos_static_routes: redirect: junipernetworks.junos.junos_static_routes junos_command: redirect: junipernetworks.junos.junos_command junos_lag_interfaces: redirect: junipernetworks.junos.junos_lag_interfaces junos_l3_interfaces: redirect: junipernetworks.junos.junos_l3_interfaces junos_lldp_interfaces: redirect: junipernetworks.junos.junos_lldp_interfaces junos_vlan: redirect: junipernetworks.junos.junos_vlan junos_system: redirect: junipernetworks.junos.junos_system junos_interfaces: redirect: junipernetworks.junos.junos_interfaces junos_vrf: redirect: junipernetworks.junos.junos_vrf tower_credential: redirect: awx.awx.tower_credential tower_credential_type: redirect: awx.awx.tower_credential_type tower_group: redirect: awx.awx.tower_group tower_host: redirect: awx.awx.tower_host tower_inventory: redirect: awx.awx.tower_inventory tower_inventory_source: redirect: awx.awx.tower_inventory_source tower_job_cancel: redirect: awx.awx.tower_job_cancel tower_job_launch: redirect: awx.awx.tower_job_launch tower_job_list: redirect: awx.awx.tower_job_list tower_job_template: redirect: awx.awx.tower_job_template tower_job_wait: redirect: awx.awx.tower_job_wait tower_label: redirect: awx.awx.tower_label tower_notification: redirect: awx.awx.tower_notification tower_organization: redirect: awx.awx.tower_organization tower_project: redirect: awx.awx.tower_project tower_receive: redirect: awx.awx.tower_receive tower_role: redirect: awx.awx.tower_role tower_send: redirect: awx.awx.tower_send tower_settings: redirect: awx.awx.tower_settings tower_team: redirect: awx.awx.tower_team tower_user: redirect: awx.awx.tower_user tower_workflow_launch: redirect: awx.awx.tower_workflow_launch tower_workflow_template: redirect: awx.awx.tower_workflow_template ovirt_affinity_group: redirect: ovirt.ovirt.ovirt_affinity_group ovirt_affinity_label: redirect: ovirt.ovirt.ovirt_affinity_label ovirt_affinity_label_info: redirect: ovirt.ovirt.ovirt_affinity_label_info ovirt_api_info: redirect: ovirt.ovirt.ovirt_api_info ovirt_auth: redirect: ovirt.ovirt.ovirt_auth ovirt_cluster: redirect: ovirt.ovirt.ovirt_cluster ovirt_cluster_info: redirect: ovirt.ovirt.ovirt_cluster_info ovirt_datacenter: redirect: ovirt.ovirt.ovirt_datacenter ovirt_datacenter_info: redirect: ovirt.ovirt.ovirt_datacenter_info ovirt_disk: redirect: ovirt.ovirt.ovirt_disk ovirt_disk_info: redirect: ovirt.ovirt.ovirt_disk_info ovirt_event: redirect: ovirt.ovirt.ovirt_event ovirt_event_info: redirect: ovirt.ovirt.ovirt_event_info ovirt_external_provider: redirect: ovirt.ovirt.ovirt_external_provider ovirt_external_provider_info: redirect: ovirt.ovirt.ovirt_external_provider_info ovirt_group: redirect: ovirt.ovirt.ovirt_group ovirt_group_info: redirect: ovirt.ovirt.ovirt_group_info ovirt_host: redirect: ovirt.ovirt.ovirt_host ovirt_host_info: redirect: ovirt.ovirt.ovirt_host_info ovirt_host_network: redirect: ovirt.ovirt.ovirt_host_network ovirt_host_pm: redirect: ovirt.ovirt.ovirt_host_pm ovirt_host_storage_info: redirect: ovirt.ovirt.ovirt_host_storage_info ovirt_instance_type: redirect: ovirt.ovirt.ovirt_instance_type ovirt_job: redirect: ovirt.ovirt.ovirt_job ovirt_mac_pool: redirect: ovirt.ovirt.ovirt_mac_pool ovirt_network: redirect: ovirt.ovirt.ovirt_network ovirt_network_info: redirect: ovirt.ovirt.ovirt_network_info ovirt_nic: redirect: ovirt.ovirt.ovirt_nic ovirt_nic_info: redirect: ovirt.ovirt.ovirt_nic_info ovirt_permission: redirect: ovirt.ovirt.ovirt_permission ovirt_permission_info: redirect: ovirt.ovirt.ovirt_permission_info ovirt_quota: redirect: ovirt.ovirt.ovirt_quota ovirt_quota_info: redirect: ovirt.ovirt.ovirt_quota_info ovirt_role: redirect: ovirt.ovirt.ovirt_role ovirt_scheduling_policy_info: redirect: ovirt.ovirt.ovirt_scheduling_policy_info ovirt_snapshot: redirect: ovirt.ovirt.ovirt_snapshot ovirt_snapshot_info: redirect: ovirt.ovirt.ovirt_snapshot_info ovirt_storage_connection: redirect: ovirt.ovirt.ovirt_storage_connection ovirt_storage_domain: redirect: ovirt.ovirt.ovirt_storage_domain ovirt_storage_domain_info: redirect: ovirt.ovirt.ovirt_storage_domain_info ovirt_storage_template_info: redirect: ovirt.ovirt.ovirt_storage_template_info ovirt_storage_vm_info: redirect: ovirt.ovirt.ovirt_storage_vm_info ovirt_tag: redirect: ovirt.ovirt.ovirt_tag ovirt_tag_info: redirect: ovirt.ovirt.ovirt_tag_info ovirt_template: redirect: ovirt.ovirt.ovirt_template ovirt_template_info: redirect: ovirt.ovirt.ovirt_template_info ovirt_user: redirect: ovirt.ovirt.ovirt_user ovirt_user_info: redirect: ovirt.ovirt.ovirt_user_info ovirt_vm: redirect: ovirt.ovirt.ovirt_vm ovirt_vm_info: redirect: ovirt.ovirt.ovirt_vm_info ovirt_vmpool: redirect: ovirt.ovirt.ovirt_vmpool ovirt_vmpool_info: redirect: ovirt.ovirt.ovirt_vmpool_info ovirt_vnic_profile: redirect: ovirt.ovirt.ovirt_vnic_profile ovirt_vnic_profile_info: redirect: ovirt.ovirt.ovirt_vnic_profile_info dellos10_command: redirect: dellemc.os10.os10_command dellos10_facts: redirect: dellemc.os10.os10_facts dellos10_config: redirect: dellemc.os10.os10_config dellos9_facts: redirect: dellemc.os9.os9_facts dellos9_command: redirect: dellemc.os9.os9_command dellos9_config: redirect: dellemc.os9.os9_config dellos6_facts: redirect: dellemc.os6.os6_facts dellos6_config: redirect: dellemc.os6.os6_config dellos6_command: redirect: dellemc.os6.os6_command hcloud_location_facts: redirect: hetzner.hcloud.hcloud_location_facts hcloud_server_info: redirect: hetzner.hcloud.hcloud_server_info hcloud_server_network: redirect: hetzner.hcloud.hcloud_server_network hcloud_server_type_info: redirect: hetzner.hcloud.hcloud_server_type_info hcloud_route: redirect: hetzner.hcloud.hcloud_route hcloud_server: redirect: hetzner.hcloud.hcloud_server hcloud_volume_info: redirect: hetzner.hcloud.hcloud_volume_info hcloud_server_type_facts: redirect: hetzner.hcloud.hcloud_server_type_facts hcloud_ssh_key_info: redirect: hetzner.hcloud.hcloud_ssh_key_info hcloud_network_info: redirect: hetzner.hcloud.hcloud_network_info hcloud_datacenter_info: redirect: hetzner.hcloud.hcloud_datacenter_info hcloud_image_facts: redirect: hetzner.hcloud.hcloud_image_facts hcloud_volume_facts: redirect: hetzner.hcloud.hcloud_volume_facts hcloud_floating_ip_info: redirect: hetzner.hcloud.hcloud_floating_ip_info hcloud_floating_ip_facts: redirect: hetzner.hcloud.hcloud_floating_ip_facts hcloud_image_info: redirect: hetzner.hcloud.hcloud_image_info hcloud_ssh_key_facts: redirect: hetzner.hcloud.hcloud_ssh_key_facts hcloud_location_info: redirect: hetzner.hcloud.hcloud_location_info hcloud_network: redirect: hetzner.hcloud.hcloud_network hcloud_volume: redirect: hetzner.hcloud.hcloud_volume hcloud_ssh_key: redirect: hetzner.hcloud.hcloud_ssh_key hcloud_datacenter_facts: redirect: hetzner.hcloud.hcloud_datacenter_facts hcloud_rdns: redirect: hetzner.hcloud.hcloud_rdns hcloud_floating_ip: redirect: hetzner.hcloud.hcloud_floating_ip hcloud_server_facts: redirect: hetzner.hcloud.hcloud_server_facts hcloud_subnetwork: redirect: hetzner.hcloud.hcloud_subnetwork skydive_capture: redirect: community.skydive.skydive_capture skydive_edge: redirect: community.skydive.skydive_edge skydive_node: redirect: community.skydive.skydive_node cyberark_authentication: redirect: cyberark.pas.cyberark_authentication cyberark_user: redirect: cyberark.pas.cyberark_user gcp_appengine_firewall_rule: redirect: google.cloud.gcp_appengine_firewall_rule gcp_appengine_firewall_rule_info: redirect: google.cloud.gcp_appengine_firewall_rule_info gcp_bigquery_dataset: redirect: google.cloud.gcp_bigquery_dataset gcp_bigquery_dataset_info: redirect: google.cloud.gcp_bigquery_dataset_info gcp_bigquery_table: redirect: google.cloud.gcp_bigquery_table gcp_bigquery_table_info: redirect: google.cloud.gcp_bigquery_table_info gcp_cloudbuild_trigger: redirect: google.cloud.gcp_cloudbuild_trigger gcp_cloudbuild_trigger_info: redirect: google.cloud.gcp_cloudbuild_trigger_info gcp_cloudfunctions_cloud_function: redirect: google.cloud.gcp_cloudfunctions_cloud_function gcp_cloudfunctions_cloud_function_info: redirect: google.cloud.gcp_cloudfunctions_cloud_function_info gcp_cloudscheduler_job: redirect: google.cloud.gcp_cloudscheduler_job gcp_cloudscheduler_job_info: redirect: google.cloud.gcp_cloudscheduler_job_info gcp_cloudtasks_queue: redirect: google.cloud.gcp_cloudtasks_queue gcp_cloudtasks_queue_info: redirect: google.cloud.gcp_cloudtasks_queue_info gcp_compute_address: redirect: google.cloud.gcp_compute_address gcp_compute_address_info: redirect: google.cloud.gcp_compute_address_info gcp_compute_autoscaler: redirect: google.cloud.gcp_compute_autoscaler gcp_compute_autoscaler_info: redirect: google.cloud.gcp_compute_autoscaler_info gcp_compute_backend_bucket: redirect: google.cloud.gcp_compute_backend_bucket gcp_compute_backend_bucket_info: redirect: google.cloud.gcp_compute_backend_bucket_info gcp_compute_backend_service: redirect: google.cloud.gcp_compute_backend_service gcp_compute_backend_service_info: redirect: google.cloud.gcp_compute_backend_service_info gcp_compute_disk: redirect: google.cloud.gcp_compute_disk gcp_compute_disk_info: redirect: google.cloud.gcp_compute_disk_info gcp_compute_firewall: redirect: google.cloud.gcp_compute_firewall gcp_compute_firewall_info: redirect: google.cloud.gcp_compute_firewall_info gcp_compute_forwarding_rule: redirect: google.cloud.gcp_compute_forwarding_rule gcp_compute_forwarding_rule_info: redirect: google.cloud.gcp_compute_forwarding_rule_info gcp_compute_global_address: redirect: google.cloud.gcp_compute_global_address gcp_compute_global_address_info: redirect: google.cloud.gcp_compute_global_address_info gcp_compute_global_forwarding_rule: redirect: google.cloud.gcp_compute_global_forwarding_rule gcp_compute_global_forwarding_rule_info: redirect: google.cloud.gcp_compute_global_forwarding_rule_info gcp_compute_health_check: redirect: google.cloud.gcp_compute_health_check gcp_compute_health_check_info: redirect: google.cloud.gcp_compute_health_check_info gcp_compute_http_health_check: redirect: google.cloud.gcp_compute_http_health_check gcp_compute_http_health_check_info: redirect: google.cloud.gcp_compute_http_health_check_info gcp_compute_https_health_check: redirect: google.cloud.gcp_compute_https_health_check gcp_compute_https_health_check_info: redirect: google.cloud.gcp_compute_https_health_check_info gcp_compute_image: redirect: google.cloud.gcp_compute_image gcp_compute_image_info: redirect: google.cloud.gcp_compute_image_info gcp_compute_instance: redirect: google.cloud.gcp_compute_instance gcp_compute_instance_group: redirect: google.cloud.gcp_compute_instance_group gcp_compute_instance_group_info: redirect: google.cloud.gcp_compute_instance_group_info gcp_compute_instance_group_manager: redirect: google.cloud.gcp_compute_instance_group_manager gcp_compute_instance_group_manager_info: redirect: google.cloud.gcp_compute_instance_group_manager_info gcp_compute_instance_info: redirect: google.cloud.gcp_compute_instance_info gcp_compute_instance_template: redirect: google.cloud.gcp_compute_instance_template gcp_compute_instance_template_info: redirect: google.cloud.gcp_compute_instance_template_info gcp_compute_interconnect_attachment: redirect: google.cloud.gcp_compute_interconnect_attachment gcp_compute_interconnect_attachment_info: redirect: google.cloud.gcp_compute_interconnect_attachment_info gcp_compute_network: redirect: google.cloud.gcp_compute_network gcp_compute_network_endpoint_group: redirect: google.cloud.gcp_compute_network_endpoint_group gcp_compute_network_endpoint_group_info: redirect: google.cloud.gcp_compute_network_endpoint_group_info gcp_compute_network_info: redirect: google.cloud.gcp_compute_network_info gcp_compute_node_group: redirect: google.cloud.gcp_compute_node_group gcp_compute_node_group_info: redirect: google.cloud.gcp_compute_node_group_info gcp_compute_node_template: redirect: google.cloud.gcp_compute_node_template gcp_compute_node_template_info: redirect: google.cloud.gcp_compute_node_template_info gcp_compute_region_backend_service: redirect: google.cloud.gcp_compute_region_backend_service gcp_compute_region_backend_service_info: redirect: google.cloud.gcp_compute_region_backend_service_info gcp_compute_region_disk: redirect: google.cloud.gcp_compute_region_disk gcp_compute_region_disk_info: redirect: google.cloud.gcp_compute_region_disk_info gcp_compute_reservation: redirect: google.cloud.gcp_compute_reservation gcp_compute_reservation_info: redirect: google.cloud.gcp_compute_reservation_info gcp_compute_route: redirect: google.cloud.gcp_compute_route gcp_compute_route_info: redirect: google.cloud.gcp_compute_route_info gcp_compute_router: redirect: google.cloud.gcp_compute_router gcp_compute_router_info: redirect: google.cloud.gcp_compute_router_info gcp_compute_snapshot: redirect: google.cloud.gcp_compute_snapshot gcp_compute_snapshot_info: redirect: google.cloud.gcp_compute_snapshot_info gcp_compute_ssl_certificate: redirect: google.cloud.gcp_compute_ssl_certificate gcp_compute_ssl_certificate_info: redirect: google.cloud.gcp_compute_ssl_certificate_info gcp_compute_ssl_policy: redirect: google.cloud.gcp_compute_ssl_policy gcp_compute_ssl_policy_info: redirect: google.cloud.gcp_compute_ssl_policy_info gcp_compute_subnetwork: redirect: google.cloud.gcp_compute_subnetwork gcp_compute_subnetwork_info: redirect: google.cloud.gcp_compute_subnetwork_info gcp_compute_target_http_proxy: redirect: google.cloud.gcp_compute_target_http_proxy gcp_compute_target_http_proxy_info: redirect: google.cloud.gcp_compute_target_http_proxy_info gcp_compute_target_https_proxy: redirect: google.cloud.gcp_compute_target_https_proxy gcp_compute_target_https_proxy_info: redirect: google.cloud.gcp_compute_target_https_proxy_info gcp_compute_target_instance: redirect: google.cloud.gcp_compute_target_instance gcp_compute_target_instance_info: redirect: google.cloud.gcp_compute_target_instance_info gcp_compute_target_pool: redirect: google.cloud.gcp_compute_target_pool gcp_compute_target_pool_info: redirect: google.cloud.gcp_compute_target_pool_info gcp_compute_target_ssl_proxy: redirect: google.cloud.gcp_compute_target_ssl_proxy gcp_compute_target_ssl_proxy_info: redirect: google.cloud.gcp_compute_target_ssl_proxy_info gcp_compute_target_tcp_proxy: redirect: google.cloud.gcp_compute_target_tcp_proxy gcp_compute_target_tcp_proxy_info: redirect: google.cloud.gcp_compute_target_tcp_proxy_info gcp_compute_target_vpn_gateway: redirect: google.cloud.gcp_compute_target_vpn_gateway gcp_compute_target_vpn_gateway_info: redirect: google.cloud.gcp_compute_target_vpn_gateway_info gcp_compute_url_map: redirect: google.cloud.gcp_compute_url_map gcp_compute_url_map_info: redirect: google.cloud.gcp_compute_url_map_info gcp_compute_vpn_tunnel: redirect: google.cloud.gcp_compute_vpn_tunnel gcp_compute_vpn_tunnel_info: redirect: google.cloud.gcp_compute_vpn_tunnel_info gcp_container_cluster: redirect: google.cloud.gcp_container_cluster gcp_container_cluster_info: redirect: google.cloud.gcp_container_cluster_info gcp_container_node_pool: redirect: google.cloud.gcp_container_node_pool gcp_container_node_pool_info: redirect: google.cloud.gcp_container_node_pool_info gcp_dns_managed_zone: redirect: google.cloud.gcp_dns_managed_zone gcp_dns_managed_zone_info: redirect: google.cloud.gcp_dns_managed_zone_info gcp_dns_resource_record_set: redirect: google.cloud.gcp_dns_resource_record_set gcp_dns_resource_record_set_info: redirect: google.cloud.gcp_dns_resource_record_set_info gcp_filestore_instance: redirect: google.cloud.gcp_filestore_instance gcp_filestore_instance_info: redirect: google.cloud.gcp_filestore_instance_info gcp_iam_role: redirect: google.cloud.gcp_iam_role gcp_iam_role_info: redirect: google.cloud.gcp_iam_role_info gcp_iam_service_account: redirect: google.cloud.gcp_iam_service_account gcp_iam_service_account_info: redirect: google.cloud.gcp_iam_service_account_info gcp_iam_service_account_key: redirect: google.cloud.gcp_iam_service_account_key gcp_kms_crypto_key: redirect: google.cloud.gcp_kms_crypto_key gcp_kms_crypto_key_info: redirect: google.cloud.gcp_kms_crypto_key_info gcp_kms_key_ring: redirect: google.cloud.gcp_kms_key_ring gcp_kms_key_ring_info: redirect: google.cloud.gcp_kms_key_ring_info gcp_logging_metric: redirect: google.cloud.gcp_logging_metric gcp_logging_metric_info: redirect: google.cloud.gcp_logging_metric_info gcp_mlengine_model: redirect: google.cloud.gcp_mlengine_model gcp_mlengine_model_info: redirect: google.cloud.gcp_mlengine_model_info gcp_mlengine_version: redirect: google.cloud.gcp_mlengine_version gcp_mlengine_version_info: redirect: google.cloud.gcp_mlengine_version_info gcp_pubsub_subscription: redirect: google.cloud.gcp_pubsub_subscription gcp_pubsub_subscription_info: redirect: google.cloud.gcp_pubsub_subscription_info gcp_pubsub_topic: redirect: google.cloud.gcp_pubsub_topic gcp_pubsub_topic_info: redirect: google.cloud.gcp_pubsub_topic_info gcp_redis_instance: redirect: google.cloud.gcp_redis_instance gcp_redis_instance_info: redirect: google.cloud.gcp_redis_instance_info gcp_resourcemanager_project: redirect: google.cloud.gcp_resourcemanager_project gcp_resourcemanager_project_info: redirect: google.cloud.gcp_resourcemanager_project_info gcp_runtimeconfig_config: redirect: google.cloud.gcp_runtimeconfig_config gcp_runtimeconfig_config_info: redirect: google.cloud.gcp_runtimeconfig_config_info gcp_runtimeconfig_variable: redirect: google.cloud.gcp_runtimeconfig_variable gcp_runtimeconfig_variable_info: redirect: google.cloud.gcp_runtimeconfig_variable_info gcp_serviceusage_service: redirect: google.cloud.gcp_serviceusage_service gcp_serviceusage_service_info: redirect: google.cloud.gcp_serviceusage_service_info gcp_sourcerepo_repository: redirect: google.cloud.gcp_sourcerepo_repository gcp_sourcerepo_repository_info: redirect: google.cloud.gcp_sourcerepo_repository_info gcp_spanner_database: redirect: google.cloud.gcp_spanner_database gcp_spanner_database_info: redirect: google.cloud.gcp_spanner_database_info gcp_spanner_instance: redirect: google.cloud.gcp_spanner_instance gcp_spanner_instance_info: redirect: google.cloud.gcp_spanner_instance_info gcp_sql_database: redirect: google.cloud.gcp_sql_database gcp_sql_database_info: redirect: google.cloud.gcp_sql_database_info gcp_sql_instance: redirect: google.cloud.gcp_sql_instance gcp_sql_instance_info: redirect: google.cloud.gcp_sql_instance_info gcp_sql_user: redirect: google.cloud.gcp_sql_user gcp_sql_user_info: redirect: google.cloud.gcp_sql_user_info gcp_storage_bucket: redirect: google.cloud.gcp_storage_bucket gcp_storage_bucket_access_control: redirect: google.cloud.gcp_storage_bucket_access_control gcp_storage_object: redirect: google.cloud.gcp_storage_object gcp_tpu_node: redirect: google.cloud.gcp_tpu_node gcp_tpu_node_info: redirect: google.cloud.gcp_tpu_node_info purefa_alert: redirect: purestorage.flasharray.purefa_alert purefa_arrayname: redirect: purestorage.flasharray.purefa_arrayname purefa_banner: redirect: purestorage.flasharray.purefa_banner purefa_connect: redirect: purestorage.flasharray.purefa_connect purefa_dns: redirect: purestorage.flasharray.purefa_dns purefa_ds: redirect: purestorage.flasharray.purefa_ds purefa_dsrole: redirect: purestorage.flasharray.purefa_dsrole purefa_hg: redirect: purestorage.flasharray.purefa_hg purefa_host: redirect: purestorage.flasharray.purefa_host purefa_info: redirect: purestorage.flasharray.purefa_info purefa_ntp: redirect: purestorage.flasharray.purefa_ntp purefa_offload: redirect: purestorage.flasharray.purefa_offload purefa_pg: redirect: purestorage.flasharray.purefa_pg purefa_pgsnap: redirect: purestorage.flasharray.purefa_pgsnap purefa_phonehome: redirect: purestorage.flasharray.purefa_phonehome purefa_ra: redirect: purestorage.flasharray.purefa_ra purefa_smtp: redirect: purestorage.flasharray.purefa_smtp purefa_snap: redirect: purestorage.flasharray.purefa_snap purefa_snmp: redirect: purestorage.flasharray.purefa_snmp purefa_syslog: redirect: purestorage.flasharray.purefa_syslog purefa_user: redirect: purestorage.flasharray.purefa_user purefa_vg: redirect: purestorage.flasharray.purefa_vg purefa_volume: redirect: purestorage.flasharray.purefa_volume purefb_bucket: redirect: purestorage.flashblade.purefb_bucket purefb_ds: redirect: purestorage.flashblade.purefb_ds purefb_dsrole: redirect: purestorage.flashblade.purefb_dsrole purefb_fs: redirect: purestorage.flashblade.purefb_fs purefb_info: redirect: purestorage.flashblade.purefb_info purefb_network: redirect: purestorage.flashblade.purefb_network purefb_ra: redirect: purestorage.flashblade.purefb_ra purefb_s3acc: redirect: purestorage.flashblade.purefb_s3acc purefb_s3user: redirect: purestorage.flashblade.purefb_s3user purefb_smtp: redirect: purestorage.flashblade.purefb_smtp purefb_snap: redirect: purestorage.flashblade.purefb_snap purefb_subnet: redirect: purestorage.flashblade.purefb_subnet azure_rm_acs: redirect: azure.azcollection.azure_rm_acs azure_rm_virtualmachine_info: redirect: azure.azcollection.azure_rm_virtualmachine_info azure_rm_dnsrecordset_info: redirect: azure.azcollection.azure_rm_dnsrecordset_info azure_rm_dnszone_info: redirect: azure.azcollection.azure_rm_dnszone_info azure_rm_networkinterface_info: redirect: azure.azcollection.azure_rm_networkinterface_info azure_rm_publicipaddress_info: redirect: azure.azcollection.azure_rm_publicipaddress_info azure_rm_securitygroup_info: redirect: azure.azcollection.azure_rm_securitygroup_info azure_rm_storageaccount_info: redirect: azure.azcollection.azure_rm_storageaccount_info azure_rm_virtualnetwork_info: redirect: azure.azcollection.azure_rm_virtualnetwork_info azure_rm_deployment: redirect: azure.azcollection.azure_rm_deployment azure_rm_dnsrecordset: redirect: azure.azcollection.azure_rm_dnsrecordset azure_rm_dnszone: redirect: azure.azcollection.azure_rm_dnszone azure_rm_networkinterface: redirect: azure.azcollection.azure_rm_networkinterface azure_rm_publicipaddress: redirect: azure.azcollection.azure_rm_publicipaddress azure_rm_securitygroup: redirect: azure.azcollection.azure_rm_securitygroup azure_rm_storageaccount: redirect: azure.azcollection.azure_rm_storageaccount azure_rm_subnet: redirect: azure.azcollection.azure_rm_subnet azure_rm_virtualmachine: redirect: azure.azcollection.azure_rm_virtualmachine azure_rm_virtualnetwork: redirect: azure.azcollection.azure_rm_virtualnetwork azure_rm_aks: redirect: azure.azcollection.azure_rm_aks azure_rm_aks_info: redirect: azure.azcollection.azure_rm_aks_info azure_rm_aksversion_info: redirect: azure.azcollection.azure_rm_aksversion_info azure_rm_appgateway: redirect: azure.azcollection.azure_rm_appgateway azure_rm_applicationsecuritygroup: redirect: azure.azcollection.azure_rm_applicationsecuritygroup azure_rm_applicationsecuritygroup_info: redirect: azure.azcollection.azure_rm_applicationsecuritygroup_info azure_rm_appserviceplan: redirect: azure.azcollection.azure_rm_appserviceplan azure_rm_appserviceplan_info: redirect: azure.azcollection.azure_rm_appserviceplan_info azure_rm_availabilityset: redirect: azure.azcollection.azure_rm_availabilityset azure_rm_availabilityset_info: redirect: azure.azcollection.azure_rm_availabilityset_info azure_rm_containerinstance: redirect: azure.azcollection.azure_rm_containerinstance azure_rm_containerinstance_info: redirect: azure.azcollection.azure_rm_containerinstance_info azure_rm_containerregistry: redirect: azure.azcollection.azure_rm_containerregistry azure_rm_containerregistry_info: redirect: azure.azcollection.azure_rm_containerregistry_info azure_rm_deployment_info: redirect: azure.azcollection.azure_rm_deployment_info azure_rm_functionapp: redirect: azure.azcollection.azure_rm_functionapp azure_rm_functionapp_info: redirect: azure.azcollection.azure_rm_functionapp_info azure_rm_gallery: redirect: azure.azcollection.azure_rm_gallery azure_rm_gallery_info: redirect: azure.azcollection.azure_rm_gallery_info azure_rm_galleryimage: redirect: azure.azcollection.azure_rm_galleryimage azure_rm_galleryimage_info: redirect: azure.azcollection.azure_rm_galleryimage_info azure_rm_galleryimageversion: redirect: azure.azcollection.azure_rm_galleryimageversion azure_rm_galleryimageversion_info: redirect: azure.azcollection.azure_rm_galleryimageversion_info azure_rm_image: redirect: azure.azcollection.azure_rm_image azure_rm_image_info: redirect: azure.azcollection.azure_rm_image_info azure_rm_keyvault: redirect: azure.azcollection.azure_rm_keyvault azure_rm_keyvault_info: redirect: azure.azcollection.azure_rm_keyvault_info azure_rm_keyvaultkey: redirect: azure.azcollection.azure_rm_keyvaultkey azure_rm_keyvaultkey_info: redirect: azure.azcollection.azure_rm_keyvaultkey_info azure_rm_keyvaultsecret: redirect: azure.azcollection.azure_rm_keyvaultsecret azure_rm_manageddisk: redirect: azure.azcollection.azure_rm_manageddisk azure_rm_manageddisk_info: redirect: azure.azcollection.azure_rm_manageddisk_info azure_rm_resource: redirect: azure.azcollection.azure_rm_resource azure_rm_resource_info: redirect: azure.azcollection.azure_rm_resource_info azure_rm_resourcegroup: redirect: azure.azcollection.azure_rm_resourcegroup azure_rm_resourcegroup_info: redirect: azure.azcollection.azure_rm_resourcegroup_info azure_rm_snapshot: redirect: azure.azcollection.azure_rm_snapshot azure_rm_storageblob: redirect: azure.azcollection.azure_rm_storageblob azure_rm_subnet_info: redirect: azure.azcollection.azure_rm_subnet_info azure_rm_virtualmachineextension: redirect: azure.azcollection.azure_rm_virtualmachineextension azure_rm_virtualmachineextension_info: redirect: azure.azcollection.azure_rm_virtualmachineextension_info azure_rm_virtualmachineimage_info: redirect: azure.azcollection.azure_rm_virtualmachineimage_info azure_rm_virtualmachinescaleset: redirect: azure.azcollection.azure_rm_virtualmachinescaleset azure_rm_virtualmachinescaleset_info: redirect: azure.azcollection.azure_rm_virtualmachinescaleset_info azure_rm_virtualmachinescalesetextension: redirect: azure.azcollection.azure_rm_virtualmachinescalesetextension azure_rm_virtualmachinescalesetextension_info: redirect: azure.azcollection.azure_rm_virtualmachinescalesetextension_info azure_rm_virtualmachinescalesetinstance: redirect: azure.azcollection.azure_rm_virtualmachinescalesetinstance azure_rm_virtualmachinescalesetinstance_info: redirect: azure.azcollection.azure_rm_virtualmachinescalesetinstance_info azure_rm_webapp: redirect: azure.azcollection.azure_rm_webapp azure_rm_webapp_info: redirect: azure.azcollection.azure_rm_webapp_info azure_rm_webappslot: redirect: azure.azcollection.azure_rm_webappslot azure_rm_automationaccount: redirect: azure.azcollection.azure_rm_automationaccount azure_rm_automationaccount_info: redirect: azure.azcollection.azure_rm_automationaccount_info azure_rm_autoscale: redirect: azure.azcollection.azure_rm_autoscale azure_rm_autoscale_info: redirect: azure.azcollection.azure_rm_autoscale_info azure_rm_azurefirewall: redirect: azure.azcollection.azure_rm_azurefirewall azure_rm_azurefirewall_info: redirect: azure.azcollection.azure_rm_azurefirewall_info azure_rm_batchaccount: redirect: azure.azcollection.azure_rm_batchaccount azure_rm_cdnendpoint: redirect: azure.azcollection.azure_rm_cdnendpoint azure_rm_cdnendpoint_info: redirect: azure.azcollection.azure_rm_cdnendpoint_info azure_rm_cdnprofile: redirect: azure.azcollection.azure_rm_cdnprofile azure_rm_cdnprofile_info: redirect: azure.azcollection.azure_rm_cdnprofile_info azure_rm_iotdevice: redirect: azure.azcollection.azure_rm_iotdevice azure_rm_iotdevice_info: redirect: azure.azcollection.azure_rm_iotdevice_info azure_rm_iotdevicemodule: redirect: azure.azcollection.azure_rm_iotdevicemodule azure_rm_iothub: redirect: azure.azcollection.azure_rm_iothub azure_rm_iothub_info: redirect: azure.azcollection.azure_rm_iothub_info azure_rm_iothubconsumergroup: redirect: azure.azcollection.azure_rm_iothubconsumergroup azure_rm_loadbalancer: redirect: azure.azcollection.azure_rm_loadbalancer azure_rm_loadbalancer_info: redirect: azure.azcollection.azure_rm_loadbalancer_info azure_rm_lock: redirect: azure.azcollection.azure_rm_lock azure_rm_lock_info: redirect: azure.azcollection.azure_rm_lock_info azure_rm_loganalyticsworkspace: redirect: azure.azcollection.azure_rm_loganalyticsworkspace azure_rm_loganalyticsworkspace_info: redirect: azure.azcollection.azure_rm_loganalyticsworkspace_info azure_rm_monitorlogprofile: redirect: azure.azcollection.azure_rm_monitorlogprofile azure_rm_rediscache: redirect: azure.azcollection.azure_rm_rediscache azure_rm_rediscache_info: redirect: azure.azcollection.azure_rm_rediscache_info azure_rm_rediscachefirewallrule: redirect: azure.azcollection.azure_rm_rediscachefirewallrule azure_rm_roleassignment: redirect: azure.azcollection.azure_rm_roleassignment azure_rm_roleassignment_info: redirect: azure.azcollection.azure_rm_roleassignment_info azure_rm_roledefinition: redirect: azure.azcollection.azure_rm_roledefinition azure_rm_roledefinition_info: redirect: azure.azcollection.azure_rm_roledefinition_info azure_rm_route: redirect: azure.azcollection.azure_rm_route azure_rm_routetable: redirect: azure.azcollection.azure_rm_routetable azure_rm_routetable_info: redirect: azure.azcollection.azure_rm_routetable_info azure_rm_servicebus: redirect: azure.azcollection.azure_rm_servicebus azure_rm_servicebus_info: redirect: azure.azcollection.azure_rm_servicebus_info azure_rm_servicebusqueue: redirect: azure.azcollection.azure_rm_servicebusqueue azure_rm_servicebussaspolicy: redirect: azure.azcollection.azure_rm_servicebussaspolicy azure_rm_servicebustopic: redirect: azure.azcollection.azure_rm_servicebustopic azure_rm_servicebustopicsubscription: redirect: azure.azcollection.azure_rm_servicebustopicsubscription azure_rm_trafficmanagerendpoint: redirect: azure.azcollection.azure_rm_trafficmanagerendpoint azure_rm_trafficmanagerendpoint_info: redirect: azure.azcollection.azure_rm_trafficmanagerendpoint_info azure_rm_trafficmanagerprofile: redirect: azure.azcollection.azure_rm_trafficmanagerprofile azure_rm_trafficmanagerprofile_info: redirect: azure.azcollection.azure_rm_trafficmanagerprofile_info azure_rm_virtualnetworkgateway: redirect: azure.azcollection.azure_rm_virtualnetworkgateway azure_rm_virtualnetworkpeering: redirect: azure.azcollection.azure_rm_virtualnetworkpeering azure_rm_virtualnetworkpeering_info: redirect: azure.azcollection.azure_rm_virtualnetworkpeering_info azure_rm_cosmosdbaccount: redirect: azure.azcollection.azure_rm_cosmosdbaccount azure_rm_cosmosdbaccount_info: redirect: azure.azcollection.azure_rm_cosmosdbaccount_info azure_rm_devtestlab: redirect: azure.azcollection.azure_rm_devtestlab azure_rm_devtestlab_info: redirect: azure.azcollection.azure_rm_devtestlab_info azure_rm_devtestlabarmtemplate_info: redirect: azure.azcollection.azure_rm_devtestlabarmtemplate_info azure_rm_devtestlabartifact_info: redirect: azure.azcollection.azure_rm_devtestlabartifact_info azure_rm_devtestlabartifactsource: redirect: azure.azcollection.azure_rm_devtestlabartifactsource azure_rm_devtestlabartifactsource_info: redirect: azure.azcollection.azure_rm_devtestlabartifactsource_info azure_rm_devtestlabcustomimage: redirect: azure.azcollection.azure_rm_devtestlabcustomimage azure_rm_devtestlabcustomimage_info: redirect: azure.azcollection.azure_rm_devtestlabcustomimage_info azure_rm_devtestlabenvironment: redirect: azure.azcollection.azure_rm_devtestlabenvironment azure_rm_devtestlabenvironment_info: redirect: azure.azcollection.azure_rm_devtestlabenvironment_info azure_rm_devtestlabpolicy: redirect: azure.azcollection.azure_rm_devtestlabpolicy azure_rm_devtestlabpolicy_info: redirect: azure.azcollection.azure_rm_devtestlabpolicy_info azure_rm_devtestlabschedule: redirect: azure.azcollection.azure_rm_devtestlabschedule azure_rm_devtestlabschedule_info: redirect: azure.azcollection.azure_rm_devtestlabschedule_info azure_rm_devtestlabvirtualmachine: redirect: azure.azcollection.azure_rm_devtestlabvirtualmachine azure_rm_devtestlabvirtualmachine_info: redirect: azure.azcollection.azure_rm_devtestlabvirtualmachine_info azure_rm_devtestlabvirtualnetwork: redirect: azure.azcollection.azure_rm_devtestlabvirtualnetwork azure_rm_devtestlabvirtualnetwork_info: redirect: azure.azcollection.azure_rm_devtestlabvirtualnetwork_info azure_rm_hdinsightcluster: redirect: azure.azcollection.azure_rm_hdinsightcluster azure_rm_hdinsightcluster_info: redirect: azure.azcollection.azure_rm_hdinsightcluster_info azure_rm_mariadbconfiguration: redirect: azure.azcollection.azure_rm_mariadbconfiguration azure_rm_mariadbconfiguration_info: redirect: azure.azcollection.azure_rm_mariadbconfiguration_info azure_rm_mariadbdatabase: redirect: azure.azcollection.azure_rm_mariadbdatabase azure_rm_mariadbdatabase_info: redirect: azure.azcollection.azure_rm_mariadbdatabase_info azure_rm_mariadbfirewallrule: redirect: azure.azcollection.azure_rm_mariadbfirewallrule azure_rm_mariadbfirewallrule_info: redirect: azure.azcollection.azure_rm_mariadbfirewallrule_info azure_rm_mariadbserver: redirect: azure.azcollection.azure_rm_mariadbserver azure_rm_mariadbserver_info: redirect: azure.azcollection.azure_rm_mariadbserver_info azure_rm_mysqlconfiguration: redirect: azure.azcollection.azure_rm_mysqlconfiguration azure_rm_mysqlconfiguration_info: redirect: azure.azcollection.azure_rm_mysqlconfiguration_info azure_rm_mysqldatabase: redirect: azure.azcollection.azure_rm_mysqldatabase azure_rm_mysqldatabase_info: redirect: azure.azcollection.azure_rm_mysqldatabase_info azure_rm_mysqlfirewallrule: redirect: azure.azcollection.azure_rm_mysqlfirewallrule azure_rm_mysqlfirewallrule_info: redirect: azure.azcollection.azure_rm_mysqlfirewallrule_info azure_rm_mysqlserver: redirect: azure.azcollection.azure_rm_mysqlserver azure_rm_mysqlserver_info: redirect: azure.azcollection.azure_rm_mysqlserver_info azure_rm_postgresqlconfiguration: redirect: azure.azcollection.azure_rm_postgresqlconfiguration azure_rm_postgresqlconfiguration_info: redirect: azure.azcollection.azure_rm_postgresqlconfiguration_info azure_rm_postgresqldatabase: redirect: azure.azcollection.azure_rm_postgresqldatabase azure_rm_postgresqldatabase_info: redirect: azure.azcollection.azure_rm_postgresqldatabase_info azure_rm_postgresqlfirewallrule: redirect: azure.azcollection.azure_rm_postgresqlfirewallrule azure_rm_postgresqlfirewallrule_info: redirect: azure.azcollection.azure_rm_postgresqlfirewallrule_info azure_rm_postgresqlserver: redirect: azure.azcollection.azure_rm_postgresqlserver azure_rm_postgresqlserver_info: redirect: azure.azcollection.azure_rm_postgresqlserver_info azure_rm_sqldatabase: redirect: azure.azcollection.azure_rm_sqldatabase azure_rm_sqldatabase_info: redirect: azure.azcollection.azure_rm_sqldatabase_info azure_rm_sqlfirewallrule: redirect: azure.azcollection.azure_rm_sqlfirewallrule azure_rm_sqlfirewallrule_info: redirect: azure.azcollection.azure_rm_sqlfirewallrule_info azure_rm_sqlserver: redirect: azure.azcollection.azure_rm_sqlserver azure_rm_sqlserver_info: redirect: azure.azcollection.azure_rm_sqlserver_info openvswitch_port: redirect: openvswitch.openvswitch.openvswitch_port openvswitch_db: redirect: openvswitch.openvswitch.openvswitch_db openvswitch_bridge: redirect: openvswitch.openvswitch.openvswitch_bridge vyos_ospfv2: redirect: vyos.vyos.vyos_ospfv2 vyos_l3_interface: redirect: vyos.vyos.vyos_l3_interface vyos_banner: redirect: vyos.vyos.vyos_banner vyos_firewall_rules: redirect: vyos.vyos.vyos_firewall_rules vyos_static_route: redirect: vyos.vyos.vyos_static_route vyos_lldp_interface: redirect: vyos.vyos.vyos_lldp_interface vyos_vlan: redirect: vyos.vyos.vyos_vlan vyos_user: redirect: vyos.vyos.vyos_user vyos_firewall_interfaces: redirect: vyos.vyos.vyos_firewall_interfaces vyos_interface: redirect: vyos.vyos.vyos_interface vyos_firewall_global: redirect: vyos.vyos.vyos_firewall_global vyos_config: redirect: vyos.vyos.vyos_config vyos_facts: redirect: vyos.vyos.vyos_facts vyos_linkagg: redirect: vyos.vyos.vyos_linkagg vyos_ping: redirect: vyos.vyos.vyos_ping vyos_lag_interfaces: redirect: vyos.vyos.vyos_lag_interfaces vyos_lldp: redirect: vyos.vyos.vyos_lldp vyos_lldp_global: redirect: vyos.vyos.vyos_lldp_global vyos_l3_interfaces: redirect: vyos.vyos.vyos_l3_interfaces vyos_lldp_interfaces: redirect: vyos.vyos.vyos_lldp_interfaces vyos_interfaces: redirect: vyos.vyos.vyos_interfaces vyos_logging: redirect: vyos.vyos.vyos_logging vyos_static_routes: redirect: vyos.vyos.vyos_static_routes vyos_command: redirect: vyos.vyos.vyos_command vyos_system: redirect: vyos.vyos.vyos_system cpm_plugconfig: redirect: wti.remote.cpm_plugconfig cpm_plugcontrol: redirect: wti.remote.cpm_plugcontrol cpm_serial_port_config: redirect: wti.remote.cpm_serial_port_config cpm_serial_port_info: redirect: wti.remote.cpm_serial_port_info cpm_user: redirect: wti.remote.cpm_user module_utils: # test entries formerly_core: redirect: ansible_collections.testns.testcoll.plugins.module_utils.base sub1.sub2.formerly_core: redirect: ansible_collections.testns.testcoll.plugins.module_utils.base # real acme: redirect: community.crypto.acme alicloud_ecs: redirect: community.general.alicloud_ecs ansible_tower: redirect: awx.awx.ansible_tower aws.batch: redirect: amazon.aws.batch aws.cloudfront_facts: redirect: amazon.aws.cloudfront_facts aws.core: redirect: amazon.aws.core aws.direct_connect: redirect: amazon.aws.direct_connect aws.elb_utils: redirect: amazon.aws.elb_utils aws.elbv2: redirect: amazon.aws.elbv2 aws.iam: redirect: amazon.aws.iam aws.rds: redirect: amazon.aws.rds aws.s3: redirect: amazon.aws.s3 aws.urls: redirect: amazon.aws.urls aws.waf: redirect: amazon.aws.waf aws.waiters: redirect: amazon.aws.waiters azure_rm_common: redirect: azure.azcollection.azure_rm_common azure_rm_common_ext: redirect: azure.azcollection.azure_rm_common_ext azure_rm_common_rest: redirect: azure.azcollection.azure_rm_common_rest cloud: redirect: community.general.cloud cloudscale: redirect: cloudscale_ch.cloud.api cloudstack: redirect: ngine_io.cloudstack.cloudstack compat.ipaddress: redirect: ansible.netcommon.compat.ipaddress crypto: redirect: community.crypto.crypto database: redirect: community.general.database digital_ocean: redirect: community.digitalocean.digital_ocean dimensiondata: redirect: community.general.dimensiondata docker: redirect: community.docker.common docker.common: redirect: community.docker.common docker.swarm: redirect: community.docker.swarm ec2: redirect: amazon.aws.ec2 ecs: redirect: community.crypto.ecs ecs.api: redirect: community.crypto.ecs.api exoscale: redirect: ngine_io.exoscale.exoscale f5_utils: tombstone: removal_date: "2019-11-06" firewalld: redirect: ansible.posix.firewalld gcdns: redirect: community.google.gcdns gce: redirect: community.google.gce gcp: redirect: community.google.gcp gcp_utils: redirect: google.cloud.gcp_utils gitlab: redirect: community.general.gitlab hcloud: redirect: hetzner.hcloud.hcloud heroku: redirect: community.general.heroku hetzner: redirect: community.hrobot.robot hwc_utils: redirect: community.general.hwc_utils ibm_sa_utils: redirect: community.general.ibm_sa_utils identity: redirect: community.general.identity identity.keycloak: redirect: community.general.identity.keycloak identity.keycloak.keycloak: redirect: community.general.identity.keycloak.keycloak infinibox: redirect: infinidat.infinibox.infinibox influxdb: redirect: community.general.influxdb ipa: redirect: community.general.ipa ismount: redirect: ansible.posix.mount k8s.common: redirect: kubernetes.core.common k8s.raw: redirect: kubernetes.core.raw k8s.scale: redirect: kubernetes.core.scale known_hosts: redirect: community.general.known_hosts kubevirt: redirect: community.kubevirt.kubevirt ldap: redirect: community.general.ldap linode: redirect: community.general.linode lxd: redirect: community.general.lxd manageiq: redirect: community.general.manageiq memset: redirect: community.general.memset mysql: redirect: community.mysql.mysql net_tools.netbox.netbox_utils: redirect: netbox.netbox.netbox_utils net_tools.nios: redirect: community.general.net_tools.nios net_tools.nios.api: redirect: community.general.net_tools.nios.api netapp: redirect: netapp.ontap.netapp netapp_elementsw_module: redirect: netapp.ontap.netapp_elementsw_module netapp_module: redirect: netapp.ontap.netapp_module network.a10.a10: redirect: community.network.network.a10.a10 network.aci.aci: redirect: cisco.aci.aci network.aci.mso: redirect: cisco.mso.mso network.aireos.aireos: redirect: community.network.network.aireos.aireos network.aos.aos: redirect: community.network.network.aos.aos network.aruba.aruba: redirect: community.network.network.aruba.aruba network.asa.asa: redirect: cisco.asa.network.asa.asa network.avi.ansible_utils: redirect: community.network.network.avi.ansible_utils network.avi.avi: redirect: community.network.network.avi.avi network.avi.avi_api: redirect: community.network.network.avi.avi_api network.bigswitch.bigswitch: redirect: community.network.network.bigswitch.bigswitch network.checkpoint.checkpoint: redirect: check_point.mgmt.checkpoint network.cloudengine.ce: redirect: community.network.network.cloudengine.ce network.cnos.cnos: redirect: community.network.network.cnos.cnos network.cnos.cnos_devicerules: redirect: community.network.network.cnos.cnos_devicerules network.cnos.cnos_errorcodes: redirect: community.network.network.cnos.cnos_errorcodes network.common.cfg.base: redirect: ansible.netcommon.network.common.cfg.base network.common.config: redirect: ansible.netcommon.network.common.config network.common.facts.facts: redirect: ansible.netcommon.network.common.facts.facts network.common.netconf: redirect: ansible.netcommon.network.common.netconf network.common.network: redirect: ansible.netcommon.network.common.network network.common.parsing: redirect: ansible.netcommon.network.common.parsing network.common.utils: redirect: ansible.netcommon.network.common.utils network.dellos10.dellos10: redirect: dellemc.os10.network.os10 network.dellos9.dellos9: redirect: dellemc.os9.network.os9 network.dellos6.dellos6: redirect: dellemc.os6.network.os6 network.edgeos.edgeos: redirect: community.network.network.edgeos.edgeos network.edgeswitch.edgeswitch: redirect: community.network.network.edgeswitch.edgeswitch network.edgeswitch.edgeswitch_interface: redirect: community.network.network.edgeswitch.edgeswitch_interface network.enos.enos: redirect: community.network.network.enos.enos network.eos.argspec.facts: redirect: arista.eos.network.eos.argspec.facts network.eos.argspec.facts.facts: redirect: arista.eos.network.eos.argspec.facts.facts network.eos.argspec.interfaces: redirect: arista.eos.network.eos.argspec.interfaces network.eos.argspec.interfaces.interfaces: redirect: arista.eos.network.eos.argspec.interfaces.interfaces network.eos.argspec.l2_interfaces: redirect: arista.eos.network.eos.argspec.l2_interfaces network.eos.argspec.l2_interfaces.l2_interfaces: redirect: arista.eos.network.eos.argspec.l2_interfaces.l2_interfaces network.eos.argspec.l3_interfaces: redirect: arista.eos.network.eos.argspec.l3_interfaces network.eos.argspec.l3_interfaces.l3_interfaces: redirect: arista.eos.network.eos.argspec.l3_interfaces.l3_interfaces network.eos.argspec.lacp: redirect: arista.eos.network.eos.argspec.lacp network.eos.argspec.lacp.lacp: redirect: arista.eos.network.eos.argspec.lacp.lacp network.eos.argspec.lacp_interfaces: redirect: arista.eos.network.eos.argspec.lacp_interfaces network.eos.argspec.lacp_interfaces.lacp_interfaces: redirect: arista.eos.network.eos.argspec.lacp_interfaces.lacp_interfaces network.eos.argspec.lag_interfaces: redirect: arista.eos.network.eos.argspec.lag_interfaces network.eos.argspec.lag_interfaces.lag_interfaces: redirect: arista.eos.network.eos.argspec.lag_interfaces.lag_interfaces network.eos.argspec.lldp_global: redirect: arista.eos.network.eos.argspec.lldp_global network.eos.argspec.lldp_global.lldp_global: redirect: arista.eos.network.eos.argspec.lldp_global.lldp_global network.eos.argspec.lldp_interfaces: redirect: arista.eos.network.eos.argspec.lldp_interfaces network.eos.argspec.lldp_interfaces.lldp_interfaces: redirect: arista.eos.network.eos.argspec.lldp_interfaces.lldp_interfaces network.eos.argspec.vlans: redirect: arista.eos.network.eos.argspec.vlans network.eos.argspec.vlans.vlans: redirect: arista.eos.network.eos.argspec.vlans.vlans network.eos.config: redirect: arista.eos.network.eos.config network.eos.config.interfaces: redirect: arista.eos.network.eos.config.interfaces network.eos.config.interfaces.interfaces: redirect: arista.eos.network.eos.config.interfaces.interfaces network.eos.config.l2_interfaces: redirect: arista.eos.network.eos.config.l2_interfaces network.eos.config.l2_interfaces.l2_interfaces: redirect: arista.eos.network.eos.config.l2_interfaces.l2_interfaces network.eos.config.l3_interfaces: redirect: arista.eos.network.eos.config.l3_interfaces network.eos.config.l3_interfaces.l3_interfaces: redirect: arista.eos.network.eos.config.l3_interfaces.l3_interfaces network.eos.config.lacp: redirect: arista.eos.network.eos.config.lacp network.eos.config.lacp.lacp: redirect: arista.eos.network.eos.config.lacp.lacp network.eos.config.lacp_interfaces: redirect: arista.eos.network.eos.config.lacp_interfaces network.eos.config.lacp_interfaces.lacp_interfaces: redirect: arista.eos.network.eos.config.lacp_interfaces.lacp_interfaces network.eos.config.lag_interfaces: redirect: arista.eos.network.eos.config.lag_interfaces network.eos.config.lag_interfaces.lag_interfaces: redirect: arista.eos.network.eos.config.lag_interfaces.lag_interfaces network.eos.config.lldp_global: redirect: arista.eos.network.eos.config.lldp_global network.eos.config.lldp_global.lldp_global: redirect: arista.eos.network.eos.config.lldp_global.lldp_global network.eos.config.lldp_interfaces: redirect: arista.eos.network.eos.config.lldp_interfaces network.eos.config.lldp_interfaces.lldp_interfaces: redirect: arista.eos.network.eos.config.lldp_interfaces.lldp_interfaces network.eos.config.vlans: redirect: arista.eos.network.eos.config.vlans network.eos.config.vlans.vlans: redirect: arista.eos.network.eos.config.vlans.vlans network.eos.eos: redirect: arista.eos.network.eos.eos network.eos.facts: redirect: arista.eos.network.eos.facts network.eos.facts.facts: redirect: arista.eos.network.eos.facts.facts network.eos.facts.interfaces: redirect: arista.eos.network.eos.facts.interfaces network.eos.facts.interfaces.interfaces: redirect: arista.eos.network.eos.facts.interfaces.interfaces network.eos.facts.l2_interfaces: redirect: arista.eos.network.eos.facts.l2_interfaces network.eos.facts.l2_interfaces.l2_interfaces: redirect: arista.eos.network.eos.facts.l2_interfaces.l2_interfaces network.eos.facts.l3_interfaces: redirect: arista.eos.network.eos.facts.l3_interfaces network.eos.facts.l3_interfaces.l3_interfaces: redirect: arista.eos.network.eos.facts.l3_interfaces.l3_interfaces network.eos.facts.lacp: redirect: arista.eos.network.eos.facts.lacp network.eos.facts.lacp.lacp: redirect: arista.eos.network.eos.facts.lacp.lacp network.eos.facts.lacp_interfaces: redirect: arista.eos.network.eos.facts.lacp_interfaces network.eos.facts.lacp_interfaces.lacp_interfaces: redirect: arista.eos.network.eos.facts.lacp_interfaces.lacp_interfaces network.eos.facts.lag_interfaces: redirect: arista.eos.network.eos.facts.lag_interfaces network.eos.facts.lag_interfaces.lag_interfaces: redirect: arista.eos.network.eos.facts.lag_interfaces.lag_interfaces network.eos.facts.legacy: redirect: arista.eos.network.eos.facts.legacy network.eos.facts.legacy.base: redirect: arista.eos.network.eos.facts.legacy.base network.eos.facts.lldp_global: redirect: arista.eos.network.eos.facts.lldp_global network.eos.facts.lldp_global.lldp_global: redirect: arista.eos.network.eos.facts.lldp_global.lldp_global network.eos.facts.lldp_interfaces: redirect: arista.eos.network.eos.facts.lldp_interfaces network.eos.facts.lldp_interfaces.lldp_interfaces: redirect: arista.eos.network.eos.facts.lldp_interfaces.lldp_interfaces network.eos.facts.vlans: redirect: arista.eos.network.eos.facts.vlans network.eos.facts.vlans.vlans: redirect: arista.eos.network.eos.facts.vlans.vlans network.eos.providers: redirect: arista.eos.network.eos.providers network.eos.providers.cli: redirect: arista.eos.network.eos.providers.cli network.eos.providers.cli.config: redirect: arista.eos.network.eos.providers.cli.config network.eos.providers.cli.config.bgp: redirect: arista.eos.network.eos.providers.cli.config.bgp network.eos.providers.cli.config.bgp.address_family: redirect: arista.eos.network.eos.providers.cli.config.bgp.address_family network.eos.providers.cli.config.bgp.neighbors: redirect: arista.eos.network.eos.providers.cli.config.bgp.neighbors network.eos.providers.cli.config.bgp.process: redirect: arista.eos.network.eos.providers.cli.config.bgp.process network.eos.providers.module: redirect: arista.eos.network.eos.providers.module network.eos.providers.providers: redirect: arista.eos.network.eos.providers.providers network.eos.utils: redirect: arista.eos.network.eos.utils network.eos.utils.utils: redirect: arista.eos.network.eos.utils.utils network.eric_eccli.eric_eccli: redirect: community.network.network.eric_eccli.eric_eccli network.exos.argspec.facts.facts: redirect: community.network.network.exos.argspec.facts.facts network.exos.argspec.lldp_global: redirect: community.network.network.exos.argspec.lldp_global network.exos.argspec.lldp_global.lldp_global: redirect: community.network.network.exos.argspec.lldp_global.lldp_global network.exos.config.lldp_global: redirect: community.network.network.exos.config.lldp_global network.exos.config.lldp_global.lldp_global: redirect: community.network.network.exos.config.lldp_global.lldp_global network.exos.exos: redirect: community.network.network.exos.exos network.exos.facts.facts: redirect: community.network.network.exos.facts.facts network.exos.facts.legacy: redirect: community.network.network.exos.facts.legacy network.exos.facts.legacy.base: redirect: community.network.network.exos.facts.legacy.base network.exos.facts.lldp_global: redirect: community.network.network.exos.facts.lldp_global network.exos.facts.lldp_global.lldp_global: redirect: community.network.network.exos.facts.lldp_global.lldp_global network.exos.utils.utils: redirect: community.network.network.exos.utils.utils network.f5.bigip: redirect: f5networks.f5_modules.bigip network.f5.bigiq: redirect: f5networks.f5_modules.bigiq network.f5.common: redirect: f5networks.f5_modules.common network.f5.compare: redirect: f5networks.f5_modules.compare network.f5.icontrol: redirect: f5networks.f5_modules.icontrol network.f5.ipaddress: redirect: f5networks.f5_modules.ipaddress # FIXME: missing #network.f5.iworkflow: # redirect: f5networks.f5_modules.iworkflow #network.f5.legacy: # redirect: f5networks.f5_modules.legacy network.f5.urls: redirect: f5networks.f5_modules.urls network.fortianalyzer.common: redirect: community.fortios.fortianalyzer.common network.fortianalyzer.fortianalyzer: redirect: community.fortios.fortianalyzer.fortianalyzer network.fortimanager.common: redirect: fortinet.fortimanager.common network.fortimanager.fortimanager: redirect: fortinet.fortimanager.fortimanager network.fortios.argspec: redirect: fortinet.fortios.fortios.argspec network.fortios.argspec.facts: redirect: fortinet.fortios.fortios.argspec.facts network.fortios.argspec.facts.facts: redirect: fortinet.fortios.fortios.argspec.facts.facts network.fortios.argspec.system: redirect: fortinet.fortios.fortios.argspec.system network.fortios.argspec.system.system: redirect: fortinet.fortios.fortios.argspec.system.system network.fortios.facts: redirect: fortinet.fortios.fortios.facts network.fortios.facts.facts: redirect: fortinet.fortios.fortios.facts.facts network.fortios.facts.system: redirect: fortinet.fortios.fortios.facts.system network.fortios.facts.system.system: redirect: fortinet.fortios.fortios.facts.system.system network.fortios.fortios: redirect: fortinet.fortios.fortios.fortios network.frr: redirect: frr.frr.network.frr network.frr.frr: redirect: frr.frr.network.frr.frr network.frr.providers: redirect: frr.frr.network.frr.providers network.frr.providers.cli: redirect: frr.frr.network.frr.providers.cli network.frr.providers.cli.config: redirect: frr.frr.network.frr.providers.cli.config network.frr.providers.cli.config.base: redirect: frr.frr.network.frr.providers.cli.config.base network.frr.providers.cli.config.bgp: redirect: frr.frr.network.frr.providers.cli.config.bgp network.frr.providers.cli.config.bgp.address_family: redirect: frr.frr.network.frr.providers.cli.config.bgp.address_family network.frr.providers.cli.config.bgp.neighbors: redirect: frr.frr.network.frr.providers.cli.config.bgp.neighbors network.frr.providers.cli.config.bgp.process: redirect: frr.frr.network.frr.providers.cli.config.bgp.process network.frr.providers.module: redirect: frr.frr.network.frr.providers.module network.frr.providers.providers: redirect: frr.frr.network.frr.providers.providers network.ftd: redirect: community.network.network.ftd network.ftd.common: redirect: community.network.network.ftd.common network.ftd.configuration: redirect: community.network.network.ftd.configuration network.ftd.device: redirect: community.network.network.ftd.device network.ftd.fdm_swagger_client: redirect: community.network.network.ftd.fdm_swagger_client network.ftd.operation: redirect: community.network.network.ftd.operation network.icx: redirect: community.network.network.icx network.icx.icx: redirect: community.network.network.icx.icx network.ingate: redirect: community.network.network.ingate network.ingate.common: redirect: community.network.network.ingate.common network.ios: redirect: cisco.ios.network.ios network.ios.argspec: redirect: cisco.ios.network.ios.argspec network.ios.argspec.facts: redirect: cisco.ios.network.ios.argspec.facts network.ios.argspec.facts.facts: redirect: cisco.ios.network.ios.argspec.facts.facts network.ios.argspec.interfaces: redirect: cisco.ios.network.ios.argspec.interfaces network.ios.argspec.interfaces.interfaces: redirect: cisco.ios.network.ios.argspec.interfaces.interfaces network.ios.argspec.l2_interfaces: redirect: cisco.ios.network.ios.argspec.l2_interfaces network.ios.argspec.l2_interfaces.l2_interfaces: redirect: cisco.ios.network.ios.argspec.l2_interfaces.l2_interfaces network.ios.argspec.l3_interfaces: redirect: cisco.ios.network.ios.argspec.l3_interfaces network.ios.argspec.l3_interfaces.l3_interfaces: redirect: cisco.ios.network.ios.argspec.l3_interfaces.l3_interfaces network.ios.argspec.lacp: redirect: cisco.ios.network.ios.argspec.lacp network.ios.argspec.lacp.lacp: redirect: cisco.ios.network.ios.argspec.lacp.lacp network.ios.argspec.lacp_interfaces: redirect: cisco.ios.network.ios.argspec.lacp_interfaces network.ios.argspec.lacp_interfaces.lacp_interfaces: redirect: cisco.ios.network.ios.argspec.lacp_interfaces.lacp_interfaces network.ios.argspec.lag_interfaces: redirect: cisco.ios.network.ios.argspec.lag_interfaces network.ios.argspec.lag_interfaces.lag_interfaces: redirect: cisco.ios.network.ios.argspec.lag_interfaces.lag_interfaces network.ios.argspec.lldp_global: redirect: cisco.ios.network.ios.argspec.lldp_global network.ios.argspec.lldp_global.lldp_global: redirect: cisco.ios.network.ios.argspec.lldp_global.lldp_global network.ios.argspec.lldp_interfaces: redirect: cisco.ios.network.ios.argspec.lldp_interfaces network.ios.argspec.lldp_interfaces.lldp_interfaces: redirect: cisco.ios.network.ios.argspec.lldp_interfaces.lldp_interfaces network.ios.argspec.vlans: redirect: cisco.ios.network.ios.argspec.vlans network.ios.argspec.vlans.vlans: redirect: cisco.ios.network.ios.argspec.vlans.vlans network.ios.config: redirect: cisco.ios.network.ios.config network.ios.config.interfaces: redirect: cisco.ios.network.ios.config.interfaces network.ios.config.interfaces.interfaces: redirect: cisco.ios.network.ios.config.interfaces.interfaces network.ios.config.l2_interfaces: redirect: cisco.ios.network.ios.config.l2_interfaces network.ios.config.l2_interfaces.l2_interfaces: redirect: cisco.ios.network.ios.config.l2_interfaces.l2_interfaces network.ios.config.l3_interfaces: redirect: cisco.ios.network.ios.config.l3_interfaces network.ios.config.l3_interfaces.l3_interfaces: redirect: cisco.ios.network.ios.config.l3_interfaces.l3_interfaces network.ios.config.lacp: redirect: cisco.ios.network.ios.config.lacp network.ios.config.lacp.lacp: redirect: cisco.ios.network.ios.config.lacp.lacp network.ios.config.lacp_interfaces: redirect: cisco.ios.network.ios.config.lacp_interfaces network.ios.config.lacp_interfaces.lacp_interfaces: redirect: cisco.ios.network.ios.config.lacp_interfaces.lacp_interfaces network.ios.config.lag_interfaces: redirect: cisco.ios.network.ios.config.lag_interfaces network.ios.config.lag_interfaces.lag_interfaces: redirect: cisco.ios.network.ios.config.lag_interfaces.lag_interfaces network.ios.config.lldp_global: redirect: cisco.ios.network.ios.config.lldp_global network.ios.config.lldp_global.lldp_global: redirect: cisco.ios.network.ios.config.lldp_global.lldp_global network.ios.config.lldp_interfaces: redirect: cisco.ios.network.ios.config.lldp_interfaces network.ios.config.lldp_interfaces.lldp_interfaces: redirect: cisco.ios.network.ios.config.lldp_interfaces.lldp_interfaces network.ios.config.vlans: redirect: cisco.ios.network.ios.config.vlans network.ios.config.vlans.vlans: redirect: cisco.ios.network.ios.config.vlans.vlans network.ios.facts: redirect: cisco.ios.network.ios.facts network.ios.facts.facts: redirect: cisco.ios.network.ios.facts.facts network.ios.facts.interfaces: redirect: cisco.ios.network.ios.facts.interfaces network.ios.facts.interfaces.interfaces: redirect: cisco.ios.network.ios.facts.interfaces.interfaces network.ios.facts.l2_interfaces: redirect: cisco.ios.network.ios.facts.l2_interfaces network.ios.facts.l2_interfaces.l2_interfaces: redirect: cisco.ios.network.ios.facts.l2_interfaces.l2_interfaces network.ios.facts.l3_interfaces: redirect: cisco.ios.network.ios.facts.l3_interfaces network.ios.facts.l3_interfaces.l3_interfaces: redirect: cisco.ios.network.ios.facts.l3_interfaces.l3_interfaces network.ios.facts.lacp: redirect: cisco.ios.network.ios.facts.lacp network.ios.facts.lacp.lacp: redirect: cisco.ios.network.ios.facts.lacp.lacp network.ios.facts.lacp_interfaces: redirect: cisco.ios.network.ios.facts.lacp_interfaces network.ios.facts.lacp_interfaces.lacp_interfaces: redirect: cisco.ios.network.ios.facts.lacp_interfaces.lacp_interfaces network.ios.facts.lag_interfaces: redirect: cisco.ios.network.ios.facts.lag_interfaces network.ios.facts.lag_interfaces.lag_interfaces: redirect: cisco.ios.network.ios.facts.lag_interfaces.lag_interfaces network.ios.facts.legacy: redirect: cisco.ios.network.ios.facts.legacy network.ios.facts.legacy.base: redirect: cisco.ios.network.ios.facts.legacy.base network.ios.facts.lldp_global: redirect: cisco.ios.network.ios.facts.lldp_global network.ios.facts.lldp_global.lldp_global: redirect: cisco.ios.network.ios.facts.lldp_global.lldp_global network.ios.facts.lldp_interfaces: redirect: cisco.ios.network.ios.facts.lldp_interfaces network.ios.facts.lldp_interfaces.lldp_interfaces: redirect: cisco.ios.network.ios.facts.lldp_interfaces.lldp_interfaces network.ios.facts.vlans: redirect: cisco.ios.network.ios.facts.vlans network.ios.facts.vlans.vlans: redirect: cisco.ios.network.ios.facts.vlans.vlans network.ios.ios: redirect: cisco.ios.network.ios.ios network.ios.providers: redirect: cisco.ios.network.ios.providers network.ios.providers.cli: redirect: cisco.ios.network.ios.providers.cli network.ios.providers.cli.config: redirect: cisco.ios.network.ios.providers.cli.config network.ios.providers.cli.config.base: redirect: cisco.ios.network.ios.providers.cli.config.base network.ios.providers.cli.config.bgp: redirect: cisco.ios.network.ios.providers.cli.config.bgp network.ios.providers.cli.config.bgp.address_family: redirect: cisco.ios.network.ios.providers.cli.config.bgp.address_family network.ios.providers.cli.config.bgp.neighbors: redirect: cisco.ios.network.ios.providers.cli.config.bgp.neighbors network.ios.providers.cli.config.bgp.process: redirect: cisco.ios.network.ios.providers.cli.config.bgp.process network.ios.providers.module: redirect: cisco.ios.network.ios.providers.module network.ios.providers.providers: redirect: cisco.ios.network.ios.providers.providers network.ios.utils: redirect: cisco.ios.network.ios.utils network.ios.utils.utils: redirect: cisco.ios.network.ios.utils.utils network.iosxr: redirect: cisco.iosxr.network.iosxr network.iosxr.argspec: redirect: cisco.iosxr.network.iosxr.argspec network.iosxr.argspec.facts: redirect: cisco.iosxr.network.iosxr.argspec.facts network.iosxr.argspec.facts.facts: redirect: cisco.iosxr.network.iosxr.argspec.facts.facts network.iosxr.argspec.interfaces: redirect: cisco.iosxr.network.iosxr.argspec.interfaces network.iosxr.argspec.interfaces.interfaces: redirect: cisco.iosxr.network.iosxr.argspec.interfaces.interfaces network.iosxr.argspec.l2_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.l2_interfaces network.iosxr.argspec.l2_interfaces.l2_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.l2_interfaces.l2_interfaces network.iosxr.argspec.l3_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.l3_interfaces network.iosxr.argspec.l3_interfaces.l3_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.l3_interfaces.l3_interfaces network.iosxr.argspec.lacp: redirect: cisco.iosxr.network.iosxr.argspec.lacp network.iosxr.argspec.lacp.lacp: redirect: cisco.iosxr.network.iosxr.argspec.lacp.lacp network.iosxr.argspec.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lacp_interfaces network.iosxr.argspec.lacp_interfaces.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lacp_interfaces.lacp_interfaces network.iosxr.argspec.lag_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lag_interfaces network.iosxr.argspec.lag_interfaces.lag_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lag_interfaces.lag_interfaces network.iosxr.argspec.lldp_global: redirect: cisco.iosxr.network.iosxr.argspec.lldp_global network.iosxr.argspec.lldp_global.lldp_global: redirect: cisco.iosxr.network.iosxr.argspec.lldp_global.lldp_global network.iosxr.argspec.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lldp_interfaces network.iosxr.argspec.lldp_interfaces.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.argspec.lldp_interfaces.lldp_interfaces network.iosxr.config: redirect: cisco.iosxr.network.iosxr.config network.iosxr.config.interfaces: redirect: cisco.iosxr.network.iosxr.config.interfaces network.iosxr.config.interfaces.interfaces: redirect: cisco.iosxr.network.iosxr.config.interfaces.interfaces network.iosxr.config.l2_interfaces: redirect: cisco.iosxr.network.iosxr.config.l2_interfaces network.iosxr.config.l2_interfaces.l2_interfaces: redirect: cisco.iosxr.network.iosxr.config.l2_interfaces.l2_interfaces network.iosxr.config.l3_interfaces: redirect: cisco.iosxr.network.iosxr.config.l3_interfaces network.iosxr.config.l3_interfaces.l3_interfaces: redirect: cisco.iosxr.network.iosxr.config.l3_interfaces.l3_interfaces network.iosxr.config.lacp: redirect: cisco.iosxr.network.iosxr.config.lacp network.iosxr.config.lacp.lacp: redirect: cisco.iosxr.network.iosxr.config.lacp.lacp network.iosxr.config.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.config.lacp_interfaces network.iosxr.config.lacp_interfaces.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.config.lacp_interfaces.lacp_interfaces network.iosxr.config.lag_interfaces: redirect: cisco.iosxr.network.iosxr.config.lag_interfaces network.iosxr.config.lag_interfaces.lag_interfaces: redirect: cisco.iosxr.network.iosxr.config.lag_interfaces.lag_interfaces network.iosxr.config.lldp_global: redirect: cisco.iosxr.network.iosxr.config.lldp_global network.iosxr.config.lldp_global.lldp_global: redirect: cisco.iosxr.network.iosxr.config.lldp_global.lldp_global network.iosxr.config.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.config.lldp_interfaces network.iosxr.config.lldp_interfaces.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.config.lldp_interfaces.lldp_interfaces network.iosxr.facts: redirect: cisco.iosxr.network.iosxr.facts network.iosxr.facts.facts: redirect: cisco.iosxr.network.iosxr.facts.facts network.iosxr.facts.interfaces: redirect: cisco.iosxr.network.iosxr.facts.interfaces network.iosxr.facts.interfaces.interfaces: redirect: cisco.iosxr.network.iosxr.facts.interfaces.interfaces network.iosxr.facts.l2_interfaces: redirect: cisco.iosxr.network.iosxr.facts.l2_interfaces network.iosxr.facts.l2_interfaces.l2_interfaces: redirect: cisco.iosxr.network.iosxr.facts.l2_interfaces.l2_interfaces network.iosxr.facts.l3_interfaces: redirect: cisco.iosxr.network.iosxr.facts.l3_interfaces network.iosxr.facts.l3_interfaces.l3_interfaces: redirect: cisco.iosxr.network.iosxr.facts.l3_interfaces.l3_interfaces network.iosxr.facts.lacp: redirect: cisco.iosxr.network.iosxr.facts.lacp network.iosxr.facts.lacp.lacp: redirect: cisco.iosxr.network.iosxr.facts.lacp.lacp network.iosxr.facts.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lacp_interfaces network.iosxr.facts.lacp_interfaces.lacp_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lacp_interfaces.lacp_interfaces network.iosxr.facts.lag_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lag_interfaces network.iosxr.facts.lag_interfaces.lag_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lag_interfaces.lag_interfaces network.iosxr.facts.legacy: redirect: cisco.iosxr.network.iosxr.facts.legacy network.iosxr.facts.legacy.base: redirect: cisco.iosxr.network.iosxr.facts.legacy.base network.iosxr.facts.lldp_global: redirect: cisco.iosxr.network.iosxr.facts.lldp_global network.iosxr.facts.lldp_global.lldp_global: redirect: cisco.iosxr.network.iosxr.facts.lldp_global.lldp_global network.iosxr.facts.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lldp_interfaces network.iosxr.facts.lldp_interfaces.lldp_interfaces: redirect: cisco.iosxr.network.iosxr.facts.lldp_interfaces.lldp_interfaces network.iosxr.iosxr: redirect: cisco.iosxr.network.iosxr.iosxr network.iosxr.providers: redirect: cisco.iosxr.network.iosxr.providers network.iosxr.providers.cli: redirect: cisco.iosxr.network.iosxr.providers.cli network.iosxr.providers.cli.config: redirect: cisco.iosxr.network.iosxr.providers.cli.config network.iosxr.providers.cli.config.bgp: redirect: cisco.iosxr.network.iosxr.providers.cli.config.bgp network.iosxr.providers.cli.config.bgp.address_family: redirect: cisco.iosxr.network.iosxr.providers.cli.config.bgp.address_family network.iosxr.providers.cli.config.bgp.neighbors: redirect: cisco.iosxr.network.iosxr.providers.cli.config.bgp.neighbors network.iosxr.providers.cli.config.bgp.process: redirect: cisco.iosxr.network.iosxr.providers.cli.config.bgp.process network.iosxr.providers.module: redirect: cisco.iosxr.network.iosxr.providers.module network.iosxr.providers.providers: redirect: cisco.iosxr.network.iosxr.providers.providers network.iosxr.utils: redirect: cisco.iosxr.network.iosxr.utils network.iosxr.utils.utils: redirect: cisco.iosxr.network.iosxr.utils.utils network.ironware: redirect: community.network.network.ironware network.ironware.ironware: redirect: community.network.network.ironware.ironware network.junos: redirect: junipernetworks.junos.network.junos network.junos.argspec: redirect: junipernetworks.junos.network.junos.argspec network.junos.argspec.facts: redirect: junipernetworks.junos.network.junos.argspec.facts network.junos.argspec.facts.facts: redirect: junipernetworks.junos.network.junos.argspec.facts.facts network.junos.argspec.interfaces: redirect: junipernetworks.junos.network.junos.argspec.interfaces network.junos.argspec.interfaces.interfaces: redirect: junipernetworks.junos.network.junos.argspec.interfaces.interfaces network.junos.argspec.l2_interfaces: redirect: junipernetworks.junos.network.junos.argspec.l2_interfaces network.junos.argspec.l2_interfaces.l2_interfaces: redirect: junipernetworks.junos.network.junos.argspec.l2_interfaces.l2_interfaces network.junos.argspec.l3_interfaces: redirect: junipernetworks.junos.network.junos.argspec.l3_interfaces network.junos.argspec.l3_interfaces.l3_interfaces: redirect: junipernetworks.junos.network.junos.argspec.l3_interfaces.l3_interfaces network.junos.argspec.lacp: redirect: junipernetworks.junos.network.junos.argspec.lacp network.junos.argspec.lacp.lacp: redirect: junipernetworks.junos.network.junos.argspec.lacp.lacp network.junos.argspec.lacp_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lacp_interfaces network.junos.argspec.lacp_interfaces.lacp_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lacp_interfaces.lacp_interfaces network.junos.argspec.lag_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lag_interfaces network.junos.argspec.lag_interfaces.lag_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lag_interfaces.lag_interfaces network.junos.argspec.lldp_global: redirect: junipernetworks.junos.network.junos.argspec.lldp_global network.junos.argspec.lldp_global.lldp_global: redirect: junipernetworks.junos.network.junos.argspec.lldp_global.lldp_global network.junos.argspec.lldp_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lldp_interfaces network.junos.argspec.lldp_interfaces.lldp_interfaces: redirect: junipernetworks.junos.network.junos.argspec.lldp_interfaces.lldp_interfaces network.junos.argspec.vlans: redirect: junipernetworks.junos.network.junos.argspec.vlans network.junos.argspec.vlans.vlans: redirect: junipernetworks.junos.network.junos.argspec.vlans.vlans network.junos.config: redirect: junipernetworks.junos.network.junos.config network.junos.config.interfaces: redirect: junipernetworks.junos.network.junos.config.interfaces network.junos.config.interfaces.interfaces: redirect: junipernetworks.junos.network.junos.config.interfaces.interfaces network.junos.config.l2_interfaces: redirect: junipernetworks.junos.network.junos.config.l2_interfaces network.junos.config.l2_interfaces.l2_interfaces: redirect: junipernetworks.junos.network.junos.config.l2_interfaces.l2_interfaces network.junos.config.l3_interfaces: redirect: junipernetworks.junos.network.junos.config.l3_interfaces network.junos.config.l3_interfaces.l3_interfaces: redirect: junipernetworks.junos.network.junos.config.l3_interfaces.l3_interfaces network.junos.config.lacp: redirect: junipernetworks.junos.network.junos.config.lacp network.junos.config.lacp.lacp: redirect: junipernetworks.junos.network.junos.config.lacp.lacp network.junos.config.lacp_interfaces: redirect: junipernetworks.junos.network.junos.config.lacp_interfaces network.junos.config.lacp_interfaces.lacp_interfaces: redirect: junipernetworks.junos.network.junos.config.lacp_interfaces.lacp_interfaces network.junos.config.lag_interfaces: redirect: junipernetworks.junos.network.junos.config.lag_interfaces network.junos.config.lag_interfaces.lag_interfaces: redirect: junipernetworks.junos.network.junos.config.lag_interfaces.lag_interfaces network.junos.config.lldp_global: redirect: junipernetworks.junos.network.junos.config.lldp_global network.junos.config.lldp_global.lldp_global: redirect: junipernetworks.junos.network.junos.config.lldp_global.lldp_global network.junos.config.lldp_interfaces: redirect: junipernetworks.junos.network.junos.config.lldp_interfaces network.junos.config.lldp_interfaces.lldp_interfaces: redirect: junipernetworks.junos.network.junos.config.lldp_interfaces.lldp_interfaces network.junos.config.vlans: redirect: junipernetworks.junos.network.junos.config.vlans network.junos.config.vlans.vlans: redirect: junipernetworks.junos.network.junos.config.vlans.vlans network.junos.facts: redirect: junipernetworks.junos.network.junos.facts network.junos.facts.facts: redirect: junipernetworks.junos.network.junos.facts.facts network.junos.facts.interfaces: redirect: junipernetworks.junos.network.junos.facts.interfaces network.junos.facts.interfaces.interfaces: redirect: junipernetworks.junos.network.junos.facts.interfaces.interfaces network.junos.facts.l2_interfaces: redirect: junipernetworks.junos.network.junos.facts.l2_interfaces network.junos.facts.l2_interfaces.l2_interfaces: redirect: junipernetworks.junos.network.junos.facts.l2_interfaces.l2_interfaces network.junos.facts.l3_interfaces: redirect: junipernetworks.junos.network.junos.facts.l3_interfaces network.junos.facts.l3_interfaces.l3_interfaces: redirect: junipernetworks.junos.network.junos.facts.l3_interfaces.l3_interfaces network.junos.facts.lacp: redirect: junipernetworks.junos.network.junos.facts.lacp network.junos.facts.lacp.lacp: redirect: junipernetworks.junos.network.junos.facts.lacp.lacp network.junos.facts.lacp_interfaces: redirect: junipernetworks.junos.network.junos.facts.lacp_interfaces network.junos.facts.lacp_interfaces.lacp_interfaces: redirect: junipernetworks.junos.network.junos.facts.lacp_interfaces.lacp_interfaces network.junos.facts.lag_interfaces: redirect: junipernetworks.junos.network.junos.facts.lag_interfaces network.junos.facts.lag_interfaces.lag_interfaces: redirect: junipernetworks.junos.network.junos.facts.lag_interfaces.lag_interfaces network.junos.facts.legacy: redirect: junipernetworks.junos.network.junos.facts.legacy network.junos.facts.legacy.base: redirect: junipernetworks.junos.network.junos.facts.legacy.base network.junos.facts.lldp_global: redirect: junipernetworks.junos.network.junos.facts.lldp_global network.junos.facts.lldp_global.lldp_global: redirect: junipernetworks.junos.network.junos.facts.lldp_global.lldp_global network.junos.facts.lldp_interfaces: redirect: junipernetworks.junos.network.junos.facts.lldp_interfaces network.junos.facts.lldp_interfaces.lldp_interfaces: redirect: junipernetworks.junos.network.junos.facts.lldp_interfaces.lldp_interfaces network.junos.facts.vlans: redirect: junipernetworks.junos.network.junos.facts.vlans network.junos.facts.vlans.vlans: redirect: junipernetworks.junos.network.junos.facts.vlans.vlans network.junos.junos: redirect: junipernetworks.junos.network.junos.junos network.junos.utils: redirect: junipernetworks.junos.network.junos.utils network.junos.utils.utils: redirect: junipernetworks.junos.network.junos.utils.utils network.meraki: redirect: cisco.meraki.network.meraki network.meraki.meraki: redirect: cisco.meraki.network.meraki.meraki network.netconf: redirect: ansible.netcommon.network.netconf network.netconf.netconf: redirect: ansible.netcommon.network.netconf.netconf network.netscaler: redirect: community.network.network.netscaler network.netscaler.netscaler: redirect: community.network.network.netscaler.netscaler network.netvisor: redirect: community.network.network.netvisor network.netvisor.netvisor: redirect: community.network.network.netvisor.netvisor network.netvisor.pn_nvos: redirect: community.network.network.netvisor.pn_nvos network.nos: redirect: community.network.network.nos network.nos.nos: redirect: community.network.network.nos.nos network.nso: redirect: cisco.nso.nso network.nso.nso: redirect: cisco.nso.nso network.nxos: redirect: cisco.nxos.network.nxos network.nxos.argspec: redirect: cisco.nxos.network.nxos.argspec network.nxos.argspec.bfd_interfaces: redirect: cisco.nxos.network.nxos.argspec.bfd_interfaces network.nxos.argspec.bfd_interfaces.bfd_interfaces: redirect: cisco.nxos.network.nxos.argspec.bfd_interfaces.bfd_interfaces network.nxos.argspec.facts: redirect: cisco.nxos.network.nxos.argspec.facts network.nxos.argspec.facts.facts: redirect: cisco.nxos.network.nxos.argspec.facts.facts network.nxos.argspec.interfaces: redirect: cisco.nxos.network.nxos.argspec.interfaces network.nxos.argspec.interfaces.interfaces: redirect: cisco.nxos.network.nxos.argspec.interfaces.interfaces network.nxos.argspec.l2_interfaces: redirect: cisco.nxos.network.nxos.argspec.l2_interfaces network.nxos.argspec.l2_interfaces.l2_interfaces: redirect: cisco.nxos.network.nxos.argspec.l2_interfaces.l2_interfaces network.nxos.argspec.l3_interfaces: redirect: cisco.nxos.network.nxos.argspec.l3_interfaces network.nxos.argspec.l3_interfaces.l3_interfaces: redirect: cisco.nxos.network.nxos.argspec.l3_interfaces.l3_interfaces network.nxos.argspec.lacp: redirect: cisco.nxos.network.nxos.argspec.lacp network.nxos.argspec.lacp.lacp: redirect: cisco.nxos.network.nxos.argspec.lacp.lacp network.nxos.argspec.lacp_interfaces: redirect: cisco.nxos.network.nxos.argspec.lacp_interfaces network.nxos.argspec.lacp_interfaces.lacp_interfaces: redirect: cisco.nxos.network.nxos.argspec.lacp_interfaces.lacp_interfaces network.nxos.argspec.lag_interfaces: redirect: cisco.nxos.network.nxos.argspec.lag_interfaces network.nxos.argspec.lag_interfaces.lag_interfaces: redirect: cisco.nxos.network.nxos.argspec.lag_interfaces.lag_interfaces network.nxos.argspec.lldp_global: redirect: cisco.nxos.network.nxos.argspec.lldp_global network.nxos.argspec.lldp_global.lldp_global: redirect: cisco.nxos.network.nxos.argspec.lldp_global.lldp_global network.nxos.argspec.telemetry: redirect: cisco.nxos.network.nxos.argspec.telemetry network.nxos.argspec.telemetry.telemetry: redirect: cisco.nxos.network.nxos.argspec.telemetry.telemetry network.nxos.argspec.vlans: redirect: cisco.nxos.network.nxos.argspec.vlans network.nxos.argspec.vlans.vlans: redirect: cisco.nxos.network.nxos.argspec.vlans.vlans network.nxos.cmdref: redirect: cisco.nxos.network.nxos.cmdref network.nxos.cmdref.telemetry: redirect: cisco.nxos.network.nxos.cmdref.telemetry network.nxos.cmdref.telemetry.telemetry: redirect: cisco.nxos.network.nxos.cmdref.telemetry.telemetry network.nxos.config: redirect: cisco.nxos.network.nxos.config network.nxos.config.bfd_interfaces: redirect: cisco.nxos.network.nxos.config.bfd_interfaces network.nxos.config.bfd_interfaces.bfd_interfaces: redirect: cisco.nxos.network.nxos.config.bfd_interfaces.bfd_interfaces network.nxos.config.interfaces: redirect: cisco.nxos.network.nxos.config.interfaces network.nxos.config.interfaces.interfaces: redirect: cisco.nxos.network.nxos.config.interfaces.interfaces network.nxos.config.l2_interfaces: redirect: cisco.nxos.network.nxos.config.l2_interfaces network.nxos.config.l2_interfaces.l2_interfaces: redirect: cisco.nxos.network.nxos.config.l2_interfaces.l2_interfaces network.nxos.config.l3_interfaces: redirect: cisco.nxos.network.nxos.config.l3_interfaces network.nxos.config.l3_interfaces.l3_interfaces: redirect: cisco.nxos.network.nxos.config.l3_interfaces.l3_interfaces network.nxos.config.lacp: redirect: cisco.nxos.network.nxos.config.lacp network.nxos.config.lacp.lacp: redirect: cisco.nxos.network.nxos.config.lacp.lacp network.nxos.config.lacp_interfaces: redirect: cisco.nxos.network.nxos.config.lacp_interfaces network.nxos.config.lacp_interfaces.lacp_interfaces: redirect: cisco.nxos.network.nxos.config.lacp_interfaces.lacp_interfaces network.nxos.config.lag_interfaces: redirect: cisco.nxos.network.nxos.config.lag_interfaces network.nxos.config.lag_interfaces.lag_interfaces: redirect: cisco.nxos.network.nxos.config.lag_interfaces.lag_interfaces network.nxos.config.lldp_global: redirect: cisco.nxos.network.nxos.config.lldp_global network.nxos.config.lldp_global.lldp_global: redirect: cisco.nxos.network.nxos.config.lldp_global.lldp_global network.nxos.config.telemetry: redirect: cisco.nxos.network.nxos.config.telemetry network.nxos.config.telemetry.telemetry: redirect: cisco.nxos.network.nxos.config.telemetry.telemetry network.nxos.config.vlans: redirect: cisco.nxos.network.nxos.config.vlans network.nxos.config.vlans.vlans: redirect: cisco.nxos.network.nxos.config.vlans.vlans network.nxos.facts: redirect: cisco.nxos.network.nxos.facts network.nxos.facts.bfd_interfaces: redirect: cisco.nxos.network.nxos.facts.bfd_interfaces network.nxos.facts.bfd_interfaces.bfd_interfaces: redirect: cisco.nxos.network.nxos.facts.bfd_interfaces.bfd_interfaces network.nxos.facts.facts: redirect: cisco.nxos.network.nxos.facts.facts network.nxos.facts.interfaces: redirect: cisco.nxos.network.nxos.facts.interfaces network.nxos.facts.interfaces.interfaces: redirect: cisco.nxos.network.nxos.facts.interfaces.interfaces network.nxos.facts.l2_interfaces: redirect: cisco.nxos.network.nxos.facts.l2_interfaces network.nxos.facts.l2_interfaces.l2_interfaces: redirect: cisco.nxos.network.nxos.facts.l2_interfaces.l2_interfaces network.nxos.facts.l3_interfaces: redirect: cisco.nxos.network.nxos.facts.l3_interfaces network.nxos.facts.l3_interfaces.l3_interfaces: redirect: cisco.nxos.network.nxos.facts.l3_interfaces.l3_interfaces network.nxos.facts.lacp: redirect: cisco.nxos.network.nxos.facts.lacp network.nxos.facts.lacp.lacp: redirect: cisco.nxos.network.nxos.facts.lacp.lacp network.nxos.facts.lacp_interfaces: redirect: cisco.nxos.network.nxos.facts.lacp_interfaces network.nxos.facts.lacp_interfaces.lacp_interfaces: redirect: cisco.nxos.network.nxos.facts.lacp_interfaces.lacp_interfaces network.nxos.facts.lag_interfaces: redirect: cisco.nxos.network.nxos.facts.lag_interfaces network.nxos.facts.lag_interfaces.lag_interfaces: redirect: cisco.nxos.network.nxos.facts.lag_interfaces.lag_interfaces network.nxos.facts.legacy: redirect: cisco.nxos.network.nxos.facts.legacy network.nxos.facts.legacy.base: redirect: cisco.nxos.network.nxos.facts.legacy.base network.nxos.facts.lldp_global: redirect: cisco.nxos.network.nxos.facts.lldp_global network.nxos.facts.lldp_global.lldp_global: redirect: cisco.nxos.network.nxos.facts.lldp_global.lldp_global network.nxos.facts.telemetry: redirect: cisco.nxos.network.nxos.facts.telemetry network.nxos.facts.telemetry.telemetry: redirect: cisco.nxos.network.nxos.facts.telemetry.telemetry network.nxos.facts.vlans: redirect: cisco.nxos.network.nxos.facts.vlans network.nxos.facts.vlans.vlans: redirect: cisco.nxos.network.nxos.facts.vlans.vlans network.nxos.nxos: redirect: cisco.nxos.network.nxos.nxos network.nxos.utils: redirect: cisco.nxos.network.nxos.utils network.nxos.utils.telemetry: redirect: cisco.nxos.network.nxos.utils.telemetry network.nxos.utils.telemetry.telemetry: redirect: cisco.nxos.network.nxos.utils.telemetry.telemetry network.nxos.utils.utils: redirect: cisco.nxos.network.nxos.utils.utils network.onyx: redirect: mellanox.onyx.network.onyx network.onyx.onyx: redirect: mellanox.onyx.network.onyx.onyx network.ordnance: redirect: community.network.network.ordnance network.ordnance.ordnance: redirect: community.network.network.ordnance.ordnance network.panos: redirect: community.network.network.panos network.panos.panos: redirect: community.network.network.panos.panos network.restconf: redirect: ansible.netcommon.network.restconf network.restconf.restconf: redirect: ansible.netcommon.network.restconf.restconf network.routeros: redirect: community.routeros.routeros network.routeros.routeros: redirect: community.routeros.routeros network.skydive: redirect: community.skydive.network.skydive network.skydive.api: redirect: community.skydive.network.skydive.api network.slxos: redirect: community.network.network.slxos network.slxos.slxos: redirect: community.network.network.slxos.slxos network.sros: redirect: community.network.network.sros network.sros.sros: redirect: community.network.network.sros.sros network.voss: redirect: community.network.network.voss network.voss.voss: redirect: community.network.network.voss.voss network.vyos: redirect: vyos.vyos.network.vyos network.vyos.argspec: redirect: vyos.vyos.network.vyos.argspec network.vyos.argspec.facts: redirect: vyos.vyos.network.vyos.argspec.facts network.vyos.argspec.facts.facts: redirect: vyos.vyos.network.vyos.argspec.facts.facts network.vyos.argspec.interfaces: redirect: vyos.vyos.network.vyos.argspec.interfaces network.vyos.argspec.interfaces.interfaces: redirect: vyos.vyos.network.vyos.argspec.interfaces.interfaces network.vyos.argspec.l3_interfaces: redirect: vyos.vyos.network.vyos.argspec.l3_interfaces network.vyos.argspec.l3_interfaces.l3_interfaces: redirect: vyos.vyos.network.vyos.argspec.l3_interfaces.l3_interfaces network.vyos.argspec.lag_interfaces: redirect: vyos.vyos.network.vyos.argspec.lag_interfaces network.vyos.argspec.lag_interfaces.lag_interfaces: redirect: vyos.vyos.network.vyos.argspec.lag_interfaces.lag_interfaces network.vyos.argspec.lldp_global: redirect: vyos.vyos.network.vyos.argspec.lldp_global network.vyos.argspec.lldp_global.lldp_global: redirect: vyos.vyos.network.vyos.argspec.lldp_global.lldp_global network.vyos.argspec.lldp_interfaces: redirect: vyos.vyos.network.vyos.argspec.lldp_interfaces network.vyos.argspec.lldp_interfaces.lldp_interfaces: redirect: vyos.vyos.network.vyos.argspec.lldp_interfaces.lldp_interfaces network.vyos.config: redirect: vyos.vyos.network.vyos.config network.vyos.config.interfaces: redirect: vyos.vyos.network.vyos.config.interfaces network.vyos.config.interfaces.interfaces: redirect: vyos.vyos.network.vyos.config.interfaces.interfaces network.vyos.config.l3_interfaces: redirect: vyos.vyos.network.vyos.config.l3_interfaces network.vyos.config.l3_interfaces.l3_interfaces: redirect: vyos.vyos.network.vyos.config.l3_interfaces.l3_interfaces network.vyos.config.lag_interfaces: redirect: vyos.vyos.network.vyos.config.lag_interfaces network.vyos.config.lag_interfaces.lag_interfaces: redirect: vyos.vyos.network.vyos.config.lag_interfaces.lag_interfaces network.vyos.config.lldp_global: redirect: vyos.vyos.network.vyos.config.lldp_global network.vyos.config.lldp_global.lldp_global: redirect: vyos.vyos.network.vyos.config.lldp_global.lldp_global network.vyos.config.lldp_interfaces: redirect: vyos.vyos.network.vyos.config.lldp_interfaces network.vyos.config.lldp_interfaces.lldp_interfaces: redirect: vyos.vyos.network.vyos.config.lldp_interfaces.lldp_interfaces network.vyos.facts: redirect: vyos.vyos.network.vyos.facts network.vyos.facts.facts: redirect: vyos.vyos.network.vyos.facts.facts network.vyos.facts.interfaces: redirect: vyos.vyos.network.vyos.facts.interfaces network.vyos.facts.interfaces.interfaces: redirect: vyos.vyos.network.vyos.facts.interfaces.interfaces network.vyos.facts.l3_interfaces: redirect: vyos.vyos.network.vyos.facts.l3_interfaces network.vyos.facts.l3_interfaces.l3_interfaces: redirect: vyos.vyos.network.vyos.facts.l3_interfaces.l3_interfaces network.vyos.facts.lag_interfaces: redirect: vyos.vyos.network.vyos.facts.lag_interfaces network.vyos.facts.lag_interfaces.lag_interfaces: redirect: vyos.vyos.network.vyos.facts.lag_interfaces.lag_interfaces network.vyos.facts.legacy: redirect: vyos.vyos.network.vyos.facts.legacy network.vyos.facts.legacy.base: redirect: vyos.vyos.network.vyos.facts.legacy.base network.vyos.facts.lldp_global: redirect: vyos.vyos.network.vyos.facts.lldp_global network.vyos.facts.lldp_global.lldp_global: redirect: vyos.vyos.network.vyos.facts.lldp_global.lldp_global network.vyos.facts.lldp_interfaces: redirect: vyos.vyos.network.vyos.facts.lldp_interfaces network.vyos.facts.lldp_interfaces.lldp_interfaces: redirect: vyos.vyos.network.vyos.facts.lldp_interfaces.lldp_interfaces network.vyos.utils: redirect: vyos.vyos.network.vyos.utils network.vyos.utils.utils: redirect: vyos.vyos.network.vyos.utils.utils network.vyos.vyos: redirect: vyos.vyos.network.vyos.vyos oneandone: redirect: community.general.oneandone oneview: redirect: community.general.oneview online: redirect: community.general.online opennebula: redirect: community.general.opennebula openstack: redirect: openstack.cloud.openstack oracle: redirect: community.general.oracle oracle.oci_utils: redirect: community.general.oracle.oci_utils ovirt: redirect: community.general._ovirt podman: redirect: containers.podman.podman podman.common: redirect: containers.podman.podman.common postgres: redirect: community.postgresql.postgres pure: redirect: community.general.pure rabbitmq: redirect: community.rabbitmq.rabbitmq rax: redirect: community.general.rax redfish_utils: redirect: community.general.redfish_utils redhat: redirect: community.general.redhat remote_management.dellemc: redirect: dellemc.openmanage remote_management.dellemc.dellemc_idrac: redirect: dellemc.openmanage.dellemc_idrac remote_management.dellemc.ome: redirect: dellemc.openmanage.ome remote_management.intersight: redirect: cisco.intersight.intersight remote_management.lxca: redirect: community.general.remote_management.lxca remote_management.lxca.common: redirect: community.general.remote_management.lxca.common remote_management.ucs: redirect: cisco.ucs.ucs scaleway: redirect: community.general.scaleway service_now: redirect: servicenow.servicenow.service_now source_control: redirect: community.general.source_control source_control.bitbucket: redirect: community.general.source_control.bitbucket storage: redirect: community.general.storage storage.emc: redirect: community.general.storage.emc storage.emc.emc_vnx: redirect: community.general.storage.emc.emc_vnx storage.hpe3par: redirect: community.general.storage.hpe3par storage.hpe3par.hpe3par: redirect: community.general.storage.hpe3par.hpe3par univention_umc: redirect: community.general.univention_umc utm_utils: redirect: community.general.utm_utils vca: redirect: community.vmware.vca vexata: redirect: community.general.vexata vmware: redirect: community.vmware.vmware vmware_rest_client: redirect: community.vmware.vmware_rest_client vmware_spbm: redirect: community.vmware.vmware_spbm vultr: redirect: ngine_io.vultr.vultr xenserver: redirect: community.general.xenserver # end module_utils cliconf: frr: redirect: frr.frr.frr aireos: redirect: community.network.aireos apconos: redirect: community.network.apconos aruba: redirect: community.network.aruba ce: redirect: community.network.ce cnos: redirect: community.network.cnos edgeos: redirect: community.network.edgeos edgeswitch: redirect: community.network.edgeswitch enos: redirect: community.network.enos eric_eccli: redirect: community.network.eric_eccli exos: redirect: community.network.exos icx: redirect: community.network.icx ironware: redirect: community.network.ironware netvisor: redirect: community.network.netvisor nos: redirect: community.network.nos onyx: redirect: mellanox.onyx.onyx routeros: redirect: community.routeros.routeros slxos: redirect: community.network.slxos voss: redirect: community.network.voss eos: redirect: arista.eos.eos asa: redirect: cisco.asa.asa ios: redirect: cisco.ios.ios iosxr: redirect: cisco.iosxr.iosxr nxos: redirect: cisco.nxos.nxos junos: redirect: junipernetworks.junos.junos dellos10: redirect: dellemc.os10.os10 dellos9: redirect: dellemc.os9.os9 dellos6: redirect: dellemc.os6.os6 vyos: redirect: vyos.vyos.vyos terminal: frr: redirect: frr.frr.frr aireos: redirect: community.network.aireos apconos: redirect: community.network.apconos aruba: redirect: community.network.aruba ce: redirect: community.network.ce cnos: redirect: community.network.cnos edgeos: redirect: community.network.edgeos edgeswitch: redirect: community.network.edgeswitch enos: redirect: community.network.enos eric_eccli: redirect: community.network.eric_eccli exos: redirect: community.network.exos icx: redirect: community.network.icx ironware: redirect: community.network.ironware netvisor: redirect: community.network.netvisor nos: redirect: community.network.nos onyx: redirect: mellanox.onyx.onyx routeros: redirect: community.routeros.routeros slxos: redirect: community.network.slxos sros: redirect: community.network.sros voss: redirect: community.network.voss eos: redirect: arista.eos.eos asa: redirect: cisco.asa.asa ios: redirect: cisco.ios.ios iosxr: redirect: cisco.iosxr.iosxr nxos: redirect: cisco.nxos.nxos bigip: redirect: f5networks.f5_modules.bigip junos: redirect: junipernetworks.junos.junos dellos10: redirect: dellemc.os10.os10 dellos9: redirect: dellemc.os9.os9 dellos6: redirect: dellemc.os6.os6 vyos: redirect: vyos.vyos.vyos action: # test entry, overloaded with module of same name to use a different base action (ie not "normal.py") uses_redirected_action: redirect: testns.testcoll.subclassed_norm aireos: redirect: community.network.aireos aruba: redirect: community.network.aruba ce: redirect: community.network.ce ce_template: redirect: community.network.ce_template cnos: redirect: community.network.cnos edgeos_config: redirect: community.network.edgeos_config enos: redirect: community.network.enos exos: redirect: community.network.exos ironware: redirect: community.network.ironware nos_config: redirect: community.network.nos_config onyx_config: redirect: mellanox.onyx.onyx_config slxos: redirect: community.network.slxos sros: redirect: community.network.sros voss: redirect: community.network.voss aws_s3: redirect: amazon.aws.aws_s3 cli_command: redirect: ansible.netcommon.cli_command cli_config: redirect: ansible.netcommon.cli_config net_base: redirect: ansible.netcommon.net_base net_user: redirect: ansible.netcommon.net_user net_vlan: redirect: ansible.netcommon.net_vlan net_static_route: redirect: ansible.netcommon.net_static_route net_lldp: redirect: ansible.netcommon.net_lldp net_vrf: redirect: ansible.netcommon.net_vrf net_ping: redirect: ansible.netcommon.net_ping net_l3_interface: redirect: ansible.netcommon.net_l3_interface net_l2_interface: redirect: ansible.netcommon.net_l2_interface net_interface: redirect: ansible.netcommon.net_interface net_system: redirect: ansible.netcommon.net_system net_lldp_interface: redirect: ansible.netcommon.net_lldp_interface net_put: redirect: ansible.netcommon.net_put net_get: redirect: ansible.netcommon.net_get net_logging: redirect: ansible.netcommon.net_logging net_banner: redirect: ansible.netcommon.net_banner net_linkagg: redirect: ansible.netcommon.net_linkagg netconf: redirect: ansible.netcommon.netconf network: redirect: ansible.netcommon.network telnet: redirect: ansible.netcommon.telnet patch: redirect: ansible.posix.patch synchronize: redirect: ansible.posix.synchronize win_copy: redirect: ansible.windows.win_copy win_reboot: redirect: ansible.windows.win_reboot win_template: redirect: ansible.windows.win_template win_updates: redirect: ansible.windows.win_updates fortios_config: redirect: fortinet.fortios.fortios_config eos: redirect: arista.eos.eos asa: redirect: cisco.asa.asa ios: redirect: cisco.ios.ios iosxr: redirect: cisco.iosxr.iosxr nxos: redirect: cisco.nxos.nxos nxos_file_copy: redirect: cisco.nxos.nxos_file_copy bigip: redirect: f5networks.f5_modules.bigip bigiq: redirect: f5networks.f5_modules.bigiq junos: redirect: junipernetworks.junos.junos dellos10: redirect: dellemc.os10.os10 dellos9: redirect: dellemc.os9.os9 dellos6: redirect: dellemc.os6.os6 vyos: redirect: vyos.vyos.vyos include: tombstone: removal_date: "2023-05-16" warning_text: Use include_tasks or import_tasks instead. yum: redirect: ansible.builtin.dnf become: doas: redirect: community.general.doas dzdo: redirect: community.general.dzdo ksu: redirect: community.general.ksu machinectl: redirect: community.general.machinectl pbrun: redirect: community.general.pbrun pfexec: redirect: community.general.pfexec pmrun: redirect: community.general.pmrun sesu: redirect: community.general.sesu enable: redirect: ansible.netcommon.enable cache: memcached: redirect: community.general.memcached pickle: redirect: community.general.pickle redis: redirect: community.general.redis yaml: redirect: community.general.yaml mongodb: redirect: community.mongodb.mongodb callback: actionable: redirect: community.general.actionable cgroup_memory_recap: redirect: community.general.cgroup_memory_recap context_demo: redirect: community.general.context_demo counter_enabled: redirect: community.general.counter_enabled dense: redirect: community.general.dense full_skip: redirect: community.general.full_skip hipchat: redirect: community.general.hipchat jabber: redirect: community.general.jabber log_plays: redirect: community.general.log_plays logdna: redirect: community.general.logdna logentries: redirect: community.general.logentries logstash: redirect: community.general.logstash mail: redirect: community.general.mail nrdp: redirect: community.general.nrdp 'null': redirect: community.general.null osx_say: redirect: community.general.osx_say say: redirect: community.general.say selective: redirect: community.general.selective slack: redirect: community.general.slack splunk: redirect: community.general.splunk stderr: redirect: community.general.stderr sumologic: redirect: community.general.sumologic syslog_json: redirect: community.general.syslog_json unixy: redirect: community.general.unixy yaml: redirect: community.general.yaml grafana_annotations: redirect: community.grafana.grafana_annotations aws_resource_actions: redirect: amazon.aws.aws_resource_actions cgroup_perf_recap: redirect: ansible.posix.cgroup_perf_recap debug: redirect: ansible.posix.debug json: redirect: ansible.posix.json profile_roles: redirect: ansible.posix.profile_roles profile_tasks: redirect: ansible.posix.profile_tasks skippy: redirect: ansible.posix.skippy timer: redirect: ansible.posix.timer foreman: redirect: theforeman.foreman.foreman # 'collections' integration test entries, do not remove formerly_core_callback: redirect: testns.testcoll.usercallback formerly_core_removed_callback: redirect: testns.testcoll.removedcallback formerly_core_missing_callback: redirect: bogusns.boguscoll.boguscallback doc_fragments: a10: redirect: community.network.a10 aireos: redirect: community.network.aireos alicloud: redirect: community.general.alicloud aruba: redirect: community.network.aruba auth_basic: redirect: community.general.auth_basic avi: redirect: community.network.avi ce: redirect: community.network.ce cloudscale: redirect: cloudscale_ch.cloud.api_parameters cloudstack: redirect: ngine_io.cloudstack.cloudstack cnos: redirect: community.network.cnos digital_ocean: redirect: community.digitalocean.digital_ocean dimensiondata: redirect: community.general.dimensiondata dimensiondata_wait: redirect: community.general.dimensiondata_wait docker: redirect: community.docker.docker emc: redirect: community.general.emc enos: redirect: community.network.enos exoscale: redirect: ngine_io.exoscale.exoscale gcp: redirect: google.cloud.gcp hetzner: redirect: community.hrobot.robot hpe3par: redirect: community.general.hpe3par hwc: redirect: community.general.hwc ibm_storage: redirect: community.general.ibm_storage infinibox: redirect: infinidat.infinibox.infinibox influxdb: redirect: community.general.influxdb ingate: redirect: community.network.ingate ipa: redirect: community.general.ipa ironware: redirect: community.network.ironware keycloak: redirect: community.general.keycloak kubevirt_common_options: redirect: community.kubevirt.kubevirt_common_options kubevirt_vm_options: redirect: community.kubevirt.kubevirt_vm_options ldap: redirect: community.general.ldap lxca_common: redirect: community.general.lxca_common manageiq: redirect: community.general.manageiq mysql: redirect: community.mysql.mysql netscaler: redirect: community.network.netscaler nios: redirect: community.general.nios nso: redirect: cisco.nso.nso oneview: redirect: community.general.oneview online: redirect: community.general.online onyx: redirect: mellanox.onyx.onyx opennebula: redirect: community.general.opennebula openswitch: redirect: community.general.openswitch oracle: redirect: community.general.oracle oracle_creatable_resource: redirect: community.general.oracle_creatable_resource oracle_display_name_option: redirect: community.general.oracle_display_name_option oracle_name_option: redirect: community.general.oracle_name_option oracle_tags: redirect: community.general.oracle_tags oracle_wait_options: redirect: community.general.oracle_wait_options ovirt_facts: redirect: community.general.ovirt_facts panos: redirect: community.network.panos postgres: redirect: community.postgresql.postgres proxysql: redirect: community.proxysql.proxysql purestorage: redirect: community.general.purestorage rabbitmq: redirect: community.rabbitmq.rabbitmq rackspace: redirect: community.general.rackspace scaleway: redirect: community.general.scaleway sros: redirect: community.network.sros utm: redirect: community.general.utm vexata: redirect: community.general.vexata vultr: redirect: ngine_io.vultr.vultr xenserver: redirect: community.general.xenserver zabbix: redirect: community.zabbix.zabbix k8s_auth_options: redirect: kubernetes.core.k8s_auth_options k8s_name_options: redirect: kubernetes.core.k8s_name_options k8s_resource_options: redirect: kubernetes.core.k8s_resource_options k8s_scale_options: redirect: kubernetes.core.k8s_scale_options k8s_state_options: redirect: kubernetes.core.k8s_state_options acme: redirect: community.crypto.acme ecs_credential: redirect: community.crypto.ecs_credential VmwareRestModule: redirect: vmware.vmware_rest.VmwareRestModule VmwareRestModule_filters: redirect: vmware.vmware_rest.VmwareRestModule_filters VmwareRestModule_full: redirect: vmware.vmware_rest.VmwareRestModule_full VmwareRestModule_state: redirect: vmware.vmware_rest.VmwareRestModule_state vca: redirect: community.vmware.vca vmware: redirect: community.vmware.vmware vmware_rest_client: redirect: community.vmware.vmware_rest_client service_now: redirect: servicenow.servicenow.service_now aws: redirect: amazon.aws.aws aws_credentials: redirect: amazon.aws.aws_credentials aws_region: redirect: amazon.aws.aws_region ec2: redirect: amazon.aws.ec2 netconf: redirect: ansible.netcommon.netconf network_agnostic: redirect: ansible.netcommon.network_agnostic fortios: redirect: fortinet.fortios.fortios netapp: redirect: netapp.ontap.netapp checkpoint_commands: redirect: check_point.mgmt.checkpoint_commands checkpoint_facts: redirect: check_point.mgmt.checkpoint_facts checkpoint_objects: redirect: check_point.mgmt.checkpoint_objects eos: redirect: arista.eos.eos aci: redirect: cisco.aci.aci asa: redirect: cisco.asa.asa intersight: redirect: cisco.intersight.intersight ios: redirect: cisco.ios.ios iosxr: redirect: cisco.iosxr.iosxr meraki: redirect: cisco.meraki.meraki mso: redirect: cisco.mso.modules nxos: redirect: cisco.nxos.nxos ucs: redirect: cisco.ucs.ucs f5: redirect: f5networks.f5_modules.f5 openstack: redirect: openstack.cloud.openstack junos: redirect: junipernetworks.junos.junos tower: redirect: awx.awx.auth ovirt: redirect: ovirt.ovirt.ovirt ovirt_info: redirect: ovirt.ovirt.ovirt_info dellos10: redirect: dellemc.os10.os10 dellos9: redirect: dellemc.os9.os9 dellos6: redirect: dellemc.os6.os6 hcloud: redirect: hetzner.hcloud.hcloud skydive: redirect: community.skydive.skydive azure: redirect: azure.azcollection.azure azure_tags: redirect: azure.azcollection.azure_tags vyos: redirect: vyos.vyos.vyos filter: # test entries formerly_core_filter: redirect: ansible.builtin.bool formerly_core_masked_filter: redirect: ansible.builtin.bool gcp_kms_encrypt: redirect: google.cloud.gcp_kms_encrypt gcp_kms_decrypt: redirect: google.cloud.gcp_kms_decrypt json_query: redirect: community.general.json_query random_mac: redirect: community.general.random_mac k8s_config_resource_name: redirect: kubernetes.core.k8s_config_resource_name cidr_merge: redirect: ansible.netcommon.cidr_merge ipaddr: redirect: ansible.netcommon.ipaddr ipmath: redirect: ansible.netcommon.ipmath ipwrap: redirect: ansible.netcommon.ipwrap ip4_hex: redirect: ansible.netcommon.ip4_hex ipv4: redirect: ansible.netcommon.ipv4 ipv6: redirect: ansible.netcommon.ipv6 ipsubnet: redirect: ansible.netcommon.ipsubnet next_nth_usable: redirect: ansible.netcommon.next_nth_usable network_in_network: redirect: ansible.netcommon.network_in_network network_in_usable: redirect: ansible.netcommon.network_in_usable reduce_on_network: redirect: ansible.netcommon.reduce_on_network nthhost: redirect: ansible.netcommon.nthhost previous_nth_usable: redirect: ansible.netcommon.previous_nth_usable slaac: redirect: ansible.netcommon.slaac hwaddr: redirect: ansible.netcommon.hwaddr parse_cli: redirect: ansible.netcommon.parse_cli parse_cli_textfsm: redirect: ansible.netcommon.parse_cli_textfsm parse_xml: redirect: ansible.netcommon.parse_xml type5_pw: redirect: ansible.netcommon.type5_pw hash_salt: redirect: ansible.netcommon.hash_salt comp_type5: redirect: ansible.netcommon.comp_type5 vlan_parser: redirect: ansible.netcommon.vlan_parser httpapi: exos: redirect: community.network.exos fortianalyzer: redirect: community.fortios.fortianalyzer fortimanager: redirect: fortinet.fortimanager.fortimanager ftd: redirect: community.network.ftd vmware: redirect: community.vmware.vmware restconf: redirect: ansible.netcommon.restconf fortios: redirect: fortinet.fortios.fortios checkpoint: redirect: check_point.mgmt.checkpoint eos: redirect: arista.eos.eos nxos: redirect: cisco.nxos.nxos splunk: redirect: splunk.es.splunk qradar: redirect: ibm.qradar.qradar inventory: # test entry formerly_core_inventory: redirect: testns.content_adj.statichost cloudscale: redirect: cloudscale_ch.cloud.inventory docker_machine: redirect: community.docker.docker_machine docker_swarm: redirect: community.docker.docker_swarm gitlab_runners: redirect: community.general.gitlab_runners kubevirt: redirect: community.kubevirt.kubevirt linode: redirect: community.general.linode nmap: redirect: community.general.nmap online: redirect: community.general.online scaleway: redirect: community.general.scaleway virtualbox: redirect: community.general.virtualbox vultr: redirect: ngine_io.vultr.vultr k8s: redirect: kubernetes.core.k8s openshift: redirect: kubernetes.core.openshift vmware_vm_inventory: redirect: community.vmware.vmware_vm_inventory aws_ec2: redirect: amazon.aws.aws_ec2 aws_rds: redirect: amazon.aws.aws_rds foreman: redirect: theforeman.foreman.foreman netbox: redirect: netbox.netbox.nb_inventory openstack: redirect: openstack.cloud.openstack tower: redirect: awx.awx.tower hcloud: redirect: hetzner.hcloud.hcloud gcp_compute: redirect: google.cloud.gcp_compute azure_rm: redirect: azure.azcollection.azure_rm lookup: # test entry formerly_core_lookup: redirect: testns.testcoll.mylookup avi: redirect: community.network.avi cartesian: redirect: community.general.cartesian chef_databag: redirect: community.general.chef_databag conjur_variable: redirect: cyberark.conjur.conjur_variable consul_kv: redirect: community.general.consul_kv credstash: redirect: community.general.credstash cyberarkpassword: redirect: community.general.cyberarkpassword dig: redirect: community.general.dig dnstxt: redirect: community.general.dnstxt etcd: redirect: community.general.etcd filetree: redirect: community.general.filetree flattened: redirect: community.general.flattened gcp_storage_file: redirect: community.google.gcp_storage_file hashi_vault: redirect: community.hashi_vault.hashi_vault hiera: redirect: community.general.hiera keyring: redirect: community.general.keyring lastpass: redirect: community.general.lastpass lmdb_kv: redirect: community.general.lmdb_kv manifold: redirect: community.general.manifold nios: redirect: community.general.nios nios_next_ip: redirect: community.general.nios_next_ip nios_next_network: redirect: community.general.nios_next_network onepassword: redirect: community.general.onepassword onepassword_raw: redirect: community.general.onepassword_raw passwordstore: redirect: community.general.passwordstore rabbitmq: redirect: community.rabbitmq.rabbitmq redis: redirect: community.general.redis shelvefile: redirect: community.general.shelvefile grafana_dashboard: redirect: community.grafana.grafana_dashboard openshift: redirect: kubernetes.core.openshift k8s: redirect: kubernetes.core.k8s mongodb: redirect: community.mongodb.mongodb laps_password: redirect: community.windows.laps_password aws_account_attribute: redirect: amazon.aws.aws_account_attribute aws_secret: redirect: amazon.aws.aws_secret aws_service_ip_ranges: redirect: amazon.aws.aws_service_ip_ranges aws_ssm: redirect: amazon.aws.aws_ssm skydive: redirect: community.skydive.skydive cpm_metering: redirect: wti.remote.cpm_metering cpm_status: redirect: wti.remote.cpm_status netconf: ce: redirect: community.network.ce sros: redirect: community.network.sros default: redirect: ansible.netcommon.default iosxr: redirect: cisco.iosxr.iosxr junos: redirect: junipernetworks.junos.junos shell: # test entry formerly_core_powershell: redirect: ansible.builtin.powershell csh: redirect: ansible.posix.csh fish: redirect: ansible.posix.fish test: # test entries formerly_core_test: redirect: ansible.builtin.search formerly_core_masked_test: redirect: ansible.builtin.search import_redirection: # test entry ansible.module_utils.formerly_core: redirect: ansible_collections.testns.testcoll.plugins.module_utils.base ansible.module_utils.known_hosts: redirect: ansible_collections.community.general.plugins.module_utils.known_hosts # ansible.builtin synthetic collection redirection hackery ansible_collections.ansible.builtin.plugins.modules: redirect: ansible.modules ansible_collections.ansible.builtin.plugins.module_utils: redirect: ansible.module_utils ansible_collections.ansible.builtin.plugins: redirect: ansible.plugins action_groups: testgroup: # The list items under a group should always be action/module name strings except # for a special 'metadata' dictionary. # The only valid key currently for the metadata dictionary is 'extend_group', which is a # list of other groups, the actions of which will be included in this group. # (Note: it's still possible to also have a module/action named 'metadata' in the list) - metadata: extend_group: - testns.testcoll.testgroup - testns.testcoll.anothergroup - testns.boguscoll.testgroup - ping - legacy_ping # Includes ansible.builtin.legacy_ping, not ansible.legacy.legacy_ping - formerly_core_ping testlegacy: - ansible.legacy.legacy_ping aws: - metadata: extend_group: - amazon.aws.aws - community.aws.aws acme: - metadata: extend_group: - community.crypto.acme azure: - metadata: extend_group: - azure.azcollection.azure cpm: - metadata: extend_group: - wti.remote.cpm docker: - metadata: extend_group: - community.general.docker - community.docker.docker gcp: - metadata: extend_group: - google.cloud.gcp k8s: - metadata: extend_group: - community.kubernetes.k8s - community.general.k8s - community.kubevirt.k8s - community.okd.k8s - kubernetes.core.k8s os: - metadata: extend_group: - openstack.cloud.os ovirt: - metadata: extend_group: - ovirt.ovirt.ovirt - community.general.ovirt vmware: - metadata: extend_group: - community.vmware.vmware ansible_core-2.19.0b5/lib/ansible/config/base.yml0000644000000000000000000025672215017704211020316 0ustar00rootroot# Copyright (c) 2017 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) --- _ANSIBLE_CONNECTION_PATH: env: - name: _ANSIBLE_CONNECTION_PATH name: Overrides the location of the Ansible persistent connection helper script. description: - For internal use only. type: path version_added: "2.18" _CALLBACK_DISPATCH_ERROR_BEHAVIOR: name: Callback dispatch error behavior default: warning description: - Action to take when a callback dispatch results in an error. type: choices choices: &basic_error error: issue a 'fatal' error and stop the play warning: issue a warning but continue ignore: just continue silently env: [ { name: _ANSIBLE_CALLBACK_DISPATCH_ERROR_BEHAVIOR } ] version_added: '2.19' ALLOW_BROKEN_CONDITIONALS: # This config option will be deprecated once it no longer has any effect (2.23). name: Allow broken conditionals default: false description: - When enabled, this option allows conditionals with non-boolean results to be used. - A deprecation warning will be emitted in these cases. - By default, non-boolean conditionals result in an error. - Such results often indicate unintentional use of templates where they are not supported, resulting in a conditional that is always true. - When this option is enabled, conditional expressions which are a literal ``None`` or empty string will evaluate as true for backwards compatibility. env: [{name: ANSIBLE_ALLOW_BROKEN_CONDITIONALS}] ini: - {key: allow_broken_conditionals, section: defaults} type: boolean version_added: "2.19" ALLOW_EMBEDDED_TEMPLATES: name: Allow embedded templates default: true description: - When enabled, this option allows embedded templates to be used for specific backward compatibility scenarios. - A deprecation warning will be emitted in these cases. - First, conditionals (for example, ``failed_when``, ``until``, ``assert.that``) fully enclosed in template delimiters. - "Second, string constants in conditionals (for example, ``when: some_var == '{{ some_other_var }}'``)." - Finally, positional arguments to lookups (for example, ``lookup('pipe', 'echo {{ some_var }}')``). - This feature is deprecated, since embedded templates are unnecessary in these cases. - When disabled, use of embedded templates will result in an error. - A future release will disable this feature by default. env: [{name: ANSIBLE_ALLOW_EMBEDDED_TEMPLATES}] ini: - {key: allow_embedded_templates, section: defaults} type: boolean version_added: "2.19" ANSIBLE_HOME: name: The Ansible home path description: - The default root path for Ansible config files on the controller. default: ~/.ansible env: - name: ANSIBLE_HOME ini: - key: home section: defaults type: path version_added: '2.14' ANSIBLE_CONNECTION_PATH: name: Path of ansible-connection script default: null description: - Specify where to look for the ansible-connection script. This location will be checked before searching $PATH. - If null, ansible will start with the same directory as the ansible script. type: path env: [{name: ANSIBLE_CONNECTION_PATH}] ini: - {key: ansible_connection_path, section: persistent_connection} yaml: {key: persistent_connection.ansible_connection_path} version_added: "2.8" deprecated: why: This setting has no effect. version: "2.22" ANSIBLE_COW_SELECTION: name: Cowsay filter selection default: default description: This allows you to choose a specific cowsay stencil for the banners or use 'random' to cycle through them. env: [{name: ANSIBLE_COW_SELECTION}] ini: - {key: cow_selection, section: defaults} ANSIBLE_COW_ACCEPTLIST: name: Cowsay filter acceptance list default: ['bud-frogs', 'bunny', 'cheese', 'daemon', 'default', 'dragon', 'elephant-in-snake', 'elephant', 'eyes', 'hellokitty', 'kitty', 'luke-koala', 'meow', 'milk', 'moofasa', 'moose', 'ren', 'sheep', 'small', 'stegosaurus', 'stimpy', 'supermilker', 'three-eyes', 'turkey', 'turtle', 'tux', 'udder', 'vader-koala', 'vader', 'www'] description: Accept a list of cowsay templates that are 'safe' to use, set to an empty list if you want to enable all installed templates. env: - name: ANSIBLE_COW_ACCEPTLIST version_added: '2.11' ini: - key: cowsay_enabled_stencils section: defaults version_added: '2.11' type: list ANSIBLE_FORCE_COLOR: name: Force color output default: False description: This option forces color mode even when running without a TTY or the "nocolor" setting is True. env: [{name: ANSIBLE_FORCE_COLOR}] ini: - {key: force_color, section: defaults} type: boolean yaml: {key: display.force_color} ANSIBLE_NOCOLOR: name: Suppress color output default: False description: This setting allows suppressing colorizing output, which is used to give a better indication of failure and status information. env: - name: ANSIBLE_NOCOLOR # this is generic convention for CLI programs - name: NO_COLOR version_added: '2.11' ini: - {key: nocolor, section: defaults} type: boolean yaml: {key: display.nocolor} ANSIBLE_NOCOWS: name: Suppress cowsay output default: False description: If you have cowsay installed but want to avoid the 'cows' (why????), use this. env: [{name: ANSIBLE_NOCOWS}] ini: - {key: nocows, section: defaults} type: boolean yaml: {key: display.i_am_no_fun} ANSIBLE_COW_PATH: name: Set path to cowsay command default: null description: Specify a custom cowsay path or swap in your cowsay implementation of choice. env: [{name: ANSIBLE_COW_PATH}] ini: - {key: cowpath, section: defaults} type: string yaml: {key: display.cowpath} ANSIBLE_PIPELINING: name: Connection pipelining default: False description: - This is a global option, each connection plugin can override either by having more specific options or not supporting pipelining at all. - Pipelining, if supported by the connection plugin, reduces the number of network operations required to execute a module on the remote server, by executing many Ansible modules without actual file transfer. - It can result in a very significant performance improvement when enabled. - "However this conflicts with privilege escalation (become). For example, when using 'sudo:' operations you must first disable 'requiretty' in /etc/sudoers on all managed hosts, which is why it is disabled by default." - This setting will be disabled if ``ANSIBLE_KEEP_REMOTE_FILES`` is enabled. env: - name: ANSIBLE_PIPELINING ini: - section: defaults key: pipelining - section: connection key: pipelining type: boolean ANY_ERRORS_FATAL: name: Make Task failures fatal default: False description: Sets the default value for the any_errors_fatal keyword, if True, Task failures will be considered fatal errors. env: - name: ANSIBLE_ANY_ERRORS_FATAL ini: - section: defaults key: any_errors_fatal type: boolean yaml: {key: errors.any_task_errors_fatal} version_added: "2.4" BECOME_ALLOW_SAME_USER: name: Allow becoming the same user default: False description: - When ``False``(default), Ansible will skip using become if the remote user is the same as the become user, as this is normally a redundant operation. In other words root sudo to root. - If ``True``, this forces Ansible to use the become plugin anyways as there are cases in which this is needed. env: [{name: ANSIBLE_BECOME_ALLOW_SAME_USER}] ini: - {key: become_allow_same_user, section: privilege_escalation} type: boolean yaml: {key: privilege_escalation.become_allow_same_user} BECOME_PASSWORD_FILE: name: Become password file default: ~ description: - 'The password file to use for the become plugin. ``--become-password-file``.' - If executable, it will be run and the resulting stdout will be used as the password. env: [{name: ANSIBLE_BECOME_PASSWORD_FILE}] ini: - {key: become_password_file, section: defaults} type: path version_added: '2.12' AGNOSTIC_BECOME_PROMPT: name: Display an agnostic become prompt default: True type: boolean description: Display an agnostic become prompt instead of displaying a prompt containing the command line supplied become method. env: [{name: ANSIBLE_AGNOSTIC_BECOME_PROMPT}] ini: - {key: agnostic_become_prompt, section: privilege_escalation} yaml: {key: privilege_escalation.agnostic_become_prompt} version_added: "2.5" CACHE_PLUGIN: name: Persistent Fact Cache plugin default: memory description: Chooses which fact cache plugin to use. By default, no cache is used and facts do not persist between runs. env: [{name: ANSIBLE_CACHE_PLUGIN}] ini: - {key: fact_caching, section: defaults} yaml: {key: facts.cache.plugin} CACHE_PLUGIN_CONNECTION: name: Fact Cache Plugin URI default: ~ description: Defines connection or path information for the fact cache plugin. env: [{name: ANSIBLE_CACHE_PLUGIN_CONNECTION}] ini: - {key: fact_caching_connection, section: defaults} yaml: {key: facts.cache.uri} CACHE_PLUGIN_PREFIX: name: Fact Cache Plugin table prefix default: ansible_facts description: Prefix to use for fact cache plugin files/tables. env: [{name: ANSIBLE_CACHE_PLUGIN_PREFIX}] ini: - {key: fact_caching_prefix, section: defaults} yaml: {key: facts.cache.prefix} CACHE_PLUGIN_TIMEOUT: name: Fact Cache Plugin expiration timeout default: 86400 description: Expiration timeout for the fact cache plugin data. env: [{name: ANSIBLE_CACHE_PLUGIN_TIMEOUT}] ini: - {key: fact_caching_timeout, section: defaults} type: integer yaml: {key: facts.cache.timeout} COLLECTIONS_SCAN_SYS_PATH: name: Scan PYTHONPATH for installed collections description: A boolean to enable or disable scanning the sys.path for installed collections. default: true type: boolean env: - {name: ANSIBLE_COLLECTIONS_SCAN_SYS_PATH} ini: - {key: collections_scan_sys_path, section: defaults} COLLECTIONS_PATHS: name: An ordered list of root paths for loading installed Ansible collections content. description: > Colon-separated paths in which Ansible will search for collections content. Collections must be in nested *subdirectories*, not directly in these directories. For example, if ``COLLECTIONS_PATHS`` includes ``'{{ ANSIBLE_HOME ~ "/collections" }}'``, and you want to add ``my.collection`` to that directory, it must be saved as ``'{{ ANSIBLE_HOME} ~ "/collections/ansible_collections/my/collection" }}'``. default: '{{ ANSIBLE_HOME ~ "/collections:/usr/share/ansible/collections" }}' type: pathspec env: - name: ANSIBLE_COLLECTIONS_PATH version_added: '2.10' ini: - key: collections_path section: defaults version_added: '2.10' COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH: name: Defines behavior when loading a collection that does not support the current Ansible version description: - When a collection is loaded that does not support the running Ansible version (with the collection metadata key `requires_ansible`). env: [{name: ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH}] ini: [{key: collections_on_ansible_version_mismatch, section: defaults}] choices: *basic_error default: warning COLOR_CHANGED: name: Color for 'changed' task status default: yellow description: Defines the color to use on 'Changed' task status. env: [{name: ANSIBLE_COLOR_CHANGED}] ini: - {key: changed, section: colors} COLOR_CONSOLE_PROMPT: name: "Color for ansible-console's prompt task status" default: white description: Defines the default color to use for ansible-console. env: [{name: ANSIBLE_COLOR_CONSOLE_PROMPT}] ini: - {key: console_prompt, section: colors} version_added: "2.7" COLOR_DEBUG: name: Color for debug statements default: dark gray description: Defines the color to use when emitting debug messages. env: [{name: ANSIBLE_COLOR_DEBUG}] ini: - {key: debug, section: colors} COLOR_DEPRECATE: name: Color for deprecation messages default: purple description: Defines the color to use when emitting deprecation messages. env: [{name: ANSIBLE_COLOR_DEPRECATE}] ini: - {key: deprecate, section: colors} COLOR_DIFF_ADD: name: Color for diff added display default: green description: Defines the color to use when showing added lines in diffs. env: [{name: ANSIBLE_COLOR_DIFF_ADD}] ini: - {key: diff_add, section: colors} yaml: {key: display.colors.diff.add} COLOR_DIFF_LINES: name: Color for diff lines display default: cyan description: Defines the color to use when showing diffs. env: [{name: ANSIBLE_COLOR_DIFF_LINES}] ini: - {key: diff_lines, section: colors} COLOR_DIFF_REMOVE: name: Color for diff removed display default: red description: Defines the color to use when showing removed lines in diffs. env: [{name: ANSIBLE_COLOR_DIFF_REMOVE}] ini: - {key: diff_remove, section: colors} COLOR_ERROR: name: Color for error messages default: red description: Defines the color to use when emitting error messages. env: [{name: ANSIBLE_COLOR_ERROR}] ini: - {key: error, section: colors} yaml: {key: colors.error} COLOR_HIGHLIGHT: name: Color for highlighting default: white description: Defines the color to use for highlighting. env: [{name: ANSIBLE_COLOR_HIGHLIGHT}] ini: - {key: highlight, section: colors} COLOR_INCLUDED: name: Color for 'included' task status default: cyan description: Defines the color to use when showing 'Included' task status. env: [{name: ANSIBLE_COLOR_INCLUDED}] ini: - {key: included, section: colors} version_added: '2.18' COLOR_OK: name: Color for 'ok' task status default: green description: Defines the color to use when showing 'OK' task status. env: [{name: ANSIBLE_COLOR_OK}] ini: - {key: ok, section: colors} COLOR_SKIP: name: Color for 'skip' task status default: cyan description: Defines the color to use when showing 'Skipped' task status. env: [{name: ANSIBLE_COLOR_SKIP}] ini: - {key: skip, section: colors} COLOR_UNREACHABLE: name: Color for 'unreachable' host state default: bright red description: Defines the color to use on 'Unreachable' status. env: [{name: ANSIBLE_COLOR_UNREACHABLE}] ini: - {key: unreachable, section: colors} COLOR_VERBOSE: name: Color for verbose messages default: blue description: Defines the color to use when emitting verbose messages. In other words, those that show with '-v's. env: [{name: ANSIBLE_COLOR_VERBOSE}] ini: - {key: verbose, section: colors} COLOR_WARN: name: Color for warning messages default: bright purple description: Defines the color to use when emitting warning messages. env: [{name: ANSIBLE_COLOR_WARN}] ini: - {key: warn, section: colors} COLOR_DOC_MODULE: name: Color for module name in the ansible-doc output default: yellow description: Defines the color to use when emitting a module name in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_MODULE}] ini: - {key: doc_module, section: colors} version_added: '2.18' COLOR_DOC_REFERENCE: name: Color for cross-reference in the ansible-doc output default: magenta description: Defines the color to use when emitting cross-reference in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_REFERENCE}] ini: - {key: doc_reference, section: colors} version_added: '2.18' COLOR_DOC_LINK: name: Color for Link in ansible-doc output default: cyan description: Defines the color to use when emitting a link in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_LINK}] ini: - {key: doc_link, section: colors} version_added: '2.18' COLOR_DOC_DEPRECATED: name: Color for deprecated value in ansible-doc output default: magenta description: Defines the color to use when emitting a deprecated value in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_DEPRECATED}] ini: - {key: doc_deprecated, section: colors} version_added: '2.18' COLOR_DOC_CONSTANT: name: Color for constant in ansible-doc output default: dark gray description: Defines the color to use when emitting a constant in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_CONSTANT}] ini: - {key: doc_constant, section: colors} version_added: '2.18' COLOR_DOC_PLUGIN: name: Color for the plugin in ansible-doc output default: yellow description: Defines the color to use when emitting a plugin name in the ansible-doc output. env: [{name: ANSIBLE_COLOR_DOC_PLUGIN}] ini: - {key: doc_plugin, section: colors} version_added: '2.18' CONNECTION_PASSWORD_FILE: name: Connection password file default: ~ description: 'The password file to use for the connection plugin. ``--connection-password-file``.' env: [{name: ANSIBLE_CONNECTION_PASSWORD_FILE}] ini: - {key: connection_password_file, section: defaults} type: path version_added: '2.12' COVERAGE_REMOTE_OUTPUT: name: Sets the output directory and filename prefix to generate coverage run info. description: - Sets the output directory on the remote host to generate coverage reports into. - Currently only used for remote coverage on PowerShell modules. - This is for internal use only. env: - {name: _ANSIBLE_COVERAGE_REMOTE_OUTPUT} vars: - {name: _ansible_coverage_remote_output} type: str version_added: '2.9' COVERAGE_REMOTE_PATHS: name: Sets the list of paths to run coverage for. description: - A list of paths for files on the Ansible controller to run coverage for when executing on the remote host. - Only files that match the path glob will have their coverage collected. - Multiple path globs can be specified and are separated by ``:``. - Currently only used for remote coverage on PowerShell modules. - This is for internal use only. default: '*' env: - {name: _ANSIBLE_COVERAGE_REMOTE_PATH_FILTER} type: str version_added: '2.9' ACTION_WARNINGS: name: Toggle action warnings default: True description: - By default, Ansible will issue a warning when received from a task action (module or action plugin). - These warnings can be silenced by adjusting this setting to False. env: [{name: ANSIBLE_ACTION_WARNINGS}] ini: - {key: action_warnings, section: defaults} type: boolean version_added: "2.5" LOCALHOST_WARNING: name: Warning when using implicit inventory with only localhost default: True description: - By default, Ansible will issue a warning when there are no hosts in the inventory. - These warnings can be silenced by adjusting this setting to False. env: [{name: ANSIBLE_LOCALHOST_WARNING}] ini: - {key: localhost_warning, section: defaults} type: boolean version_added: "2.6" LOG_VERBOSITY: name: Default log verbosity description: - This will set log verbosity if higher than the normal display verbosity, otherwise it will match that. env: [{name: ANSIBLE_LOG_VERBOSITY}] ini: - {key: log_verbosity, section: defaults} type: int version_added: "2.17" INVENTORY_UNPARSED_WARNING: name: Warning when no inventory files can be parsed, resulting in an implicit inventory with only localhost default: True description: - By default, Ansible will issue a warning when no inventory was loaded and notes that it will use an implicit localhost-only inventory. - These warnings can be silenced by adjusting this setting to False. env: [{name: ANSIBLE_INVENTORY_UNPARSED_WARNING}] ini: - {key: inventory_unparsed_warning, section: inventory} type: boolean version_added: "2.14" DOC_FRAGMENT_PLUGIN_PATH: name: documentation fragment plugins path default: '{{ ANSIBLE_HOME ~ "/plugins/doc_fragments:/usr/share/ansible/plugins/doc_fragments" }}' description: Colon-separated paths in which Ansible will search for Documentation Fragments Plugins. env: [{name: ANSIBLE_DOC_FRAGMENT_PLUGINS}] ini: - {key: doc_fragment_plugins, section: defaults} type: pathspec DEFAULT_ACTION_PLUGIN_PATH: name: Action plugins path default: '{{ ANSIBLE_HOME ~ "/plugins/action:/usr/share/ansible/plugins/action" }}' description: Colon-separated paths in which Ansible will search for Action Plugins. env: [{name: ANSIBLE_ACTION_PLUGINS}] ini: - {key: action_plugins, section: defaults} type: pathspec yaml: {key: plugins.action.path} DEFAULT_ALLOW_UNSAFE_LOOKUPS: name: Allow unsafe lookups default: False description: - "When enabled, this option allows lookup plugins (whether used in variables as ``{{lookup('foo')}}`` or as a loop as with_foo) to return data that is not marked 'unsafe'." - By default, such data is marked as unsafe to prevent the templating engine from evaluating any jinja2 templating language, as this could represent a security risk. This option is provided to allow for backward compatibility, however, users should first consider adding allow_unsafe=True to any lookups that may be expected to contain data that may be run through the templating engine late. env: [] ini: - {key: allow_unsafe_lookups, section: defaults} type: boolean version_added: "2.2.3" deprecated: why: This option is no longer used in the Ansible Core code base. version: "2.23" alternatives: Lookup plugins are responsible for tagging strings containing templates to allow evaluation as a template. DEFAULT_ASK_PASS: name: Ask for the login password default: False description: - This controls whether an Ansible playbook should prompt for a login password. If using SSH keys for authentication, you probably do not need to change this setting. env: [{name: ANSIBLE_ASK_PASS}] ini: - {key: ask_pass, section: defaults} type: boolean yaml: {key: defaults.ask_pass} DEFAULT_ASK_VAULT_PASS: name: Ask for the vault password(s) default: False description: - This controls whether an Ansible playbook should prompt for a vault password. env: [{name: ANSIBLE_ASK_VAULT_PASS}] ini: - {key: ask_vault_pass, section: defaults} type: boolean DEFAULT_BECOME: name: Enable privilege escalation (become) default: False description: Toggles the use of privilege escalation, allowing you to 'become' another user after login. env: [{name: ANSIBLE_BECOME}] ini: - {key: become, section: privilege_escalation} type: boolean DEFAULT_BECOME_ASK_PASS: name: Ask for the privilege escalation (become) password default: False description: Toggle to prompt for privilege escalation password. env: [{name: ANSIBLE_BECOME_ASK_PASS}] ini: - {key: become_ask_pass, section: privilege_escalation} type: boolean DEFAULT_BECOME_METHOD: name: Choose privilege escalation method default: 'sudo' description: Privilege escalation method to use when `become` is enabled. env: [{name: ANSIBLE_BECOME_METHOD}] ini: - {section: privilege_escalation, key: become_method} DEFAULT_BECOME_EXE: name: Choose 'become' executable default: ~ description: 'executable to use for privilege escalation, otherwise Ansible will depend on PATH.' env: [{name: ANSIBLE_BECOME_EXE}] ini: - {key: become_exe, section: privilege_escalation} DEFAULT_BECOME_FLAGS: name: Set 'become' executable options default: '' description: Flags to pass to the privilege escalation executable. env: [{name: ANSIBLE_BECOME_FLAGS}] ini: - {key: become_flags, section: privilege_escalation} BECOME_PLUGIN_PATH: name: Become plugins path default: '{{ ANSIBLE_HOME ~ "/plugins/become:/usr/share/ansible/plugins/become" }}' description: Colon-separated paths in which Ansible will search for Become Plugins. env: [{name: ANSIBLE_BECOME_PLUGINS}] ini: - {key: become_plugins, section: defaults} type: pathspec version_added: "2.8" DEFAULT_BECOME_USER: # FIXME: should really be blank and make -u passing optional depending on it name: Set the user you 'become' via privilege escalation default: root description: The user your login/remote user 'becomes' when using privilege escalation, most systems will use 'root' when no user is specified. env: [{name: ANSIBLE_BECOME_USER}] ini: - {key: become_user, section: privilege_escalation} yaml: {key: become.user} DEFAULT_CACHE_PLUGIN_PATH: name: Cache Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/cache:/usr/share/ansible/plugins/cache" }}' description: Colon-separated paths in which Ansible will search for Cache Plugins. env: [{name: ANSIBLE_CACHE_PLUGINS}] ini: - {key: cache_plugins, section: defaults} type: pathspec DEFAULT_CALLBACK_PLUGIN_PATH: name: Callback Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/callback:/usr/share/ansible/plugins/callback" }}' description: Colon-separated paths in which Ansible will search for Callback Plugins. env: [{name: ANSIBLE_CALLBACK_PLUGINS}] ini: - {key: callback_plugins, section: defaults} type: pathspec yaml: {key: plugins.callback.path} CALLBACKS_ENABLED: name: Enable callback plugins that require it. default: [] description: - "List of enabled callbacks, not all callbacks need enabling, but many of those shipped with Ansible do as we don't want them activated by default." env: - name: ANSIBLE_CALLBACKS_ENABLED version_added: '2.11' ini: - key: callbacks_enabled section: defaults version_added: '2.11' type: list DEFAULT_CLICONF_PLUGIN_PATH: name: Cliconf Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/cliconf:/usr/share/ansible/plugins/cliconf" }}' description: Colon-separated paths in which Ansible will search for Cliconf Plugins. env: [{name: ANSIBLE_CLICONF_PLUGINS}] ini: - {key: cliconf_plugins, section: defaults} type: pathspec DEFAULT_CONNECTION_PLUGIN_PATH: name: Connection Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/connection:/usr/share/ansible/plugins/connection" }}' description: Colon-separated paths in which Ansible will search for Connection Plugins. env: [{name: ANSIBLE_CONNECTION_PLUGINS}] ini: - {key: connection_plugins, section: defaults} type: pathspec yaml: {key: plugins.connection.path} DEFAULT_DEBUG: name: Debug mode default: False description: - "Toggles debug output in Ansible. This is *very* verbose and can hinder multiprocessing. Debug output can also include secret information despite no_log settings being enabled, which means debug mode should not be used in production." env: [{name: ANSIBLE_DEBUG}] ini: - {key: debug, section: defaults} type: boolean DEFAULT_EXECUTABLE: name: Target shell executable default: /bin/sh description: - "This indicates the command to use to spawn a shell under, which is required for Ansible's execution needs on a target. Users may need to change this in rare instances when shell usage is constrained, but in most cases, it may be left as is." env: [{name: ANSIBLE_EXECUTABLE}] ini: - {key: executable, section: defaults} DEFAULT_FILTER_PLUGIN_PATH: name: Jinja2 Filter Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/filter:/usr/share/ansible/plugins/filter" }}' description: Colon-separated paths in which Ansible will search for Jinja2 Filter Plugins. env: [{name: ANSIBLE_FILTER_PLUGINS}] ini: - {key: filter_plugins, section: defaults} type: pathspec DEFAULT_FORCE_HANDLERS: name: Force handlers to run after failure default: False description: - This option controls if notified handlers run on a host even if a failure occurs on that host. - When false, the handlers will not run if a failure has occurred on a host. - This can also be set per play or on the command line. See Handlers and Failure for more details. env: [{name: ANSIBLE_FORCE_HANDLERS}] ini: - {key: force_handlers, section: defaults} type: boolean version_added: "1.9.1" DEFAULT_FORKS: name: Number of task forks default: 5 description: Maximum number of forks Ansible will use to execute tasks on target hosts. env: [{name: ANSIBLE_FORKS}] ini: - {key: forks, section: defaults} type: integer DEFAULT_GATHERING: name: Gathering behaviour default: 'implicit' description: - This setting controls the default policy of fact gathering (facts discovered about remote systems). - "This option can be useful for those wishing to save fact gathering time. Both 'smart' and 'explicit' will use the cache plugin." env: [{name: ANSIBLE_GATHERING}] ini: - key: gathering section: defaults version_added: "1.6" choices: implicit: "the cache plugin will be ignored and facts will be gathered per play unless 'gather_facts: False' is set." explicit: facts will not be gathered unless directly requested in the play. smart: each new host that has no facts discovered will be scanned, but if the same host is addressed in multiple plays it will not be contacted again in the run. DEFAULT_HASH_BEHAVIOUR: name: Hash merge behaviour default: replace type: string choices: replace: Any variable that is defined more than once is overwritten using the order from variable precedence rules (highest wins). merge: Any dictionary variable will be recursively merged with new definitions across the different variable definition sources. description: - This setting controls how duplicate definitions of dictionary variables (aka hash, map, associative array) are handled in Ansible. - This does not affect variables whose values are scalars (integers, strings) or arrays. - "**WARNING**, changing this setting is not recommended as this is fragile and makes your content (plays, roles, collections) nonportable, leading to continual confusion and misuse. Don't change this setting unless you think you have an absolute need for it." - We recommend avoiding reusing variable names and relying on the ``combine`` filter and ``vars`` and ``varnames`` lookups to create merged versions of the individual variables. In our experience, this is rarely needed and is a sign that too much complexity has been introduced into the data structures and plays. - For some uses you can also look into custom vars_plugins to merge on input, even substituting the default ``host_group_vars`` that is in charge of parsing the ``host_vars/`` and ``group_vars/`` directories. Most users of this setting are only interested in inventory scope, but the setting itself affects all sources and makes debugging even harder. - All playbooks and roles in the official examples repos assume the default for this setting. - Changing the setting to ``merge`` applies across variable sources, but many sources will internally still overwrite the variables. For example ``include_vars`` will dedupe variables internally before updating Ansible, with 'last defined' overwriting previous definitions in same file. - The Ansible project recommends you **avoid ``merge`` for new projects.** - It is the intention of the Ansible developers to eventually deprecate and remove this setting, but it is being kept as some users do heavily rely on it. New projects should **avoid 'merge'**. env: [{name: ANSIBLE_HASH_BEHAVIOUR}] ini: - {key: hash_behaviour, section: defaults} DEFAULT_HOST_LIST: name: Inventory Source default: [/etc/ansible/hosts] description: Comma-separated list of Ansible inventory sources env: - name: ANSIBLE_INVENTORY expand_relative_paths: True ini: - key: inventory section: defaults type: pathlist yaml: {key: defaults.inventory} DEFAULT_HTTPAPI_PLUGIN_PATH: name: HttpApi Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/httpapi:/usr/share/ansible/plugins/httpapi" }}' description: Colon-separated paths in which Ansible will search for HttpApi Plugins. env: [{name: ANSIBLE_HTTPAPI_PLUGINS}] ini: - {key: httpapi_plugins, section: defaults} type: pathspec DEFAULT_INTERNAL_POLL_INTERVAL: name: Internal poll interval default: 0.001 env: [] ini: - {key: internal_poll_interval, section: defaults} type: float version_added: "2.2" description: - This sets the interval (in seconds) of Ansible internal processes polling each other. Lower values improve performance with large playbooks at the expense of extra CPU load. Higher values are more suitable for Ansible usage in automation scenarios when UI responsiveness is not required but CPU usage might be a concern. - "The default corresponds to the value hardcoded in Ansible <= 2.1" DEFAULT_INVENTORY_PLUGIN_PATH: name: Inventory Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/inventory:/usr/share/ansible/plugins/inventory" }}' description: Colon-separated paths in which Ansible will search for Inventory Plugins. env: [{name: ANSIBLE_INVENTORY_PLUGINS}] ini: - {key: inventory_plugins, section: defaults} type: pathspec DEFAULT_JINJA2_EXTENSIONS: name: Enabled Jinja2 extensions default: [] type: list description: - This is a developer-specific feature that allows enabling additional Jinja2 extensions. - "See the Jinja2 documentation for details. If you do not know what these do, you probably don't need to change this setting :)" env: [{name: ANSIBLE_JINJA2_EXTENSIONS}] ini: - {key: jinja2_extensions, section: defaults} deprecated: why: Jinja2 extensions have been deprecated version: "2.23" alternatives: Ansible-supported Jinja plugins (tests, filters, lookups) DEFAULT_JINJA2_NATIVE: name: Use Jinja2's NativeEnvironment for templating default: True description: This option preserves variable types during template operations. env: [{name: ANSIBLE_JINJA2_NATIVE}] ini: - {key: jinja2_native, section: defaults} type: boolean yaml: {key: jinja2_native} version_added: 2.7 deprecated: why: This option is no longer used in the Ansible Core code base. version: "2.23" alternatives: Jinja2 native mode is now the default and only option. DEFAULT_KEEP_REMOTE_FILES: name: Keep remote files default: False description: - Enables/disables the cleaning up of the temporary files Ansible used to execute the tasks on the remote. - If this option is enabled it will disable ``ANSIBLE_PIPELINING``. env: [{name: ANSIBLE_KEEP_REMOTE_FILES}] ini: - {key: keep_remote_files, section: defaults} type: boolean DEFAULT_LIBVIRT_LXC_NOSECLABEL: name: No security label on Lxc default: False description: - "This setting causes libvirt to connect to LXC containers by passing ``--noseclabel`` parameter to ``virsh`` command. This is necessary when running on systems which do not have SELinux." env: - name: ANSIBLE_LIBVIRT_LXC_NOSECLABEL ini: - {key: libvirt_lxc_noseclabel, section: selinux} type: boolean version_added: "2.1" deprecated: why: This option was moved to the plugin itself version: "2.22" alternatives: Use the option from the plugin itself. DEFAULT_LOAD_CALLBACK_PLUGINS: name: Load callbacks for adhoc default: False description: - Controls whether callback plugins are loaded when running /usr/bin/ansible. This may be used to log activity from the command line, send notifications, and so on. Callback plugins are always loaded for ``ansible-playbook``. env: [{name: ANSIBLE_LOAD_CALLBACK_PLUGINS}] ini: - {key: bin_ansible_callbacks, section: defaults} type: boolean version_added: "1.8" DEFAULT_LOCAL_TMP: name: Controller temporary directory default: '{{ ANSIBLE_HOME ~ "/tmp" }}' description: Temporary directory for Ansible to use on the controller. env: [{name: ANSIBLE_LOCAL_TEMP}] ini: - {key: local_tmp, section: defaults} type: tmppath DEFAULT_LOG_PATH: name: Ansible log file path default: ~ description: - File to which Ansible will log on the controller. - When not set the logging is disabled. env: [{name: ANSIBLE_LOG_PATH}] ini: - {key: log_path, section: defaults} type: path DEFAULT_LOG_FILTER: name: Name filters for python logger default: [] description: List of logger names to filter out of the log file. env: [{name: ANSIBLE_LOG_FILTER}] ini: - {key: log_filter, section: defaults} type: list DEFAULT_LOOKUP_PLUGIN_PATH: name: Lookup Plugins Path description: Colon-separated paths in which Ansible will search for Lookup Plugins. default: '{{ ANSIBLE_HOME ~ "/plugins/lookup:/usr/share/ansible/plugins/lookup" }}' env: [{name: ANSIBLE_LOOKUP_PLUGINS}] ini: - {key: lookup_plugins, section: defaults} type: pathspec yaml: {key: defaults.lookup_plugins} DEFAULT_MANAGED_STR: name: Ansible managed default: 'Ansible managed' description: Sets the macro for the 'ansible_managed' variable available for :ref:`ansible_collections.ansible.builtin.template_module` and :ref:`ansible_collections.ansible.windows.win_template_module`. This is only relevant to those two modules. env: [] ini: - {key: ansible_managed, section: defaults} yaml: {key: defaults.ansible_managed} DEFAULT_MODULE_ARGS: name: Adhoc default arguments default: ~ description: - This sets the default arguments to pass to the ``ansible`` adhoc binary if no ``-a`` is specified. env: [{name: ANSIBLE_MODULE_ARGS}] ini: - {key: module_args, section: defaults} DEFAULT_MODULE_COMPRESSION: name: Python module compression default: ZIP_DEFLATED description: Compression scheme to use when transferring Python modules to the target. env: [] ini: - {key: module_compression, section: defaults} vars: - name: ansible_module_compression DEFAULT_MODULE_NAME: name: Default adhoc module default: command description: "Module to use with the ``ansible`` AdHoc command, if none is specified via ``-m``." env: [] ini: - {key: module_name, section: defaults} DEFAULT_MODULE_PATH: name: Modules Path description: Colon-separated paths in which Ansible will search for Modules. default: '{{ ANSIBLE_HOME ~ "/plugins/modules:/usr/share/ansible/plugins/modules" }}' env: [{name: ANSIBLE_LIBRARY}] ini: - {key: library, section: defaults} type: pathspec DEFAULT_MODULE_UTILS_PATH: name: Module Utils Path description: Colon-separated paths in which Ansible will search for Module utils files, which are shared by modules. default: '{{ ANSIBLE_HOME ~ "/plugins/module_utils:/usr/share/ansible/plugins/module_utils" }}' env: [{name: ANSIBLE_MODULE_UTILS}] ini: - {key: module_utils, section: defaults} type: pathspec DEFAULT_NETCONF_PLUGIN_PATH: name: Netconf Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/netconf:/usr/share/ansible/plugins/netconf" }}' description: Colon-separated paths in which Ansible will search for Netconf Plugins. env: [{name: ANSIBLE_NETCONF_PLUGINS}] ini: - {key: netconf_plugins, section: defaults} type: pathspec DEFAULT_NO_LOG: name: No log default: False description: "Toggle Ansible's display and logging of task details, mainly used to avoid security disclosures." env: [{name: ANSIBLE_NO_LOG}] ini: - {key: no_log, section: defaults} type: boolean DEFAULT_NO_TARGET_SYSLOG: name: No syslog on target default: False description: - Toggle Ansible logging to syslog on the target when it executes tasks. On Windows hosts, this will disable a newer style PowerShell modules from writing to the event log. env: [{name: ANSIBLE_NO_TARGET_SYSLOG}] ini: - {key: no_target_syslog, section: defaults} vars: - name: ansible_no_target_syslog version_added: '2.10' type: boolean yaml: {key: defaults.no_target_syslog} DEFAULT_NULL_REPRESENTATION: name: Represent a null default: ~ description: What templating should return as a 'null' value. When not set it will let Jinja2 decide. env: [{name: ANSIBLE_NULL_REPRESENTATION}] ini: - {key: null_representation, section: defaults} type: raw deprecated: why: This option is no longer used in the Ansible Core code base. version: "2.23" alternatives: There is no alternative at the moment. A different mechanism would have to be implemented in the current code base. DEFAULT_POLL_INTERVAL: name: Async poll interval default: 15 description: - For asynchronous tasks in Ansible (covered in Asynchronous Actions and Polling), this is how often to check back on the status of those tasks when an explicit poll interval is not supplied. The default is a reasonably moderate 15 seconds which is a tradeoff between checking in frequently and providing a quick turnaround when something may have completed. env: [{name: ANSIBLE_POLL_INTERVAL}] ini: - {key: poll_interval, section: defaults} type: integer DEFAULT_PRIVATE_KEY_FILE: name: Private key file default: ~ description: - Option for connections using a certificate or key file to authenticate, rather than an agent or passwords, you can set the default value here to avoid re-specifying ``--private-key`` with every invocation. env: [{name: ANSIBLE_PRIVATE_KEY_FILE}] ini: - {key: private_key_file, section: defaults} type: path DEFAULT_PRIVATE_ROLE_VARS: name: Private role variables default: False description: - By default, imported roles publish their variables to the play and other roles, this setting can avoid that. - This was introduced as a way to reset role variables to default values if a role is used more than once in a playbook. - Starting in version '2.17' M(ansible.builtin.include_roles) and M(ansible.builtin.import_roles) can individually override this via the C(public) parameter. - Included roles only make their variables public at execution, unlike imported roles which happen at playbook compile time. env: [{name: ANSIBLE_PRIVATE_ROLE_VARS}] ini: - {key: private_role_vars, section: defaults} type: boolean yaml: {key: defaults.private_role_vars} DEFAULT_REMOTE_PORT: name: Remote port default: ~ description: Port to use in remote connections, when blank it will use the connection plugin default. env: [{name: ANSIBLE_REMOTE_PORT}] ini: - {key: remote_port, section: defaults} type: integer yaml: {key: defaults.remote_port} DEFAULT_REMOTE_USER: name: Login/Remote User description: - Sets the login user for the target machines - "When blank it uses the connection plugin's default, normally the user currently executing Ansible." env: [{name: ANSIBLE_REMOTE_USER}] ini: - {key: remote_user, section: defaults} DEFAULT_ROLES_PATH: name: Roles path default: '{{ ANSIBLE_HOME ~ "/roles:/usr/share/ansible/roles:/etc/ansible/roles" }}' description: Colon-separated paths in which Ansible will search for Roles. env: [{name: ANSIBLE_ROLES_PATH}] expand_relative_paths: True ini: - {key: roles_path, section: defaults} type: pathspec yaml: {key: defaults.roles_path} DEFAULT_SELINUX_SPECIAL_FS: name: Problematic file systems default: [fuse, nfs, vboxsf, ramfs, 9p, vfat] description: - "Some filesystems do not support safe operations and/or return inconsistent errors, this setting makes Ansible 'tolerate' those in the list without causing fatal errors." - Data corruption may occur and writes are not always verified when a filesystem is in the list. env: - name: ANSIBLE_SELINUX_SPECIAL_FS version_added: "2.9" ini: - {key: special_context_filesystems, section: selinux} type: list DEFAULT_STDOUT_CALLBACK: name: Main display callback plugin default: default description: - "Set the main callback used to display Ansible output. You can only have one at a time." - You can have many other callbacks, but just one can be in charge of stdout. - See :ref:`callback_plugins` for a list of available options. env: [{name: ANSIBLE_STDOUT_CALLBACK}] ini: - {key: stdout_callback, section: defaults} EDITOR: name: editor application to use default: vi description: - for the cases in which Ansible needs to return a file within an editor, this chooses the application to use. ini: - section: defaults key: editor version_added: '2.15' env: - name: ANSIBLE_EDITOR version_added: '2.15' - name: EDITOR ENABLE_TASK_DEBUGGER: name: Whether to enable the task debugger default: False description: - Whether or not to enable the task debugger, this previously was done as a strategy plugin. - Now all strategy plugins can inherit this behavior. The debugger defaults to activating when - a task is failed on unreachable. Use the debugger keyword for more flexibility. type: boolean env: [{name: ANSIBLE_ENABLE_TASK_DEBUGGER}] ini: - {key: enable_task_debugger, section: defaults} version_added: "2.5" TASK_DEBUGGER_IGNORE_ERRORS: name: Whether a failed task with ignore_errors=True will still invoke the debugger default: True description: - This option defines whether the task debugger will be invoked on a failed task when ignore_errors=True is specified. - True specifies that the debugger will honor ignore_errors, and False will not honor ignore_errors. type: boolean env: [{name: ANSIBLE_TASK_DEBUGGER_IGNORE_ERRORS}] ini: - {key: task_debugger_ignore_errors, section: defaults} version_added: "2.7" DEFAULT_STRATEGY: name: Implied strategy default: 'linear' description: Set the default strategy used for plays. env: [{name: ANSIBLE_STRATEGY}] ini: - {key: strategy, section: defaults} version_added: "2.3" DEFAULT_STRATEGY_PLUGIN_PATH: name: Strategy Plugins Path description: Colon-separated paths in which Ansible will search for Strategy Plugins. default: '{{ ANSIBLE_HOME ~ "/plugins/strategy:/usr/share/ansible/plugins/strategy" }}' env: [{name: ANSIBLE_STRATEGY_PLUGINS}] ini: - {key: strategy_plugins, section: defaults} type: pathspec DEFAULT_SU: default: False description: 'Toggle the use of "su" for tasks.' env: [{name: ANSIBLE_SU}] ini: - {key: su, section: defaults} type: boolean yaml: {key: defaults.su} DEFAULT_SYSLOG_FACILITY: name: syslog facility default: LOG_USER description: Syslog facility to use when Ansible logs to the remote target. env: [{name: ANSIBLE_SYSLOG_FACILITY}] ini: - {key: syslog_facility, section: defaults} DEFAULT_TERMINAL_PLUGIN_PATH: name: Terminal Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/terminal:/usr/share/ansible/plugins/terminal" }}' description: Colon-separated paths in which Ansible will search for Terminal Plugins. env: [{name: ANSIBLE_TERMINAL_PLUGINS}] ini: - {key: terminal_plugins, section: defaults} type: pathspec DEFAULT_TEST_PLUGIN_PATH: name: Jinja2 Test Plugins Path description: Colon-separated paths in which Ansible will search for Jinja2 Test Plugins. default: '{{ ANSIBLE_HOME ~ "/plugins/test:/usr/share/ansible/plugins/test" }}' env: [{name: ANSIBLE_TEST_PLUGINS}] ini: - {key: test_plugins, section: defaults} type: pathspec DEFAULT_TIMEOUT: name: Connection timeout default: 10 description: This is the default timeout for connection plugins to use. env: [{name: ANSIBLE_TIMEOUT}] ini: - {key: timeout, section: defaults} type: integer DEFAULT_TRANSPORT: name: Connection plugin default: ssh description: - Can be any connection plugin available to your ansible installation. - There is also a (DEPRECATED) special 'smart' option, that will toggle between 'ssh' and 'paramiko' depending on controller OS and ssh versions. env: [{name: ANSIBLE_TRANSPORT}] ini: - {key: transport, section: defaults} DEFAULT_UNDEFINED_VAR_BEHAVIOR: name: Jinja2 fail on undefined default: True version_added: "1.3" description: - When True, this causes ansible templating to fail steps that reference variable names that are likely typoed. - "Otherwise, any '{{ template_expression }}' that contains undefined variables will be rendered in a template or ansible action line exactly as written." env: [{name: ANSIBLE_ERROR_ON_UNDEFINED_VARS}] ini: - {key: error_on_undefined_vars, section: defaults} type: boolean deprecated: why: This option is no longer used in the Ansible Core code base. version: "2.23" alternatives: There is no alternative at the moment. A different mechanism would have to be implemented in the current code base. DEFAULT_VARS_PLUGIN_PATH: name: Vars Plugins Path default: '{{ ANSIBLE_HOME ~ "/plugins/vars:/usr/share/ansible/plugins/vars" }}' description: Colon-separated paths in which Ansible will search for Vars Plugins. env: [{name: ANSIBLE_VARS_PLUGINS}] ini: - {key: vars_plugins, section: defaults} type: pathspec DEFAULT_VAULT_ID_MATCH: name: Force vault id match default: False description: 'If true, decrypting vaults with a vault id will only try the password from the matching vault-id.' env: [{name: ANSIBLE_VAULT_ID_MATCH}] ini: - {key: vault_id_match, section: defaults} yaml: {key: defaults.vault_id_match} DEFAULT_VAULT_IDENTITY: name: Vault id label default: default description: 'The label to use for the default vault id label in cases where a vault id label is not provided.' env: [{name: ANSIBLE_VAULT_IDENTITY}] ini: - {key: vault_identity, section: defaults} yaml: {key: defaults.vault_identity} VAULT_ENCRYPT_SALT: name: Vault salt to use for encryption default: ~ description: 'The salt to use for the vault encryption. If it is not provided, a random salt will be used.' env: [{name: ANSIBLE_VAULT_ENCRYPT_SALT}] ini: - {key: vault_encrypt_salt, section: defaults} version_added: '2.15' DEFAULT_VAULT_ENCRYPT_IDENTITY: name: Vault id to use for encryption description: 'The vault_id to use for encrypting by default. If multiple vault_ids are provided, this specifies which to use for encryption. The ``--encrypt-vault-id`` CLI option overrides the configured value.' env: [{name: ANSIBLE_VAULT_ENCRYPT_IDENTITY}] ini: - {key: vault_encrypt_identity, section: defaults} yaml: {key: defaults.vault_encrypt_identity} DEFAULT_VAULT_IDENTITY_LIST: name: Default vault ids default: [] description: 'A list of vault-ids to use by default. Equivalent to multiple ``--vault-id`` args. Vault-ids are tried in order.' env: [{name: ANSIBLE_VAULT_IDENTITY_LIST}] ini: - {key: vault_identity_list, section: defaults} type: list yaml: {key: defaults.vault_identity_list} DEFAULT_VAULT_PASSWORD_FILE: name: Vault password file default: ~ description: - 'The vault password file to use. Equivalent to ``--vault-password-file`` or ``--vault-id``.' - If executable, it will be run and the resulting stdout will be used as the password. env: [{name: ANSIBLE_VAULT_PASSWORD_FILE}] ini: - {key: vault_password_file, section: defaults} type: path yaml: {key: defaults.vault_password_file} DEFAULT_VERBOSITY: name: Verbosity default: 0 description: Sets the default verbosity, equivalent to the number of ``-v`` passed in the command line. env: [{name: ANSIBLE_VERBOSITY}] ini: - {key: verbosity, section: defaults} type: integer DEPRECATION_WARNINGS: name: Deprecation messages default: True description: "Toggle to control the showing of deprecation warnings" env: [{name: ANSIBLE_DEPRECATION_WARNINGS}] ini: - {key: deprecation_warnings, section: defaults} type: boolean vars: - name: ansible_deprecation_warnings version_added: '2.19' DEVEL_WARNING: name: Running devel warning default: True description: Toggle to control showing warnings related to running devel. env: [{name: ANSIBLE_DEVEL_WARNING}] ini: - {key: devel_warning, section: defaults} type: boolean DIFF_ALWAYS: name: Show differences default: False description: Configuration toggle to tell modules to show differences when in 'changed' status, equivalent to ``--diff``. env: [{name: ANSIBLE_DIFF_ALWAYS}] ini: - {key: always, section: diff} type: bool DIFF_CONTEXT: name: Difference context default: 3 description: Number of lines of context to show when displaying the differences between files. env: [{name: ANSIBLE_DIFF_CONTEXT}] ini: - {key: context, section: diff} type: integer DISPLAY_ARGS_TO_STDOUT: name: Show task arguments default: False description: - "Normally ``ansible-playbook`` will print a header for each task that is run. These headers will contain the name: field from the task if you specified one. If you didn't then ``ansible-playbook`` uses the task's action to help you tell which task is presently running. Sometimes you run many of the same action and so you want more information about the task to differentiate it from others of the same action. If you set this variable to True in the config then ``ansible-playbook`` will also include the task's arguments in the header." - "This setting defaults to False because there is a chance that you have sensitive values in your parameters and you do not want those to be printed." - "If you set this to True you should be sure that you have secured your environment's stdout (no one can shoulder surf your screen and you aren't saving stdout to an insecure file) or made sure that all of your playbooks explicitly added the ``no_log: True`` parameter to tasks that have sensitive values :ref:`keep_secret_data` for more information." env: [{name: ANSIBLE_DISPLAY_ARGS_TO_STDOUT}] ini: - {key: display_args_to_stdout, section: defaults} type: boolean version_added: "2.1" DISPLAY_SKIPPED_HOSTS: name: Show skipped results default: True description: "Toggle to control displaying skipped task/host entries in a task in the default callback." env: - name: ANSIBLE_DISPLAY_SKIPPED_HOSTS ini: - {key: display_skipped_hosts, section: defaults} type: boolean DISPLAY_TRACEBACK: name: Control traceback display default: [never] description: When to include tracebacks in extended error messages env: - name: ANSIBLE_DISPLAY_TRACEBACK ini: - {key: display_traceback, section: defaults} type: list choices: - error - warning - deprecated - deprecated_value - always - never version_added: "2.19" DOCSITE_ROOT_URL: name: Root docsite URL default: https://docs.ansible.com/ansible-core/ description: Root docsite URL used to generate docs URLs in warning/error text; must be an absolute URL with a valid scheme and trailing slash. ini: - {key: docsite_root_url, section: defaults} version_added: "2.8" DUPLICATE_YAML_DICT_KEY: name: Controls ansible behaviour when finding duplicate keys in YAML. default: warn description: - By default, Ansible will issue a warning when a duplicate dict key is encountered in YAML. - These warnings can be silenced by adjusting this setting to False. env: [{name: ANSIBLE_DUPLICATE_YAML_DICT_KEY}] ini: - {key: duplicate_dict_key, section: defaults} type: string choices: &basic_error2 error: issue a 'fatal' error and stop the play warn: issue a warning but continue ignore: just continue silently version_added: "2.9" ERROR_ON_MISSING_HANDLER: name: Missing handler error default: True description: "Toggle to allow missing handlers to become a warning instead of an error when notifying." env: [{name: ANSIBLE_ERROR_ON_MISSING_HANDLER}] ini: - {key: error_on_missing_handler, section: defaults} type: boolean CONNECTION_FACTS_MODULES: name: Map of connections to fact modules default: # use ansible.legacy names on unqualified facts modules to allow library/ overrides asa: ansible.legacy.asa_facts cisco.asa.asa: cisco.asa.asa_facts eos: ansible.legacy.eos_facts arista.eos.eos: arista.eos.eos_facts frr: ansible.legacy.frr_facts frr.frr.frr: frr.frr.frr_facts ios: ansible.legacy.ios_facts cisco.ios.ios: cisco.ios.ios_facts iosxr: ansible.legacy.iosxr_facts cisco.iosxr.iosxr: cisco.iosxr.iosxr_facts junos: ansible.legacy.junos_facts junipernetworks.junos.junos: junipernetworks.junos.junos_facts nxos: ansible.legacy.nxos_facts cisco.nxos.nxos: cisco.nxos.nxos_facts vyos: ansible.legacy.vyos_facts vyos.vyos.vyos: vyos.vyos.vyos_facts exos: ansible.legacy.exos_facts extreme.exos.exos: extreme.exos.exos_facts slxos: ansible.legacy.slxos_facts extreme.slxos.slxos: extreme.slxos.slxos_facts voss: ansible.legacy.voss_facts extreme.voss.voss: extreme.voss.voss_facts ironware: ansible.legacy.ironware_facts community.network.ironware: community.network.ironware_facts description: "Which modules to run during a play's fact gathering stage based on connection" type: dict FACTS_MODULES: name: Gather Facts Modules default: - smart description: - "Which modules to run during a play's fact gathering stage, using the default of 'smart' will try to figure it out based on connection type." - "If adding your own modules but you still want to use the default Ansible facts, you will want to include 'setup' or corresponding network module to the list (if you add 'smart', Ansible will also figure it out)." - "This does not affect explicit calls to the 'setup' module, but does always affect the 'gather_facts' action (implicit or explicit)." env: [{name: ANSIBLE_FACTS_MODULES}] ini: - {key: facts_modules, section: defaults} type: list vars: - name: ansible_facts_modules GALAXY_IGNORE_CERTS: name: Galaxy validate certs description: - If set to yes, ansible-galaxy will not validate TLS certificates. This can be useful for testing against a server with a self-signed certificate. env: [{name: ANSIBLE_GALAXY_IGNORE}] ini: - {key: ignore_certs, section: galaxy} type: boolean GALAXY_SERVER_TIMEOUT: name: Default timeout to use for API calls description: - The default timeout for Galaxy API calls. Galaxy servers that don't configure a specific timeout will fall back to this value. env: [{name: ANSIBLE_GALAXY_SERVER_TIMEOUT}] default: 60 ini: - {key: server_timeout, section: galaxy} type: int GALAXY_ROLE_SKELETON: name: Galaxy role skeleton directory description: Role skeleton directory to use as a template for the ``init`` action in ``ansible-galaxy``/``ansible-galaxy role``, same as ``--role-skeleton``. env: [{name: ANSIBLE_GALAXY_ROLE_SKELETON}] ini: - {key: role_skeleton, section: galaxy} type: path GALAXY_ROLE_SKELETON_IGNORE: name: Galaxy role skeleton ignore default: ["^.git$", "^.*/.git_keep$"] description: patterns of files to ignore inside a Galaxy role or collection skeleton directory. env: [{name: ANSIBLE_GALAXY_ROLE_SKELETON_IGNORE}] ini: - {key: role_skeleton_ignore, section: galaxy} type: list GALAXY_COLLECTION_SKELETON: name: Galaxy collection skeleton directory description: Collection skeleton directory to use as a template for the ``init`` action in ``ansible-galaxy collection``, same as ``--collection-skeleton``. env: [{name: ANSIBLE_GALAXY_COLLECTION_SKELETON}] ini: - {key: collection_skeleton, section: galaxy} type: path GALAXY_COLLECTION_SKELETON_IGNORE: name: Galaxy collection skeleton ignore default: ["^.git$", "^.*/.git_keep$"] description: patterns of files to ignore inside a Galaxy collection skeleton directory. env: [{name: ANSIBLE_GALAXY_COLLECTION_SKELETON_IGNORE}] ini: - {key: collection_skeleton_ignore, section: galaxy} type: list GALAXY_COLLECTIONS_PATH_WARNING: name: "ansible-galaxy collection install collections path warnings" description: "whether ``ansible-galaxy collection install`` should warn about ``--collections-path`` missing from configured :ref:`collections_paths`." default: true type: bool env: [{name: ANSIBLE_GALAXY_COLLECTIONS_PATH_WARNING}] ini: - {key: collections_path_warning, section: galaxy} version_added: "2.16" GALAXY_SERVER: default: https://galaxy.ansible.com description: "URL to prepend when roles don't specify the full URI, assume they are referencing this server as the source." env: [{name: ANSIBLE_GALAXY_SERVER}] ini: - {key: server, section: galaxy} yaml: {key: galaxy.server} GALAXY_SERVER_LIST: description: - A list of Galaxy servers to use when installing a collection. - The value corresponds to the config ini header ``[galaxy_server.{{item}}]`` which defines the server details. - 'See :ref:`galaxy_server_config` for more details on how to define a Galaxy server.' - The order of servers in this list is used as the order in which a collection is resolved. - Setting this config option will ignore the :ref:`galaxy_server` config option. env: [{name: ANSIBLE_GALAXY_SERVER_LIST}] ini: - {key: server_list, section: galaxy} type: list version_added: "2.9" GALAXY_TOKEN_PATH: default: '{{ ANSIBLE_HOME ~ "/galaxy_token" }}' description: "Local path to galaxy access token file" env: [{name: ANSIBLE_GALAXY_TOKEN_PATH}] ini: - {key: token_path, section: galaxy} type: path version_added: "2.9" GALAXY_DISPLAY_PROGRESS: default: ~ description: - Some steps in ``ansible-galaxy`` display a progress wheel which can cause issues on certain displays or when outputting the stdout to a file. - This config option controls whether the display wheel is shown or not. - The default is to show the display wheel if stdout has a tty. env: [{name: ANSIBLE_GALAXY_DISPLAY_PROGRESS}] ini: - {key: display_progress, section: galaxy} type: bool version_added: "2.10" GALAXY_CACHE_DIR: default: '{{ ANSIBLE_HOME ~ "/galaxy_cache" }}' description: - The directory that stores cached responses from a Galaxy server. - This is only used by the ``ansible-galaxy collection install`` and ``download`` commands. - Cache files inside this dir will be ignored if they are world writable. env: - name: ANSIBLE_GALAXY_CACHE_DIR ini: - section: galaxy key: cache_dir type: path version_added: '2.11' GALAXY_DISABLE_GPG_VERIFY: default: false type: bool env: - name: ANSIBLE_GALAXY_DISABLE_GPG_VERIFY ini: - section: galaxy key: disable_gpg_verify description: - Disable GPG signature verification during collection installation. version_added: '2.13' GALAXY_GPG_KEYRING: type: path env: - name: ANSIBLE_GALAXY_GPG_KEYRING ini: - section: galaxy key: gpg_keyring description: - Configure the keyring used for GPG signature verification during collection installation and verification. version_added: '2.13' GALAXY_IGNORE_INVALID_SIGNATURE_STATUS_CODES: type: list env: - name: ANSIBLE_GALAXY_IGNORE_SIGNATURE_STATUS_CODES ini: - section: galaxy key: ignore_signature_status_codes description: - A list of GPG status codes to ignore during GPG signature verification. See L(https://github.com/gpg/gnupg/blob/master/doc/DETAILS#general-status-codes) for status code descriptions. - If fewer signatures successfully verify the collection than `GALAXY_REQUIRED_VALID_SIGNATURE_COUNT`, signature verification will fail even if all error codes are ignored. choices: - EXPSIG - EXPKEYSIG - REVKEYSIG - BADSIG - ERRSIG - NO_PUBKEY - MISSING_PASSPHRASE - BAD_PASSPHRASE - NODATA - UNEXPECTED - ERROR - FAILURE - BADARMOR - KEYEXPIRED - KEYREVOKED - NO_SECKEY GALAXY_REQUIRED_VALID_SIGNATURE_COUNT: type: str default: 1 env: - name: ANSIBLE_GALAXY_REQUIRED_VALID_SIGNATURE_COUNT ini: - section: galaxy key: required_valid_signature_count description: - The number of signatures that must be successful during GPG signature verification while installing or verifying collections. - This should be a positive integer or all to indicate all signatures must successfully validate the collection. - Prepend + to the value to fail if no valid signatures are found for the collection. GALAXY_COLLECTION_IMPORT_POLL_INTERVAL: description: - The initial interval in seconds for polling the import status of a collection. - This interval increases exponentially based on the :ref:`galaxy_collection_import_poll_factor`, with a maximum delay of 30 seconds. type: float default: 2.0 env: - name: ANSIBLE_GALAXY_COLLECTION_IMPORT_POLL_INTERVAL version_added: '2.18' GALAXY_COLLECTION_IMPORT_POLL_FACTOR: description: - The multiplier used to increase the :ref:`galaxy_collection_import_poll_interval` when checking the collection import status. type: float default: 1.5 env: - name: ANSIBLE_GALAXY_COLLECTION_IMPORT_POLL_FACTOR version_added: "2.18" HOST_KEY_CHECKING: # NOTE: constant not in use by ssh/paramiko plugins anymore, but they do support the same configuration sources # TODO: check non ssh connection plugins for use/migration name: Toggle host/key check default: True description: - Set this to "False" if you want to avoid host key checking by the underlying connection plugin Ansible uses to connect to the host. - Please read the documentation of the specific connection plugin used for details. env: [{name: ANSIBLE_HOST_KEY_CHECKING}] ini: - {key: host_key_checking, section: defaults} type: boolean HOST_PATTERN_MISMATCH: name: Control host pattern mismatch behaviour default: 'warning' description: This setting changes the behaviour of mismatched host patterns, it allows you to force a fatal error, a warning or just ignore it. env: [{name: ANSIBLE_HOST_PATTERN_MISMATCH}] ini: - {key: host_pattern_mismatch, section: inventory} choices: <<: *basic_error version_added: "2.8" INTERPRETER_PYTHON: name: Python interpreter path (or automatic discovery behavior) used for module execution default: auto env: [{name: ANSIBLE_PYTHON_INTERPRETER}] ini: - {key: interpreter_python, section: defaults} vars: - {name: ansible_python_interpreter} version_added: "2.8" description: - Path to the Python interpreter to be used for module execution on remote targets, or an automatic discovery mode. Supported discovery modes are ``auto`` (the default), ``auto_silent``, ``auto_legacy``, and ``auto_legacy_silent``. All discovery modes match against an ordered list of well-known Python interpreter locations. The fallback behavior will issue a warning that the interpreter should be set explicitly (since interpreters installed later may change which one is used). This warning behavior can be disabled by setting ``auto_silent``. The ``auto_legacy`` modes are deprecated and behave the same as their respective ``auto`` modes. They exist for backward-compatibility with older Ansible releases that always defaulted to ``/usr/bin/python3``, which will use that interpreter if present. INTERPRETER_PYTHON_FALLBACK: name: Ordered list of Python interpreters to check for in discovery default: - python3.13 - python3.12 - python3.11 - python3.10 - python3.9 - python3.8 - /usr/bin/python3 - python3 vars: - name: ansible_interpreter_python_fallback type: list version_added: "2.8" TRANSFORM_INVALID_GROUP_CHARS: name: Transform invalid characters in group names default: 'never' description: - Make ansible transform invalid characters in group names supplied by inventory sources. env: [{name: ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS}] ini: - {key: force_valid_group_names, section: defaults} type: string choices: always: it will replace any invalid characters with '_' (underscore) and warn the user never: it will allow for the group name but warn about the issue ignore: it does the same as 'never', without issuing a warning silently: it does the same as 'always', without issuing a warning version_added: '2.8' INVALID_TASK_ATTRIBUTE_FAILED: name: Controls whether invalid attributes for a task result in errors instead of warnings default: True description: If 'false', invalid attributes for a task will result in warnings instead of errors. type: boolean env: - name: ANSIBLE_INVALID_TASK_ATTRIBUTE_FAILED ini: - key: invalid_task_attribute_failed section: defaults version_added: "2.7" INVENTORY_ANY_UNPARSED_IS_FAILED: name: Controls whether any unparsable inventory source is a fatal error default: False description: > If 'true', it is a fatal error when any given inventory source cannot be successfully parsed by any available inventory plugin; otherwise, this situation only attracts a warning. type: boolean env: [{name: ANSIBLE_INVENTORY_ANY_UNPARSED_IS_FAILED}] ini: - {key: any_unparsed_is_failed, section: inventory} version_added: "2.7" INVENTORY_ENABLED: name: Active Inventory plugins default: ['host_list', 'script', 'auto', 'yaml', 'ini', 'toml'] description: List of enabled inventory plugins, it also determines the order in which they are used. env: [{name: ANSIBLE_INVENTORY_ENABLED}] ini: - {key: enable_plugins, section: inventory} type: list INVENTORY_EXPORT: name: Set ansible-inventory into export mode default: False description: Controls if ansible-inventory will accurately reflect Ansible's view into inventory or its optimized for exporting. env: [{name: ANSIBLE_INVENTORY_EXPORT}] ini: - {key: export, section: inventory} type: bool INVENTORY_IGNORE_EXTS: name: Inventory ignore extensions default: "{{ REJECT_EXTS + ['.orig', '.cfg', '.retry'] }}" description: List of extensions to ignore when using a directory as an inventory source. env: [{name: ANSIBLE_INVENTORY_IGNORE}] ini: - {key: inventory_ignore_extensions, section: defaults} - {key: ignore_extensions, section: inventory} type: list INVENTORY_IGNORE_PATTERNS: name: Inventory ignore patterns default: [] description: List of patterns to ignore when using a directory as an inventory source. env: [{name: ANSIBLE_INVENTORY_IGNORE_REGEX}] ini: - {key: inventory_ignore_patterns, section: defaults} - {key: ignore_patterns, section: inventory} type: list INVENTORY_UNPARSED_IS_FAILED: name: Unparsed Inventory failure default: False description: > If 'true' it is a fatal error if every single potential inventory source fails to parse, otherwise, this situation will only attract a warning. env: [{name: ANSIBLE_INVENTORY_UNPARSED_FAILED}] ini: - {key: unparsed_is_failed, section: inventory} type: bool MAX_FILE_SIZE_FOR_DIFF: name: Diff maximum file size default: 104448 description: Maximum size of files to be considered for diff display. env: [{name: ANSIBLE_MAX_DIFF_SIZE}] ini: - {key: max_diff_size, section: defaults} type: int NETWORK_GROUP_MODULES: name: Network module families default: [eos, nxos, ios, iosxr, junos, enos, ce, vyos, sros, dellos9, dellos10, dellos6, asa, aruba, aireos, bigip, ironware, onyx, netconf, exos, voss, slxos] description: 'TODO: write it' env: - name: ANSIBLE_NETWORK_GROUP_MODULES ini: - {key: network_group_modules, section: defaults} type: list yaml: {key: defaults.network_group_modules} INJECT_FACTS_AS_VARS: default: True description: - Facts are available inside the `ansible_facts` variable, this setting also pushes them as their own vars in the main namespace. - Unlike inside the `ansible_facts` dictionary where the prefix `ansible_` is removed from fact names, these will have the exact names that are returned by the module. env: [{name: ANSIBLE_INJECT_FACT_VARS}] ini: - {key: inject_facts_as_vars, section: defaults} type: boolean version_added: "2.5" MODULE_IGNORE_EXTS: name: Module ignore extensions default: "{{ REJECT_EXTS + ['.yaml', '.yml', '.ini'] }}" description: - List of extensions to ignore when looking for modules to load. - This is for rejecting script and binary module fallback extensions. env: [{name: ANSIBLE_MODULE_IGNORE_EXTS}] ini: - {key: module_ignore_exts, section: defaults} type: list MODULE_STRICT_UTF8_RESPONSE: name: Module strict UTF-8 response description: - Enables whether module responses are evaluated for containing non-UTF-8 data. - Disabling this may result in unexpected behavior. - Only ansible-core should evaluate this configuration. env: [{name: ANSIBLE_MODULE_STRICT_UTF8_RESPONSE}] ini: - {key: module_strict_utf8_response, section: defaults} type: bool default: True OLD_PLUGIN_CACHE_CLEARING: description: Previously Ansible would only clear some of the plugin loading caches when loading new roles, this led to some behaviors in which a plugin loaded in previous plays would be unexpectedly 'sticky'. This setting allows the user to return to that behavior. env: [{name: ANSIBLE_OLD_PLUGIN_CACHE_CLEAR}] ini: - {key: old_plugin_cache_clear, section: defaults} type: boolean default: False version_added: "2.8" PAGER: name: pager application to use default: less description: - for the cases in which Ansible needs to return output in a pageable fashion, this chooses the application to use. ini: - section: defaults key: pager version_added: '2.15' env: - name: ANSIBLE_PAGER version_added: '2.15' - name: PAGER PARAMIKO_HOST_KEY_AUTO_ADD: default: False description: 'TODO: write it' env: [{name: ANSIBLE_PARAMIKO_HOST_KEY_AUTO_ADD}] ini: - {key: host_key_auto_add, section: paramiko_connection} type: boolean deprecated: why: This option was moved to the plugin itself version: "2.20" alternatives: Use the option from the plugin itself. PARAMIKO_LOOK_FOR_KEYS: name: look for keys default: True description: 'TODO: write it' env: [{name: ANSIBLE_PARAMIKO_LOOK_FOR_KEYS}] ini: - {key: look_for_keys, section: paramiko_connection} type: boolean deprecated: why: This option was moved to the plugin itself version: "2.20" alternatives: Use the option from the plugin itself. PERSISTENT_CONTROL_PATH_DIR: name: Persistence socket path default: '{{ ANSIBLE_HOME ~ "/pc" }}' description: Path to the socket to be used by the connection persistence system. env: [{name: ANSIBLE_PERSISTENT_CONTROL_PATH_DIR}] ini: - {key: control_path_dir, section: persistent_connection} type: path PERSISTENT_CONNECT_TIMEOUT: name: Persistence timeout default: 30 description: This controls how long the persistent connection will remain idle before it is destroyed. env: [{name: ANSIBLE_PERSISTENT_CONNECT_TIMEOUT}] ini: - {key: connect_timeout, section: persistent_connection} type: integer PERSISTENT_CONNECT_RETRY_TIMEOUT: name: Persistence connection retry timeout default: 15 description: This controls the retry timeout for persistent connection to connect to the local domain socket. env: [{name: ANSIBLE_PERSISTENT_CONNECT_RETRY_TIMEOUT}] ini: - {key: connect_retry_timeout, section: persistent_connection} type: integer PERSISTENT_COMMAND_TIMEOUT: name: Persistence command timeout default: 30 description: This controls the amount of time to wait for a response from a remote device before timing out a persistent connection. env: [{name: ANSIBLE_PERSISTENT_COMMAND_TIMEOUT}] ini: - {key: command_timeout, section: persistent_connection} type: int PLAYBOOK_DIR: name: playbook dir override for non-playbook CLIs (ala --playbook-dir) version_added: "2.9" description: - A number of non-playbook CLIs have a ``--playbook-dir`` argument; this sets the default value for it. env: [{name: ANSIBLE_PLAYBOOK_DIR}] ini: [{key: playbook_dir, section: defaults}] type: path PLAYBOOK_VARS_ROOT: name: playbook vars files root default: top version_added: "2.4.1" description: - This sets which playbook dirs will be used as a root to process vars plugins, which includes finding host_vars/group_vars. env: [{name: ANSIBLE_PLAYBOOK_VARS_ROOT}] ini: - {key: playbook_vars_root, section: defaults} choices: top: follows the traditional behavior of using the top playbook in the chain to find the root directory. bottom: follows the 2.4.0 behavior of using the current playbook to find the root directory. all: examines from the first parent to the current playbook. PLUGIN_FILTERS_CFG: name: Config file for limiting valid plugins default: null version_added: "2.5.0" description: - "A path to configuration for filtering which plugins installed on the system are allowed to be used." - "See :ref:`plugin_filtering_config` for details of the filter file's format." - " The default is /etc/ansible/plugin_filters.yml" ini: - key: plugin_filters_cfg section: defaults type: path PYTHON_MODULE_RLIMIT_NOFILE: name: Adjust maximum file descriptor soft limit during Python module execution description: - Attempts to set RLIMIT_NOFILE soft limit to the specified value when executing Python modules (can speed up subprocess usage on Python 2.x. See https://bugs.python.org/issue11284). The value will be limited by the existing hard limit. Default value of 0 does not attempt to adjust existing system-defined limits. default: 0 env: - {name: ANSIBLE_PYTHON_MODULE_RLIMIT_NOFILE} ini: - {key: python_module_rlimit_nofile, section: defaults} vars: - {name: ansible_python_module_rlimit_nofile} version_added: '2.8' RETRY_FILES_ENABLED: name: Retry files default: False description: This controls whether a failed Ansible playbook should create a .retry file. env: [{name: ANSIBLE_RETRY_FILES_ENABLED}] ini: - {key: retry_files_enabled, section: defaults} type: bool RETRY_FILES_SAVE_PATH: name: Retry files path default: ~ description: - This sets the path in which Ansible will save .retry files when a playbook fails and retry files are enabled. - This file will be overwritten after each run with the list of failed hosts from all plays. env: [{name: ANSIBLE_RETRY_FILES_SAVE_PATH}] ini: - {key: retry_files_save_path, section: defaults} type: path RUN_VARS_PLUGINS: name: When should vars plugins run relative to inventory default: demand description: - This setting can be used to optimize vars_plugin usage depending on the user's inventory size and play selection. env: [{name: ANSIBLE_RUN_VARS_PLUGINS}] ini: - {key: run_vars_plugins, section: defaults} type: str choices: demand: will run vars_plugins relative to inventory sources anytime vars are 'demanded' by tasks. start: will run vars_plugins relative to inventory sources after importing that inventory source. version_added: "2.10" SHOW_CUSTOM_STATS: name: Display custom stats default: False description: 'This adds the custom stats set via the set_stats plugin to the default output.' env: [{name: ANSIBLE_SHOW_CUSTOM_STATS}] ini: - {key: show_custom_stats, section: defaults} type: bool SSH_AGENT: name: Manage an SSH Agent description: Manage an SSH Agent via Ansible. A configuration of ``none`` will not interact with an agent, ``auto`` will start and destroy an agent via ``ssh-agent`` binary during the run, and a path to an SSH_AUTH_SOCK will allow interaction with a pre-existing agent. default: none type: string env: [{name: ANSIBLE_SSH_AGENT}] ini: [{key: ssh_agent, section: connection}] version_added: '2.19' SSH_AGENT_EXECUTABLE: name: Executable to start for the ansible-managed SSH agent description: When ``SSH_AGENT`` is ``auto``, the path or name of the ssh agent executable to start. default: ssh-agent type: str env: [ { name: ANSIBLE_SSH_AGENT_EXECUTABLE } ] ini: [ { key: ssh_agent_executable, section: connection } ] version_added: '2.19' SSH_AGENT_KEY_LIFETIME: name: Set a maximum lifetime when adding identities to an agent description: For keys inserted into an agent defined by ``SSH_AGENT``, define a lifetime, in seconds, that the key may remain in the agent. type: int env: [{name: ANSIBLE_SSH_AGENT_KEY_LIFETIME}] ini: [{key: ssh_agent_key_lifetime, section: connection}] version_added: '2.19' STRING_TYPE_FILTERS: name: Filters to preserve strings default: [string, to_json, to_nice_json, to_yaml, to_nice_yaml, ppretty, json] description: - "This list of filters avoids 'type conversion' when templating variables." - Useful when you want to avoid conversion into lists or dictionaries for JSON strings, for example. env: [{name: ANSIBLE_STRING_TYPE_FILTERS}] ini: - {key: dont_type_filters, section: jinja2} type: list deprecated: why: This option has no effect. version: "2.23" alternatives: None; native types returned from filters are always preserved. SYSTEM_WARNINGS: name: System warnings default: True description: - Allows disabling of warnings related to potential issues on the system running Ansible itself (not on the managed hosts). - These may include warnings about third-party packages or other conditions that should be resolved if possible. env: [{name: ANSIBLE_SYSTEM_WARNINGS}] ini: - {key: system_warnings, section: defaults} type: boolean TAGS_RUN: name: Run Tags default: [] type: list description: default list of tags to run in your plays, Skip Tags has precedence. env: [{name: ANSIBLE_RUN_TAGS}] ini: - {key: run, section: tags} version_added: "2.5" TAGS_SKIP: name: Skip Tags default: [] type: list description: default list of tags to skip in your plays, has precedence over Run Tags env: [{name: ANSIBLE_SKIP_TAGS}] ini: - {key: skip, section: tags} version_added: "2.5" TARGET_LOG_INFO: name: Target log info description: A string to insert into target logging for tracking purposes env: [{name: ANSIBLE_TARGET_LOG_INFO}] ini: - {key: target_log_info, section: defaults} vars: - name: ansible_target_log_info version_added: "2.17" TASK_TIMEOUT: name: Task Timeout default: 0 description: - Set the maximum time (in seconds) for a task action to execute in. - Timeout runs independently from templating or looping. It applies per each attempt of executing the task's action and remains unchanged by the total time spent on a task. - When the action execution exceeds the timeout, Ansible interrupts the process. This is registered as a failure due to outside circumstances, not a task failure, to receive appropriate response and recovery process. - If set to 0 (the default) there is no timeout. env: [{name: ANSIBLE_TASK_TIMEOUT}] ini: - {key: task_timeout, section: defaults} type: integer version_added: '2.10' _TEMPLAR_SANDBOX_MODE: name: Control Jinja template sandbox behavior default: default description: - The default Jinja sandbox behavior blocks template access to all `_` prefixed object attributes and known collection mutation methods (e.g., `dict.clear()`, `list.append()`). type: choices choices: - default - allow_unsafe_attributes env: [{name: _ANSIBLE_TEMPLAR_SANDBOX_MODE}] deprecated: why: controlling sandbox behavior is a temporary workaround version: '2.23' _TEMPLAR_UNKNOWN_TYPE_CONVERSION: name: Templar unknown type conversion behavior default: warning description: - Action to take when an unknown type is converted for variable storage during template finalization. - This setting has no effect on the inability to store unsupported variable types as the result of templating. - Experimental diagnostic feature, subject to change. type: choices choices: *basic_error env: [{name: _ANSIBLE_TEMPLAR_UNKNOWN_TYPE_CONVERSION}] version_added: '2.19' _TEMPLAR_UNKNOWN_TYPE_ENCOUNTERED: name: Templar unknown type encountered behavior default: ignore description: - Action to take when an unknown type is encountered inside a template pipeline. - Experimental diagnostic feature, subject to change. type: choices choices: *basic_error env: [{name: _ANSIBLE_TEMPLAR_UNKNOWN_TYPE_ENCOUNTERED}] version_added: '2.19' _TEMPLAR_UNTRUSTED_TEMPLATE_BEHAVIOR: name: Templar untrusted template behavior default: ignore description: - Action to take when processing of an untrusted template is skipped. - For `ignore` or `warn`, the input template string is returned as-is. - This setting has no effect on expressions. - Experimental diagnostic feature, subject to change. type: choices choices: *basic_error env: [{name: _ANSIBLE_TEMPLAR_UNTRUSTED_TEMPLATE_BEHAVIOR}] version_added: '2.19' WORKER_SHUTDOWN_POLL_COUNT: name: Worker Shutdown Poll Count default: 0 description: - The maximum number of times to check Task Queue Manager worker processes to verify they have exited cleanly. - After this limit is reached any worker processes still running will be terminated. - This is for internal use only. env: [{name: ANSIBLE_WORKER_SHUTDOWN_POLL_COUNT}] type: integer version_added: '2.10' WORKER_SHUTDOWN_POLL_DELAY: name: Worker Shutdown Poll Delay default: 0.1 description: - The number of seconds to sleep between polling loops when checking Task Queue Manager worker processes to verify they have exited cleanly. - This is for internal use only. env: [{name: ANSIBLE_WORKER_SHUTDOWN_POLL_DELAY}] type: float version_added: '2.10' USE_PERSISTENT_CONNECTIONS: name: Persistence default: False description: Toggles the use of persistence for connections. env: [{name: ANSIBLE_USE_PERSISTENT_CONNECTIONS}] ini: - {key: use_persistent_connections, section: defaults} type: boolean VARIABLE_PLUGINS_ENABLED: name: Vars plugin enabled list default: ['host_group_vars'] description: Accept list for variable plugins that require it. env: [{name: ANSIBLE_VARS_ENABLED}] ini: - {key: vars_plugins_enabled, section: defaults} type: list version_added: "2.10" VARIABLE_PRECEDENCE: name: Group variable precedence default: ['all_inventory', 'groups_inventory', 'all_plugins_inventory', 'all_plugins_play', 'groups_plugins_inventory', 'groups_plugins_play'] description: Allows to change the group variable precedence merge order. env: [{name: ANSIBLE_PRECEDENCE}] ini: - {key: precedence, section: defaults} type: list version_added: "2.4" WIN_ASYNC_STARTUP_TIMEOUT: name: Windows Async Startup Timeout default: 5 description: - For asynchronous tasks in Ansible (covered in Asynchronous Actions and Polling), this is how long, in seconds, to wait for the task spawned by Ansible to connect back to the named pipe used on Windows systems. The default is 5 seconds. This can be too low on slower systems, or systems under heavy load. - This is not the total time an async command can run for, but is a separate timeout to wait for an async command to start. The task will only start to be timed against its async_timeout once it has connected to the pipe, so the overall maximum duration the task can take will be extended by the amount specified here. env: [{name: ANSIBLE_WIN_ASYNC_STARTUP_TIMEOUT}] ini: - {key: win_async_startup_timeout, section: defaults} type: integer vars: - {name: ansible_win_async_startup_timeout} version_added: '2.10' WRAP_STDERR: description: Control line-wrapping behavior on console warnings and errors from default output callbacks (eases pattern-based output testing) env: [{name: ANSIBLE_WRAP_STDERR}] default: false type: bool version_added: "2.19" YAML_FILENAME_EXTENSIONS: name: Valid YAML extensions default: [".yml", ".yaml", ".json"] description: - "Check all of these extensions when looking for 'variable' files which should be YAML or JSON or vaulted versions of these." - 'This affects vars_files, include_vars, inventory and vars plugins among others.' env: - name: ANSIBLE_YAML_FILENAME_EXT ini: - section: defaults key: yaml_valid_extensions type: list NETCONF_SSH_CONFIG: description: This variable is used to enable bastion/jump host with netconf connection. If set to True the bastion/jump host ssh settings should be present in ~/.ssh/config file, alternatively it can be set to custom ssh configuration file path to read the bastion/jump host settings. env: [{name: ANSIBLE_NETCONF_SSH_CONFIG}] ini: - {key: ssh_config, section: netconf_connection} yaml: {key: netconf_connection.ssh_config} default: null VALIDATE_ACTION_GROUP_METADATA: version_added: '2.12' description: - A toggle to disable validating a collection's 'metadata' entry for a module_defaults action group. Metadata containing unexpected fields or value types will produce a warning when this is True. default: True env: [{name: ANSIBLE_VALIDATE_ACTION_GROUP_METADATA}] ini: - section: defaults key: validate_action_group_metadata type: bool VERBOSE_TO_STDERR: version_added: '2.8' description: - Force 'verbose' option to use stderr instead of stdout default: False env: - name: ANSIBLE_VERBOSE_TO_STDERR ini: - section: defaults key: verbose_to_stderr type: bool _Z_TEST_ENTRY: name: testentry description: for tests env: - name: ANSIBLE_TEST_ENTRY - name: ANSIBLE_TEST_ENTRY_D deprecated: why: for testing version: '3.30' alternatives: nothing ini: - section: testing key: valid - section: testing key: deprecated deprecated: why: for testing version: '3.30' alternatives: nothing _Z_TEST_ENTRY_2: version_added: '2.18' name: testentry description: for tests deprecated: why: for testing version: '3.30' alternatives: nothing env: - name: ANSIBLE_TEST_ENTRY2 ini: - section: testing key: valid2 ansible_core-2.19.0b5/lib/ansible/config/manager.py0000644000000000000000000007462315017704211020643 0ustar00rootroot# Copyright: (c) 2017, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import atexit import decimal import configparser import os import os.path import sys import stat import tempfile import typing as t from collections.abc import Mapping, Sequence from jinja2.nativetypes import NativeEnvironment from ansible._internal._datatag import _tags from ansible.errors import AnsibleOptionsError, AnsibleError, AnsibleUndefinedConfigEntry, AnsibleRequiredOptionError from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible.module_utils.common.sentinel import Sentinel from ansible.module_utils.common.text.converters import to_text, to_bytes, to_native from ansible.module_utils.common.yaml import yaml_load from ansible.module_utils.parsing.convert_bool import boolean from ansible.parsing.quoting import unquote from ansible.utils.path import cleanup_tmp_file, makedirs_safe, unfrackpath INTERNAL_DEFS = {'lookup': ('_terms',)} GALAXY_SERVER_DEF = [ ('url', True, 'str'), ('username', False, 'str'), ('password', False, 'str'), ('token', False, 'str'), ('auth_url', False, 'str'), ('api_version', False, 'int'), ('validate_certs', False, 'bool'), ('client_id', False, 'str'), ('client_secret', False, 'str'), ('timeout', False, 'int'), ] # config definition fields GALAXY_SERVER_ADDITIONAL = { 'api_version': {'default': None, 'choices': [2, 3]}, 'validate_certs': {'cli': [{'name': 'validate_certs'}]}, 'timeout': {'cli': [{'name': 'timeout'}]}, 'token': {'default': None}, } @t.runtime_checkable class _EncryptedStringProtocol(t.Protocol): """Protocol representing an `EncryptedString`, since it cannot be imported here.""" # DTFIX-FUTURE: collapse this with the one in collection loader, once we can def _decrypt(self) -> str: ... def _get_config_label(plugin_type: str, plugin_name: str, config: str) -> str: """Return a label for the given config.""" entry = f'{config!r}' if plugin_type: entry += ' for' if plugin_name: entry += f' {plugin_name!r}' entry += f' {plugin_type} plugin' return entry def ensure_type(value: object, value_type: str | None, origin: str | None = None, origin_ftype: str | None = None) -> t.Any: """ Converts `value` to the requested `value_type`; raises `ValueError` for failed conversions. Values for `value_type` are: * boolean/bool: Return a `bool` by applying non-strict `bool` filter rules: 'y', 'yes', 'on', '1', 'true', 't', 1, 1.0, True return True, any other value is False. * integer/int: Return an `int`. Accepts any `str` parseable by `int` or numeric value with a zero mantissa (including `bool`). * float: Return a `float`. Accepts any `str` parseable by `float` or numeric value (including `bool`). * list: Return a `list`. Accepts `list` or `Sequence`. Also accepts, `str`, splitting on ',' while stripping whitespace and unquoting items. * none: Return `None`. Accepts only the string "None". * path: Return a resolved path. Accepts `str`. * temppath/tmppath/tmp: Return a unique temporary directory inside the resolved path specified by the value. * pathspec: Return a `list` of resolved paths. Accepts a `list` or `Sequence`. Also accepts `str`, splitting on ':'. * pathlist: Return a `list` of resolved paths. Accepts a `list` or `Sequence`. Also accepts `str`, splitting on `,` while stripping whitespace from paths. * dictionary/dict: Return a `dict`. Accepts `dict` or `Mapping`. * string/str: Return a `str`. Accepts `bool`, `int`, `float`, `complex` or `str`. Path resolution ensures paths are `str` with expansion of '{{CWD}}', environment variables and '~'. Non-absolute paths are expanded relative to the basedir from `origin`, if specified. No conversion is performed if `value_type` is unknown or `value` is `None`. When `origin_ftype` is "ini", a `str` result will be unquoted. """ if value is None: return None original_value = value copy_tags = value_type not in ('temppath', 'tmppath', 'tmp') value = _ensure_type(value, value_type, origin) if copy_tags and value is not original_value: if isinstance(value, list): value = [AnsibleTagHelper.tag_copy(original_value, item) for item in value] value = AnsibleTagHelper.tag_copy(original_value, value) if isinstance(value, str) and origin_ftype and origin_ftype == 'ini': value = unquote(value) return value def _ensure_type(value: object, value_type: str | None, origin: str | None = None) -> t.Any: """Internal implementation for `ensure_type`, call that function instead.""" original_value = value basedir = origin if origin and os.path.isabs(origin) and os.path.exists(to_bytes(origin)) else None if value_type: value_type = value_type.lower() match value_type: case 'boolean' | 'bool': return boolean(value, strict=False) case 'integer' | 'int': if isinstance(value, int): # handle both int and bool (which is an int) return int(value) if isinstance(value, (float, str)): try: # use Decimal for all other source type conversions; non-zero mantissa is a failure if (decimal_value := decimal.Decimal(value)) == (int_part := int(decimal_value)): return int_part except (decimal.DecimalException, ValueError): pass case 'float': if isinstance(value, float): return value if isinstance(value, (int, str)): try: return float(value) except ValueError: pass case 'list': if isinstance(value, list): return value if isinstance(value, str): return [unquote(x.strip()) for x in value.split(',')] if isinstance(value, Sequence) and not isinstance(value, bytes): return list(value) case 'none': if value == "None": return None case 'path': if isinstance(value, str): return resolve_path(value, basedir=basedir) case 'temppath' | 'tmppath' | 'tmp': if isinstance(value, str): value = resolve_path(value, basedir=basedir) if not os.path.exists(value): makedirs_safe(value, 0o700) prefix = 'ansible-local-%s' % os.getpid() value = tempfile.mkdtemp(prefix=prefix, dir=value) atexit.register(cleanup_tmp_file, value, warn=True) return value case 'pathspec': if isinstance(value, str): value = value.split(os.pathsep) if isinstance(value, Sequence) and not isinstance(value, bytes) and all(isinstance(x, str) for x in value): return [resolve_path(x, basedir=basedir) for x in value] case 'pathlist': if isinstance(value, str): value = [x.strip() for x in value.split(',')] if isinstance(value, Sequence) and not isinstance(value, bytes) and all(isinstance(x, str) for x in value): return [resolve_path(x, basedir=basedir) for x in value] case 'dictionary' | 'dict': if isinstance(value, dict): return value if isinstance(value, Mapping): return dict(value) case 'string' | 'str': if isinstance(value, str): return value if isinstance(value, (bool, int, float, complex)): return str(value) if isinstance(value, _EncryptedStringProtocol): return value._decrypt() case _: # FIXME: define and document a pass-through value_type (None, 'raw', 'object', '', ...) and then deprecate acceptance of unknown types return value # return non-str values of unknown value_type as-is raise ValueError(f'Invalid value provided for {value_type!r}: {original_value!r}') # FIXME: see if this can live in utils/path def resolve_path(path: str, basedir: str | None = None) -> str: """ resolve relative or 'variable' paths """ if '{{CWD}}' in path: # allow users to force CWD using 'magic' {{CWD}} path = path.replace('{{CWD}}', os.getcwd()) return unfrackpath(path, follow=False, basedir=basedir) # FIXME: generic file type? def get_config_type(cfile): ftype = None if cfile is not None: ext = os.path.splitext(cfile)[-1] if ext in ('.ini', '.cfg'): ftype = 'ini' elif ext in ('.yaml', '.yml'): ftype = 'yaml' else: raise AnsibleOptionsError("Unsupported configuration file extension for %s: %s" % (cfile, to_native(ext))) return ftype # FIXME: can move to module_utils for use for ini plugins also? def get_ini_config_value(p, entry): """ returns the value of last ini entry found """ value = None if p is not None: try: value = p.get(entry.get('section', 'defaults'), entry.get('key', ''), raw=True) except Exception: # FIXME: actually report issues here pass return value def find_ini_config_file(warnings=None): """ Load INI Config File order(first found is used): ENV, CWD, HOME, /etc/ansible """ # FIXME: eventually deprecate ini configs if warnings is None: # Note: In this case, warnings does nothing warnings = set() potential_paths = [] # A value that can never be a valid path so that we can tell if ANSIBLE_CONFIG was set later # We can't use None because we could set path to None. # Environment setting path_from_env = os.getenv("ANSIBLE_CONFIG", Sentinel) if path_from_env is not Sentinel: path_from_env = unfrackpath(path_from_env, follow=False) if os.path.isdir(to_bytes(path_from_env)): path_from_env = os.path.join(path_from_env, "ansible.cfg") potential_paths.append(path_from_env) # Current working directory warn_cmd_public = False try: cwd = os.getcwd() perms = os.stat(cwd) cwd_cfg = os.path.join(cwd, "ansible.cfg") if perms.st_mode & stat.S_IWOTH: # Working directory is world writable so we'll skip it. # Still have to look for a file here, though, so that we know if we have to warn if os.path.exists(cwd_cfg): warn_cmd_public = True else: potential_paths.append(to_text(cwd_cfg, errors='surrogate_or_strict')) except OSError: # If we can't access cwd, we'll simply skip it as a possible config source pass # Per user location potential_paths.append(unfrackpath("~/.ansible.cfg", follow=False)) # System location potential_paths.append("/etc/ansible/ansible.cfg") for path in potential_paths: b_path = to_bytes(path) if os.path.exists(b_path) and os.access(b_path, os.R_OK): break else: path = None # Emit a warning if all the following are true: # * We did not use a config from ANSIBLE_CONFIG # * There's an ansible.cfg in the current working directory that we skipped if path_from_env != path and warn_cmd_public: warnings.add(u"Ansible is being run in a world writable directory (%s)," u" ignoring it as an ansible.cfg source." u" For more information see" u" https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir" % to_text(cwd)) return path def _add_base_defs_deprecations(base_defs): """Add deprecation source 'ansible.builtin' to deprecations in base.yml""" def process(entry): if 'deprecated' in entry: entry['deprecated']['collection_name'] = 'ansible.builtin' for dummy, data in base_defs.items(): process(data) for section in ('ini', 'env', 'vars'): if section in data: for entry in data[section]: process(entry) class ConfigManager: DEPRECATED = [] # type: list[tuple[str, dict[str, str]]] WARNINGS = set() # type: set[str] _errors: list[tuple[str, Exception]] def __init__(self, conf_file=None, defs_file=None): self._base_defs = {} self._plugins = {} self._parsers = {} self._config_file = conf_file self._base_defs = self._read_config_yaml_file(defs_file or ('%s/base.yml' % os.path.dirname(__file__))) _add_base_defs_deprecations(self._base_defs) if self._config_file is None: # set config using ini self._config_file = find_ini_config_file(self.WARNINGS) # consume configuration if self._config_file: # initialize parser and read config self._parse_config_file() self._errors = [] """Deferred errors that will be turned into warnings.""" # ensure we always have config def entry self._base_defs['CONFIG_FILE'] = {'default': None, 'type': 'path'} def load_galaxy_server_defs(self, server_list): def server_config_def(section, key, required, option_type): config_def = { 'description': 'The %s of the %s Galaxy server' % (key, section), 'ini': [ { 'section': 'galaxy_server.%s' % section, 'key': key, } ], 'env': [ {'name': 'ANSIBLE_GALAXY_SERVER_%s_%s' % (section.upper(), key.upper())}, ], 'required': required, 'type': option_type, } if key in GALAXY_SERVER_ADDITIONAL: config_def.update(GALAXY_SERVER_ADDITIONAL[key]) # ensure we always have a default timeout if key == 'timeout' and 'default' not in config_def: config_def['default'] = self.get_config_value('GALAXY_SERVER_TIMEOUT') return config_def if server_list: for server_key in server_list: if not server_key: # To filter out empty strings or non truthy values as an empty server list env var is equal to ['']. continue # Config definitions are looked up dynamically based on the C.GALAXY_SERVER_LIST entry. We look up the # section [galaxy_server.] for the values url, username, password, and token. defs = dict((k, server_config_def(server_key, k, req, value_type)) for k, req, value_type in GALAXY_SERVER_DEF) self.initialize_plugin_configuration_definitions('galaxy_server', server_key, defs) def template_default(self, value, variables, key_name: str = ''): if isinstance(value, str) and (value.startswith('{{') and value.endswith('}}')) and variables is not None: # template default values if possible # NOTE: cannot use is_template due to circular dep try: # FIXME: This really should be using an immutable sandboxed native environment, not just native environment template = NativeEnvironment().from_string(value) value = template.render(variables) except Exception as ex: self._errors.append((f'Failed to template default for config {key_name}.', ex)) return value def _read_config_yaml_file(self, yml_file): # TODO: handle relative paths as relative to the directory containing the current playbook instead of CWD # Currently this is only used with absolute paths to the `ansible/config` directory yml_file = to_bytes(yml_file) if os.path.exists(yml_file): with open(yml_file, 'rb') as config_def: return yaml_load(config_def) or {} raise AnsibleError( "Missing base YAML definition file (bad install?): %s" % to_native(yml_file)) def _parse_config_file(self, cfile=None): """ return flat configuration settings from file(s) """ # TODO: take list of files with merge/nomerge if cfile is None: cfile = self._config_file ftype = get_config_type(cfile) if cfile is not None: if ftype == 'ini': self._parsers[cfile] = configparser.ConfigParser(inline_comment_prefixes=(';',)) with open(to_bytes(cfile), 'rb') as f: try: cfg_text = to_text(f.read(), errors='surrogate_or_strict') except UnicodeError as e: raise AnsibleOptionsError("Error reading config file(%s) because the config file was not utf8 encoded: %s" % (cfile, to_native(e))) try: self._parsers[cfile].read_string(cfg_text) except configparser.Error as e: raise AnsibleOptionsError("Error reading config file (%s): %s" % (cfile, to_native(e))) # FIXME: this should eventually handle yaml config files # elif ftype == 'yaml': # with open(cfile, 'rb') as config_stream: # self._parsers[cfile] = yaml_load(config_stream) else: raise AnsibleOptionsError("Unsupported configuration file type: %s" % to_native(ftype)) def _find_yaml_config_files(self): """ Load YAML Config Files in order, check merge flags, keep origin of settings""" pass def get_plugin_options(self, plugin_type, name, keys=None, variables=None, direct=None): options = {} defs = self.get_configuration_definitions(plugin_type=plugin_type, name=name) for option in defs: options[option] = self.get_config_value(option, plugin_type=plugin_type, plugin_name=name, keys=keys, variables=variables, direct=direct) return options def get_plugin_vars(self, plugin_type, name): pvars = [] for pdef in self.get_configuration_definitions(plugin_type=plugin_type, name=name).values(): if 'vars' in pdef and pdef['vars']: for var_entry in pdef['vars']: pvars.append(var_entry['name']) return pvars def get_plugin_options_from_var(self, plugin_type, name, variable): options = [] for option_name, pdef in self.get_configuration_definitions(plugin_type=plugin_type, name=name).items(): if 'vars' in pdef and pdef['vars']: for var_entry in pdef['vars']: if variable == var_entry['name']: options.append(option_name) return options def get_configuration_definition(self, name, plugin_type=None, plugin_name=None): ret = {} if plugin_type is None: ret = self._base_defs.get(name, None) elif plugin_name is None: ret = self._plugins.get(plugin_type, {}).get(name, None) else: ret = self._plugins.get(plugin_type, {}).get(plugin_name, {}).get(name, None) return ret def has_configuration_definition(self, plugin_type, name): has = False if plugin_type in self._plugins: has = (name in self._plugins[plugin_type]) return has def get_configuration_definitions(self, plugin_type=None, name=None, ignore_private=False): """ just list the possible settings, either base or for specific plugins or plugin """ ret = {} if plugin_type is None: ret = self._base_defs elif name is None: ret = self._plugins.get(plugin_type, {}) else: ret = self._plugins.get(plugin_type, {}).get(name, {}) if ignore_private: # ignore 'test' config entries, they should not change runtime behaviors for cdef in list(ret.keys()): if cdef.startswith('_Z_'): del ret[cdef] return ret def _loop_entries(self, container, entry_list): """ repeat code for value entry assignment """ value = None origin = None for entry in entry_list: name = entry.get('name') try: temp_value = container.get(name, None) except UnicodeEncodeError: self.WARNINGS.add(u'value for config entry {0} contains invalid characters, ignoring...'.format(to_text(name))) continue if temp_value is not None: # only set if entry is defined in container value = temp_value origin = name # deal with deprecation of setting source, if used if 'deprecated' in entry: self.DEPRECATED.append((entry['name'], entry['deprecated'])) return value, origin def get_config_value(self, config, cfile=None, plugin_type=None, plugin_name=None, keys=None, variables=None, direct=None): """ wrapper """ try: value, _drop = self.get_config_value_and_origin(config, cfile=cfile, plugin_type=plugin_type, plugin_name=plugin_name, keys=keys, variables=variables, direct=direct) except AnsibleError: raise except Exception as ex: raise AnsibleError(f"Unhandled exception when retrieving {config!r}.") from ex return value def get_config_default(self, config: str, plugin_type: str | None = None, plugin_name: str | None = None) -> t.Any: """Return the default value for the specified configuration.""" return self.get_configuration_definitions(plugin_type, plugin_name)[config]['default'] def get_config_value_and_origin(self, config, cfile=None, plugin_type=None, plugin_name=None, keys=None, variables=None, direct=None): """ Given a config key figure out the actual value and report on the origin of the settings """ if cfile is None: # use default config cfile = self._config_file if config == 'CONFIG_FILE': return cfile, '' # Note: sources that are lists listed in low to high precedence (last one wins) value = None origin = None origin_ftype = None defs = self.get_configuration_definitions(plugin_type=plugin_type, name=plugin_name) if config in defs: aliases = defs[config].get('aliases', []) # direct setting via plugin arguments, can set to None so we bypass rest of processing/defaults if direct: if config in direct: value = direct[config] origin = 'Direct' else: direct_aliases = [direct[alias] for alias in aliases if alias in direct] if direct_aliases: value = direct_aliases[0] origin = 'Direct' if value is None and variables and defs[config].get('vars'): # Use 'variable overrides' if present, highest precedence, but only present when querying running play value, origin = self._loop_entries(variables, defs[config]['vars']) origin = 'var: %s' % origin # use playbook keywords if you have em if value is None and defs[config].get('keyword') and keys: value, origin = self._loop_entries(keys, defs[config]['keyword']) origin = 'keyword: %s' % origin # automap to keywords # TODO: deprecate these in favor of explicit keyword above if value is None and keys: if config in keys: value = keys[config] keyword = config elif aliases: for alias in aliases: if alias in keys: value = keys[alias] keyword = alias break if value is not None: origin = 'keyword: %s' % keyword if value is None and 'cli' in defs[config]: # avoid circular import .. until valid from ansible import context value, origin = self._loop_entries(context.CLIARGS, defs[config]['cli']) origin = 'cli: %s' % origin # env vars are next precedence if value is None and defs[config].get('env'): value, origin = self._loop_entries(os.environ, defs[config]['env']) origin = 'env: %s' % origin # try config file entries next, if we have one if self._parsers.get(cfile, None) is None: self._parse_config_file(cfile) # attempt to read from config file if value is None and cfile is not None: ftype = get_config_type(cfile) if ftype and defs[config].get(ftype): try: for entry in defs[config][ftype]: # load from config if ftype == 'ini': temp_value = get_ini_config_value(self._parsers[cfile], entry) elif ftype == 'yaml': raise AnsibleError('YAML configuration type has not been implemented yet') else: raise AnsibleError('Invalid configuration file type: %s' % ftype) if temp_value is not None: # set value and origin value = temp_value origin = cfile origin_ftype = ftype if 'deprecated' in entry: if ftype == 'ini': self.DEPRECATED.append(('[%s]%s' % (entry['section'], entry['key']), entry['deprecated'])) else: raise AnsibleError('Unimplemented file type: %s' % ftype) except Exception as e: sys.stderr.write("Error while loading config %s: %s" % (cfile, to_native(e))) # set default if we got here w/o a value if value is None: if defs[config].get('required', False): if not plugin_type or config not in INTERNAL_DEFS.get(plugin_type, {}): raise AnsibleRequiredOptionError(f"Required config {_get_config_label(plugin_type, plugin_name, config)} not provided.") else: origin = 'default' value = self.template_default(defs[config].get('default'), variables, key_name=_get_config_label(plugin_type, plugin_name, config)) try: # ensure correct type, can raise exceptions on mismatched types value = ensure_type(value, defs[config].get('type'), origin=origin, origin_ftype=origin_ftype) except ValueError as ex: if origin.startswith('env:') and value == '': # this is empty env var for non string so we can set to default origin = 'default' value = ensure_type(defs[config].get('default'), defs[config].get('type'), origin=origin, origin_ftype=origin_ftype) else: raise AnsibleOptionsError(f'Config {_get_config_label(plugin_type, plugin_name, config)} from {origin!r} has an invalid value.') from ex # deal with restricted values if value is not None and 'choices' in defs[config] and defs[config]['choices'] is not None: invalid_choices = True # assume the worst! if defs[config].get('type') == 'list': # for a list type, compare all values in type are allowed invalid_choices = not all(choice in defs[config]['choices'] for choice in value) else: # these should be only the simple data types (string, int, bool, float, etc) .. ignore dicts for now invalid_choices = value not in defs[config]['choices'] if invalid_choices: if isinstance(defs[config]['choices'], Mapping): valid = ', '.join([to_text(k) for k in defs[config]['choices'].keys()]) elif isinstance(defs[config]['choices'], str): valid = defs[config]['choices'] elif isinstance(defs[config]['choices'], Sequence): valid = ', '.join([to_text(c) for c in defs[config]['choices']]) else: valid = defs[config]['choices'] raise AnsibleOptionsError(f'Invalid value {value!r} for config {_get_config_label(plugin_type, plugin_name, config)}.', help_text=f'Valid values are: {valid}') # deal with deprecation of the setting if 'deprecated' in defs[config] and origin != 'default': self.DEPRECATED.append((config, defs[config].get('deprecated'))) else: raise AnsibleUndefinedConfigEntry(f'No config definition exists for {_get_config_label(plugin_type, plugin_name, config)}.') if not _tags.Origin.is_tagged_on(value): value = _tags.Origin(description=f'').tag(value) return value, origin def initialize_plugin_configuration_definitions(self, plugin_type, name, defs): if plugin_type not in self._plugins: self._plugins[plugin_type] = {} self._plugins[plugin_type][name] = defs @staticmethod def get_deprecated_msg_from_config(dep_docs, include_removal=False, collection_name=None): removal = '' if include_removal: if 'removed_at_date' in dep_docs: removal = f"Will be removed in a release after {dep_docs['removed_at_date']}\n\t" elif collection_name: removal = f"Will be removed in: {collection_name} {dep_docs['removed_in']}\n\t" else: removal = f"Will be removed in: Ansible {dep_docs['removed_in']}\n\t" # TODO: choose to deprecate either singular or plural alt = dep_docs.get('alternatives', dep_docs.get('alternative', 'none')) return f"Reason: {dep_docs['why']}\n\t{removal}Alternatives: {alt}" ansible_core-2.19.0b5/lib/ansible/constants.py0000644000000000000000000001746515017704211020001 0ustar00rootroot# Copyright: (c) 2012-2014, Michael DeHaan # Copyright: (c) 2017, Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import re from string import ascii_letters, digits from ansible.config.manager import ConfigManager from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE from ansible.utils.fqcn import add_internal_fqcns # initialize config manager/config data to read/store global settings # and generate 'pseudo constants' for app consumption. config = ConfigManager() def set_constant(name, value, export=vars()): """ sets constants and returns resolved options dict """ export[name] = value # CONSTANTS ### yes, actual ones # The following are hard-coded action names _ACTION_DEBUG = add_internal_fqcns(('debug', )) _ACTION_IMPORT_PLAYBOOK = add_internal_fqcns(('import_playbook', )) _ACTION_IMPORT_ROLE = add_internal_fqcns(('import_role', )) _ACTION_IMPORT_TASKS = add_internal_fqcns(('import_tasks', )) _ACTION_INCLUDE_ROLE = add_internal_fqcns(('include_role', )) _ACTION_INCLUDE_TASKS = add_internal_fqcns(('include_tasks', )) _ACTION_INCLUDE_VARS = add_internal_fqcns(('include_vars', )) _ACTION_INVENTORY_TASKS = add_internal_fqcns(('add_host', 'group_by')) _ACTION_META = add_internal_fqcns(('meta', )) _ACTION_SET_FACT = add_internal_fqcns(('set_fact', )) _ACTION_SETUP = add_internal_fqcns(('setup', )) _ACTION_HAS_CMD = add_internal_fqcns(('command', 'shell', 'script')) _ACTION_ALLOWS_RAW_ARGS = _ACTION_HAS_CMD + add_internal_fqcns(('raw', )) _ACTION_ALL_INCLUDES = _ACTION_INCLUDE_TASKS + _ACTION_INCLUDE_ROLE _ACTION_ALL_INCLUDE_IMPORT_TASKS = _ACTION_INCLUDE_TASKS + _ACTION_IMPORT_TASKS _ACTION_ALL_PROPER_INCLUDE_IMPORT_ROLES = _ACTION_INCLUDE_ROLE + _ACTION_IMPORT_ROLE _ACTION_ALL_PROPER_INCLUDE_IMPORT_TASKS = _ACTION_INCLUDE_TASKS + _ACTION_IMPORT_TASKS _ACTION_ALL_INCLUDE_ROLE_TASKS = _ACTION_INCLUDE_ROLE + _ACTION_INCLUDE_TASKS _ACTION_FACT_GATHERING = _ACTION_SETUP + add_internal_fqcns(('gather_facts', )) _ACTION_WITH_CLEAN_FACTS = _ACTION_SET_FACT + _ACTION_INCLUDE_VARS # http://nezzen.net/2008/06/23/colored-text-in-python-using-ansi-escape-sequences/ COLOR_CODES = { 'black': u'0;30', 'bright gray': u'0;37', 'blue': u'0;34', 'white': u'1;37', 'green': u'0;32', 'bright blue': u'1;34', 'cyan': u'0;36', 'bright green': u'1;32', 'red': u'0;31', 'bright cyan': u'1;36', 'purple': u'0;35', 'bright red': u'1;31', 'yellow': u'0;33', 'bright purple': u'1;35', 'dark gray': u'1;30', 'bright yellow': u'1;33', 'magenta': u'0;35', 'bright magenta': u'1;35', 'normal': u'0', } REJECT_EXTS = ['.pyc', '.pyo', '.swp', '.bak', '~', '.rpm', '.md', '.txt', '.rst'] # this is concatenated with other config settings as lists; cannot be tuple BOOL_TRUE = BOOLEANS_TRUE COLLECTION_PTYPE_COMPAT = {'module': 'modules'} PYTHON_DOC_EXTENSIONS = ('.py',) YAML_DOC_EXTENSIONS = ('.yml', '.yaml') DOC_EXTENSIONS = PYTHON_DOC_EXTENSIONS + YAML_DOC_EXTENSIONS DEFAULT_BECOME_PASS = None DEFAULT_PASSWORD_CHARS = to_text(ascii_letters + digits + ".,:-_", errors='strict') # characters included in auto-generated passwords DEFAULT_REMOTE_PASS = None DEFAULT_SUBSET = None # FIXME: expand to other plugins, but never doc fragments CONFIGURABLE_PLUGINS = ('become', 'cache', 'callback', 'cliconf', 'connection', 'httpapi', 'inventory', 'lookup', 'netconf', 'shell', 'vars') # NOTE: always update the docs/docsite/Makefile to match DOCUMENTABLE_PLUGINS = CONFIGURABLE_PLUGINS + ('module', 'strategy', 'test', 'filter') IGNORE_FILES = ("COPYING", "CONTRIBUTING", "LICENSE", "README", "VERSION", "GUIDELINES", "MANIFEST", "Makefile") # ignore during module search INTERNAL_RESULT_KEYS = ('add_host', 'add_group') INTERNAL_STATIC_VARS = frozenset( [ "ansible_async_path", "ansible_collection_name", "ansible_config_file", "ansible_dependent_role_names", "ansible_diff_mode", "ansible_config_file", "ansible_facts", "ansible_forks", "ansible_inventory_sources", "ansible_limit", "ansible_play_batch", "ansible_play_hosts", "ansible_play_hosts_all", "ansible_play_role_names", "ansible_playbook_python", "ansible_role_name", "ansible_role_names", "ansible_run_tags", "ansible_skip_tags", "ansible_verbosity", "ansible_version", "inventory_dir", "inventory_file", "inventory_hostname", "inventory_hostname_short", "groups", "group_names", "hostvars", "playbook_dir", "play_hosts", "role_name", "role_names", "role_path", "role_uuid", "role_names", ] ) LOCALHOST = ('127.0.0.1', 'localhost', '::1') WIN_MOVED = ['ansible.windows.win_command', 'ansible.windows.win_shell'] MODULE_REQUIRE_ARGS_SIMPLE = ['command', 'raw', 'script', 'shell', 'win_command', 'win_shell'] MODULE_REQUIRE_ARGS = tuple(add_internal_fqcns(MODULE_REQUIRE_ARGS_SIMPLE) + WIN_MOVED) MODULE_NO_JSON = tuple(add_internal_fqcns(('command', 'win_command', 'shell', 'win_shell', 'raw')) + WIN_MOVED) RESTRICTED_RESULT_KEYS = ('ansible_rsync_path', 'ansible_playbook_python', 'ansible_facts') SYNTHETIC_COLLECTIONS = ('ansible.builtin', 'ansible.legacy') TREE_DIR = None VAULT_VERSION_MIN = 1.0 VAULT_VERSION_MAX = 1.0 # This matches a string that cannot be used as a valid python variable name i.e 'not-valid', 'not!valid@either' '1_nor_This' INVALID_VARIABLE_NAMES = re.compile(r'^[\d\W]|[^\w]') # FIXME: remove once play_context mangling is removed # the magic variable mapping dictionary below is used to translate # host/inventory variables to fields in the PlayContext # object. The dictionary values are tuples, to account for aliases # in variable names. COMMON_CONNECTION_VARS = frozenset(('ansible_connection', 'ansible_host', 'ansible_user', 'ansible_shell_executable', 'ansible_port', 'ansible_pipelining', 'ansible_password', 'ansible_timeout', 'ansible_shell_type', 'ansible_module_compression', 'ansible_private_key_file')) MAGIC_VARIABLE_MAPPING = dict( # base connection=('ansible_connection', ), module_compression=('ansible_module_compression', ), shell=('ansible_shell_type', ), executable=('ansible_shell_executable', ), # connection common remote_addr=('ansible_ssh_host', 'ansible_host'), remote_user=('ansible_ssh_user', 'ansible_user'), password=('ansible_ssh_pass', 'ansible_password'), port=('ansible_ssh_port', 'ansible_port'), pipelining=('ansible_ssh_pipelining', 'ansible_pipelining'), timeout=('ansible_ssh_timeout', 'ansible_timeout'), private_key_file=('ansible_ssh_private_key_file', 'ansible_private_key_file'), # networking modules network_os=('ansible_network_os', ), connection_user=('ansible_connection_user',), # ssh TODO: remove ssh_executable=('ansible_ssh_executable', ), ssh_common_args=('ansible_ssh_common_args', ), sftp_extra_args=('ansible_sftp_extra_args', ), scp_extra_args=('ansible_scp_extra_args', ), ssh_extra_args=('ansible_ssh_extra_args', ), ssh_transfer_method=('ansible_ssh_transfer_method', ), # docker TODO: remove docker_extra_args=('ansible_docker_extra_args', ), # become become=('ansible_become', ), become_method=('ansible_become_method', ), become_user=('ansible_become_user', ), become_pass=('ansible_become_password', 'ansible_become_pass'), become_exe=('ansible_become_exe', ), become_flags=('ansible_become_flags', ), ) # POPULATE SETTINGS FROM CONFIG ### for setting in config.get_configuration_definitions(): set_constant(setting, config.get_config_value(setting, variables=vars())) ansible_core-2.19.0b5/lib/ansible/context.py0000644000000000000000000000361515017704211017441 0ustar00rootroot# Copyright: (c) 2018, Toshio Kuratomi # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) """ Context of the running Ansible. In the future we *may* create Context objects to allow running multiple Ansible plays in parallel with different contexts but that is currently out of scope as the Ansible library is just for running the ansible command line tools. These APIs are still in flux so do not use them unless you are willing to update them with every Ansible release """ from __future__ import annotations from collections.abc import Mapping, Set from ansible.module_utils.common.collections import is_sequence from ansible.utils.context_objects import CLIArgs, GlobalCLIArgs __all__ = ('CLIARGS',) # Note: this is not the singleton version. The Singleton is only created once the program has # actually parsed the args CLIARGS = CLIArgs({}) # This should be called immediately after cli_args are processed (parsed, validated, and any # normalization performed on them). No other code should call it def _init_global_context(cli_args): """Initialize the global context objects""" global CLIARGS CLIARGS = GlobalCLIArgs.from_options(cli_args) def cliargs_deferred_get(key, default=None, shallowcopy=False): """Closure over getting a key from CLIARGS with shallow copy functionality Primarily used in ``FieldAttribute`` where we need to defer setting the default until after the CLI arguments have been parsed This function is not directly bound to ``CliArgs`` so that it works with ``CLIARGS`` being replaced """ def inner(): value = CLIARGS.get(key, default=default) if not shallowcopy: return value elif is_sequence(value): return value[:] elif isinstance(value, (Mapping, Set)): return value.copy() return value return inner ansible_core-2.19.0b5/lib/ansible/errors/0000755000000000000000000000000015017704211016712 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/errors/__init__.py0000644000000000000000000003770415017704211021036 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import collections.abc as _c import enum import types import typing as t from json import JSONDecodeError from ansible.module_utils.common.text.converters import to_text from ..module_utils.datatag import native_type_name from ansible._internal._datatag import _tags from .._internal._errors import _error_utils from ansible.module_utils._internal import _text_utils if t.TYPE_CHECKING: from ansible.plugins import loader as _t_loader class ExitCode(enum.IntEnum): SUCCESS = 0 # used by TQM, must be bit-flag safe GENERIC_ERROR = 1 # used by TQM, must be bit-flag safe HOST_FAILED = 2 # TQM-sourced, must be bit-flag safe HOST_UNREACHABLE = 4 # TQM-sourced, must be bit-flag safe PARSER_ERROR = 4 # FIXME: CLI-sourced, conflicts with HOST_UNREACHABLE INVALID_CLI_OPTION = 5 UNICODE_ERROR = 6 # obsolete, no longer used KEYBOARD_INTERRUPT = 99 UNKNOWN_ERROR = 250 class AnsibleError(Exception): """ This is the base class for all errors raised from Ansible code, and can be instantiated with two optional parameters beyond the error message to control whether detailed information is displayed when the error occurred while parsing a data file of some kind. Usage: raise AnsibleError('some message here', obj=obj) Where "obj" may be tagged with Origin to provide context for error messages. """ _exit_code = ExitCode.GENERIC_ERROR _default_message = '' _default_help_text: str | None = None _include_cause_message = True """ When `True`, the exception message will be augmented with cause message(s). Subclasses doing complex error analysis can disable this to take responsibility for reporting cause messages as needed. """ def __init__( self, message: str = "", obj: t.Any = None, show_content: bool = True, suppress_extended_error: bool | types.EllipsisType = ..., orig_exc: BaseException | None = None, help_text: str | None = None, ) -> None: # DTFIX-FUTURE: these fallback cases mask incorrect use of AnsibleError.message, what should we do? if message is None: message = '' elif not isinstance(message, str): message = str(message) if self._default_message and message: message = _text_utils.concat_message(self._default_message, message) elif self._default_message: message = self._default_message elif not message: message = f'Unexpected {type(self).__name__} error.' super().__init__(message) self._show_content = show_content self._message = message self._help_text_value = help_text or self._default_help_text self.obj = obj # deprecated: description='deprecate support for orig_exc, callers should use `raise ... from` only' core_version='2.23' # deprecated: description='remove support for orig_exc' core_version='2.27' self.orig_exc = orig_exc if suppress_extended_error is not ...: from ..utils.display import Display if suppress_extended_error: self._show_content = False Display().deprecated( msg=f"The `suppress_extended_error` argument to `{type(self).__name__}` is deprecated. Use `show_content=False` instead.", version="2.23", ) @property def _original_message(self) -> str: return self._message @property def message(self) -> str: """ Return the original message with cause message(s) appended. The cause will not be followed on any `AnsibleError` with `_include_cause_message=False`. """ return _error_utils.format_exception_message(self) @message.setter def message(self, val) -> None: self._message = val @property def _formatted_source_context(self) -> str | None: with _error_utils.RedactAnnotatedSourceContext.when(not self._show_content): if source_context := _error_utils.SourceContext.from_value(self.obj): return str(source_context) return None @property def _help_text(self) -> str | None: return self._help_text_value @_help_text.setter def _help_text(self, value: str | None) -> None: self._help_text_value = value def __str__(self) -> str: return self.message def __getstate__(self) -> dict[str, t.Any]: """Augment object.__getstate__ to preserve additional values not represented in BaseException.__dict__.""" state = t.cast(dict[str, t.Any], super().__getstate__()) state.update( args=self.args, __cause__=self.__cause__, __context__=self.__context__, __suppress_context__=self.__suppress_context__, ) return state def __reduce__(self) -> tuple[t.Callable, tuple[type], dict[str, t.Any]]: """ Enable copy/pickle of AnsibleError derived types by correcting for BaseException's ancient C __reduce__ impl that: * requires use of a type constructor with positional args * assumes positional args are passed through from the derived type __init__ to BaseException.__init__ unmodified * does not propagate args/__cause__/__context__/__suppress_context__ NOTE: This does not preserve the dunder attributes on non-AnsibleError derived cause/context exceptions. As a result, copy/pickle will discard chained exceptions after the first non-AnsibleError cause/context. """ return type(self).__new__, (type(self),), self.__getstate__() class AnsibleUndefinedConfigEntry(AnsibleError): """The requested config entry is not defined.""" class AnsibleTaskError(AnsibleError): """Task execution failed; provides contextual information about the task.""" _default_message = 'Task failed.' class AnsiblePromptInterrupt(AnsibleError): """User interrupt.""" class AnsiblePromptNoninteractive(AnsibleError): """Unable to get user input.""" class AnsibleAssertionError(AnsibleError, AssertionError): """Invalid assertion.""" class AnsibleOptionsError(AnsibleError): """Invalid options were passed.""" # FIXME: This exception is used for many non-CLI related errors. # The few cases which are CLI related should really be handled by argparse instead, at which point the exit code here can be removed. _exit_code = ExitCode.INVALID_CLI_OPTION class AnsibleRequiredOptionError(AnsibleOptionsError): """Bad or incomplete options passed.""" class AnsibleParserError(AnsibleError): """A playbook or data file could not be parsed.""" _exit_code = ExitCode.PARSER_ERROR class AnsibleFieldAttributeError(AnsibleParserError): """Errors caused during field attribute processing.""" class AnsibleJSONParserError(AnsibleParserError): """JSON-specific parsing failure wrapping an exception raised by the JSON parser.""" _default_message = 'JSON parsing failed.' _include_cause_message = False # hide the underlying cause message, it's included by `handle_exception` as needed @classmethod def handle_exception(cls, exception: Exception, origin: _tags.Origin) -> t.NoReturn: if isinstance(exception, JSONDecodeError): origin = origin.replace(line_num=exception.lineno, col_num=exception.colno) message = str(exception) error = cls(message, obj=origin) raise error from exception class AnsibleInternalError(AnsibleError): """Internal safeguards tripped, something happened in the code that should never happen.""" class AnsibleRuntimeError(AnsibleError): """Ansible had a problem while running a playbook.""" class AnsibleModuleError(AnsibleRuntimeError): """A module failed somehow.""" class AnsibleConnectionFailure(AnsibleRuntimeError, _error_utils.ContributesToTaskResult): """ The transport / connection_plugin had a fatal error. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ @property def result_contribution(self) -> t.Mapping[str, object]: return dict(unreachable=True) @property def omit_failed_key(self) -> bool: return True class AnsibleAuthenticationFailure(AnsibleConnectionFailure): """Invalid username/password/key.""" _default_message = "Failed to authenticate." class AnsibleCallbackError(AnsibleRuntimeError): """A callback failure.""" class AnsibleTemplateError(AnsibleRuntimeError): """A template related error.""" class TemplateTrustCheckFailedError(AnsibleTemplateError): """Raised when processing was requested on an untrusted template or expression.""" _default_message = 'Encountered untrusted template or expression.' _default_help_text = ('Templates and expressions must be defined by trusted sources such as playbooks or roles, ' 'not untrusted sources such as module results.') class AnsibleTemplateTransformLimitError(AnsibleTemplateError): """The internal template transform limit was exceeded.""" _default_message = "Template transform limit exceeded." class AnsibleTemplateSyntaxError(AnsibleTemplateError): """A syntax error was encountered while parsing a Jinja template or expression.""" class AnsibleBrokenConditionalError(AnsibleTemplateError): """A broken conditional with non-boolean result was used.""" _default_help_text = 'Broken conditionals can be temporarily allowed with the `ALLOW_BROKEN_CONDITIONALS` configuration option.' class AnsibleUndefinedVariable(AnsibleTemplateError): """An undefined variable was encountered while processing a template or expression.""" class AnsibleValueOmittedError(AnsibleTemplateError): """ Raised when the result of a template operation was the Omit singleton. This exception purposely does not derive from AnsibleError to avoid elision of the traceback, since uncaught errors of this type always indicate a bug. """ _default_message = "A template was resolved to an Omit scalar." _default_help_text = "Callers must be prepared to handle this value. This is most likely a bug in the code requesting templating." class AnsibleTemplatePluginError(AnsibleTemplateError): """An error sourced by a template plugin (lookup/filter/test).""" # deprecated: description='add deprecation warnings for these aliases' core_version='2.23' AnsibleFilterError = AnsibleTemplatePluginError AnsibleLookupError = AnsibleTemplatePluginError class AnsibleFileNotFound(AnsibleRuntimeError): """A file missing failure.""" def __init__(self, message="", obj=None, show_content=True, suppress_extended_error=..., orig_exc=None, paths=None, file_name=None): self.file_name = file_name self.paths = paths if message: message += "\n" if self.file_name: message += "Could not find or access '%s'" % to_text(self.file_name) else: message += "Could not find file" if self.paths and isinstance(self.paths, _c.Sequence): searched = to_text('\n\t'.join(self.paths)) if message: message += "\n" message += "Searched in:\n\t%s" % searched message += " on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option" super(AnsibleFileNotFound, self).__init__(message=message, obj=obj, show_content=show_content, suppress_extended_error=suppress_extended_error, orig_exc=orig_exc) class AnsibleAction(AnsibleRuntimeError, _error_utils.ContributesToTaskResult): """Base Exception for Action plugin flow control.""" def __init__(self, message="", obj=None, show_content=True, suppress_extended_error=..., orig_exc=None, result=None): super().__init__(message=message, obj=obj, show_content=show_content, suppress_extended_error=suppress_extended_error, orig_exc=orig_exc) self._result = result or {} @property def result_contribution(self) -> _c.Mapping[str, object]: return self._result @property def result(self) -> dict[str, object]: """Backward compatibility property returning a mutable dictionary.""" return dict(self.result_contribution) class AnsibleActionSkip(AnsibleAction): """ An action runtime skip. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ @property def result_contribution(self) -> _c.Mapping[str, object]: return self._result | dict( skipped=True, msg=self.message, ) @property def omit_failed_key(self) -> bool: return True @property def omit_exception_key(self) -> bool: return True class AnsibleActionFail(AnsibleAction): """ An action runtime failure. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ @property def result_contribution(self) -> _c.Mapping[str, object]: return self._result | dict( failed=True, msg=self.message, ) class _ActionDone(AnsibleAction): """ Imports as `_AnsibleActionDone` are deprecated. An action runtime early exit. This exception provides a result dictionary via the ContributesToTaskResult mixin. """ @property def omit_failed_key(self) -> bool: return not self._result.get('failed') @property def omit_exception_key(self) -> bool: return not self._result.get('failed') class AnsiblePluginError(AnsibleError): """Base class for Ansible plugin-related errors that do not need AnsibleError contextual data.""" def __init__(self, message: str | None = None, plugin_load_context: _t_loader.PluginLoadContext | None = None, help_text: str | None = None) -> None: super(AnsiblePluginError, self).__init__(message, help_text=help_text) self.plugin_load_context = plugin_load_context class AnsiblePluginRemovedError(AnsiblePluginError): """A requested plugin has been removed.""" class AnsiblePluginCircularRedirect(AnsiblePluginError): """A cycle was detected in plugin redirection.""" class AnsibleCollectionUnsupportedVersionError(AnsiblePluginError): """A collection is not supported by this version of Ansible.""" class AnsibleTypeError(AnsibleRuntimeError, TypeError): """Ansible-augmented TypeError subclass.""" class AnsiblePluginNotFound(AnsiblePluginError): """Indicates we did not find an Ansible plugin.""" class AnsibleConditionalError(AnsibleRuntimeError): """Errors related to failed conditional expression evaluation.""" class AnsibleVariableTypeError(AnsibleRuntimeError): """An error due to attempted storage of an unsupported variable type.""" @classmethod def from_value(cls, *, obj: t.Any) -> t.Self: # avoid an incorrect error message when `obj` is a type type_name = type(obj).__name__ if isinstance(obj, type) else native_type_name(obj) return cls(message=f'Type {type_name!r} is unsupported for variable storage.', obj=obj) def __getattr__(name: str) -> t.Any: """Inject import-time deprecation warnings.""" from ..utils.display import Display match name: case 'AnsibleFilterTypeError': Display().deprecated( msg=f"Importing {name!r} is deprecated.", help_text=f"Import {AnsibleTypeError.__name__!r} instead.", version="2.23", ) return AnsibleTypeError case '_AnsibleActionDone': Display().deprecated( msg=f"Importing {name!r} is deprecated.", help_text="Return directly from action plugins instead.", version="2.23", ) return _ActionDone raise AttributeError(f'module {__name__!r} has no attribute {name!r}') ansible_core-2.19.0b5/lib/ansible/executor/0000755000000000000000000000000015017704211017234 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/executor/__init__.py0000644000000000000000000000135515017704211021351 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . from __future__ import annotations ansible_core-2.19.0b5/lib/ansible/executor/discovery/0000755000000000000000000000000015017704211021243 5ustar00rootrootansible_core-2.19.0b5/lib/ansible/executor/discovery/__init__.py0000644000000000000000000000000015017704211023342 0ustar00rootrootansible_core-2.19.0b5/lib/ansible/executor/interpreter_discovery.py0000644000000000000000000000742215017704211024245 0ustar00rootroot# Copyright: (c) 2018 Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import annotations import re from ansible import constants as C from ansible.errors import AnsibleError from ansible.utils.display import Display from ansible.utils.plugin_docs import get_versioned_doclink _FALLBACK_INTERPRETER = '/usr/bin/python3' display = Display() foundre = re.compile(r'FOUND(.*)ENDFOUND', flags=re.DOTALL) class InterpreterDiscoveryRequiredError(Exception): def __init__(self, message, interpreter_name, discovery_mode): super(InterpreterDiscoveryRequiredError, self).__init__(message) self.interpreter_name = interpreter_name self.discovery_mode = discovery_mode def discover_interpreter(action, interpreter_name, discovery_mode, task_vars): """Probe the target host for a Python interpreter from the `INTERPRETER_PYTHON_FALLBACK` list, returning the first found or `/usr/bin/python3` if none.""" host = task_vars.get('inventory_hostname', 'unknown') res = None found_interpreters = [_FALLBACK_INTERPRETER] # fallback value is_silent = discovery_mode.endswith('_silent') if discovery_mode.startswith('auto_legacy'): display.deprecated( msg=f"The '{discovery_mode}' option for 'INTERPRETER_PYTHON' now has the same effect as 'auto'.", version='2.21', ) try: bootstrap_python_list = C.config.get_config_value('INTERPRETER_PYTHON_FALLBACK', variables=task_vars) display.vvv(msg=f"Attempting {interpreter_name} interpreter discovery.", host=host) # not all command -v impls accept a list of commands, so we have to call it once per python command_list = ["command -v '%s'" % py for py in bootstrap_python_list] shell_bootstrap = "echo FOUND; {0}; echo ENDFOUND".format('; '.join(command_list)) # FUTURE: in most cases we probably don't want to use become, but maybe sometimes we do? res = action._low_level_execute_command(shell_bootstrap, sudoable=False) raw_stdout = res.get('stdout', u'') match = foundre.match(raw_stdout) if not match: display.debug(u'raw interpreter discovery output: {0}'.format(raw_stdout), host=host) raise ValueError('unexpected output from Python interpreter discovery') found_interpreters = [interp.strip() for interp in match.groups()[0].splitlines() if interp.startswith('/')] display.debug(u"found interpreters: {0}".format(found_interpreters), host=host) if not found_interpreters: if not is_silent: display.warning(msg=f'No python interpreters found for host {host!r} (tried {bootstrap_python_list!r}).') # this is lame, but returning None or throwing an exception is uglier return _FALLBACK_INTERPRETER except AnsibleError: raise except Exception as ex: if not is_silent: display.error_as_warning(msg=f'Unhandled error in Python interpreter discovery for host {host!r}.', exception=ex) if res and res.get('stderr'): # the current ssh plugin implementation always has stderr, making coverage of the false case difficult display.vvv(msg=f"Interpreter discovery remote stderr:\n{res.get('stderr')}", host=host) if not is_silent: display.warning( msg=( f"Host {host!r} is using the discovered Python interpreter at {found_interpreters[0]!r}, " "but future installation of another Python interpreter could cause a different interpreter to be discovered." ), help_text=f"See {get_versioned_doclink('reference_appendices/interpreter_discovery.html')} for more information.", ) return found_interpreters[0] ansible_core-2.19.0b5/lib/ansible/executor/module_common.py0000644000000000000000000016360515017704211022456 0ustar00rootroot# (c) 2013-2014, Michael DeHaan # (c) 2015 Toshio Kuratomi # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . from __future__ import annotations import ast import base64 import dataclasses import datetime import json import os import pathlib import pickle import shlex import zipfile import re import pkgutil import types import typing as t from ast import AST, Import, ImportFrom from io import BytesIO from ansible._internal import _locking from ansible._internal._datatag import _utils from ansible.module_utils._internal import _dataclass_validation from ansible.module_utils.common.yaml import yaml_load from ansible.module_utils.datatag import deprecator_from_collection_name from ansible._internal._datatag._tags import Origin from ansible.module_utils.common.json import Direction, get_module_encoder from ansible.release import __version__, __author__ from ansible import constants as C from ansible.errors import AnsibleError from ansible.executor.interpreter_discovery import InterpreterDiscoveryRequiredError from ansible.executor.powershell import module_manifest as ps_manifest from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native from ansible.plugins.become import BecomeBase from ansible.plugins.loader import module_utils_loader from ansible._internal._templating._engine import TemplateOptions, TemplateEngine from ansible.template import Templar from ansible.utils.collection_loader._collection_finder import _get_collection_metadata, _nested_dict_get from ansible.module_utils._internal import _json, _ansiballz from ansible.module_utils import basic as _basic if t.TYPE_CHECKING: from ansible import template as _template from ansible.playbook.task import Task from ansible.utils.display import Display import importlib.util import importlib.machinery display = Display() @dataclasses.dataclass(frozen=True, order=True) class _ModuleUtilsProcessEntry: """Represents a module/module_utils item awaiting import analysis.""" name_parts: tuple[str, ...] is_ambiguous: bool = False child_is_redirected: bool = False is_optional: bool = False @classmethod def from_module(cls, module: types.ModuleType, append: str | None = None) -> t.Self: name = module.__name__ if append: name += '.' + append return cls.from_module_name(name) @classmethod def from_module_name(cls, module_name: str) -> t.Self: return cls(tuple(module_name.split('.'))) REPLACER = b"#<>" REPLACER_VERSION = b"\"<>\"" REPLACER_COMPLEX = b"\"<>\"" REPLACER_WINDOWS = b"# POWERSHELL_COMMON" REPLACER_JSONARGS = b"<>" REPLACER_SELINUX = b"<>" # module_common is relative to module_utils, so fix the path _MODULE_UTILS_PATH = os.path.join(os.path.dirname(__file__), '..', 'module_utils') _SHEBANG_PLACEHOLDER = '# shebang placeholder' # ****************************************************************************** def _strip_comments(source: str) -> str: # Strip comments and blank lines from the wrapper buf = [] for line in source.splitlines(): l = line.strip() if (not l or l.startswith('#')) and l != _SHEBANG_PLACEHOLDER: line = '' buf.append(line) return '\n'.join(buf) def _read_ansiballz_code() -> str: code = (pathlib.Path(__file__).parent.parent / '_internal/_ansiballz.py').read_text() if not C.DEFAULT_KEEP_REMOTE_FILES: # Keep comments when KEEP_REMOTE_FILES is set. That way users will see # the comments with some nice usage instructions. # Otherwise, strip comments for smaller over the wire size. code = _strip_comments(code) return code _ANSIBALLZ_CODE = _read_ansiballz_code() # read during startup to prevent individual workers from doing so def _get_ansiballz_code(shebang: str) -> str: code = _ANSIBALLZ_CODE code = code.replace(_SHEBANG_PLACEHOLDER, shebang) return code # dirname(dirname(dirname(site-packages/ansible/executor/module_common.py) == site-packages # Do this instead of getting site-packages from distutils.sysconfig so we work when we # haven't been installed site_packages = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) CORE_LIBRARY_PATH_RE = re.compile(r'%s/(?Pansible/modules/.*)\.(py|ps1)$' % re.escape(site_packages)) COLLECTION_PATH_RE = re.compile(r'/(?Pansible_collections/[^/]+/[^/]+/plugins/modules/.*)\.(py|ps1)$') # Detect new-style Python modules by looking for required imports: # import ansible_collections.[my_ns.my_col.plugins.module_utils.my_module_util] # from ansible_collections.[my_ns.my_col.plugins.module_utils import my_module_util] # import ansible.module_utils[.basic] # from ansible.module_utils[ import basic] # from ansible.module_utils[.basic import AnsibleModule] # from ..module_utils[ import basic] # from ..module_utils[.basic import AnsibleModule] NEW_STYLE_PYTHON_MODULE_RE = re.compile( # Relative imports br'(?:from +\.{2,} *module_utils.* +import |' # Collection absolute imports: br'from +ansible_collections\.[^.]+\.[^.]+\.plugins\.module_utils.* +import |' br'import +ansible_collections\.[^.]+\.[^.]+\.plugins\.module_utils.*|' # Core absolute imports br'from +ansible\.module_utils.* +import |' br'import +ansible\.module_utils\.)' ) class ModuleDepFinder(ast.NodeVisitor): # DTFIX-FUTURE: add support for ignoring imports with a "controller only" comment, this will allow replacing import_controller_module with standard imports def __init__(self, module_fqn, tree, is_pkg_init=False, *args, **kwargs): """ Walk the ast tree for the python module. :arg module_fqn: The fully qualified name to reach this module in dotted notation. example: ansible.module_utils.basic :arg is_pkg_init: Inform the finder it's looking at a package init (eg __init__.py) to allow relative import expansion to use the proper package level without having imported it locally first. Save submodule[.submoduleN][.identifier] into self.submodules when they are from ansible.module_utils or ansible_collections packages self.submodules will end up with tuples like: - ('ansible', 'module_utils', 'basic',) - ('ansible', 'module_utils', 'urls', 'fetch_url') - ('ansible', 'module_utils', 'database', 'postgres') - ('ansible', 'module_utils', 'database', 'postgres', 'quote') - ('ansible', 'module_utils', 'database', 'postgres', 'quote') - ('ansible_collections', 'my_ns', 'my_col', 'plugins', 'module_utils', 'foo') It's up to calling code to determine whether the final element of the tuple are module names or something else (function, class, or variable names) .. seealso:: :python3:class:`ast.NodeVisitor` """ super(ModuleDepFinder, self).__init__(*args, **kwargs) self._tree = tree # squirrel this away so we can compare node parents to it self.submodules = set() self.optional_imports = set() self.module_fqn = module_fqn self.is_pkg_init = is_pkg_init self._visit_map = { Import: self.visit_Import, ImportFrom: self.visit_ImportFrom, } self.visit(tree) def generic_visit(self, node): """Overridden ``generic_visit`` that makes some assumptions about our use case, and improves performance by calling visitors directly instead of calling ``visit`` to offload calling visitors. """ generic_visit = self.generic_visit visit_map = self._visit_map for field, value in ast.iter_fields(node): if isinstance(value, list): for item in value: if isinstance(item, (Import, ImportFrom)): item.parent = node visit_map[item.__class__](item) elif isinstance(item, AST): generic_visit(item) visit = generic_visit def visit_Import(self, node): """ Handle import ansible.module_utils.MODLIB[.MODLIBn] [as asname] We save these as interesting submodules when the imported library is in ansible.module_utils or ansible.collections """ for alias in node.names: if (alias.name.startswith('ansible.module_utils.') or alias.name.startswith('ansible_collections.')): py_mod = tuple(alias.name.split('.')) self.submodules.add(py_mod) # if the import's parent is the root document, it's a required import, otherwise it's optional if node.parent != self._tree: self.optional_imports.add(py_mod) self.generic_visit(node) def visit_ImportFrom(self, node): """ Handle from ansible.module_utils.MODLIB import [.MODLIBn] [as asname] Also has to handle relative imports We save these as interesting submodules when the imported library is in ansible.module_utils or ansible.collections """ # FIXME: These should all get skipped: # from ansible.executor import module_common # from ...executor import module_common # from ... import executor (Currently it gives a non-helpful error) if node.level > 0: # if we're in a package init, we have to add one to the node level (and make it none if 0 to preserve the right slicing behavior) level_slice_offset = -node.level + 1 or None if self.is_pkg_init else -node.level if self.module_fqn: parts = tuple(self.module_fqn.split('.')) if node.module: # relative import: from .module import x node_module = '.'.join(parts[:level_slice_offset] + (node.module,)) else: # relative import: from . import x node_module = '.'.join(parts[:level_slice_offset]) else: # fall back to an absolute import node_module = node.module else: # absolute import: from module import x node_module = node.module # Specialcase: six is a special case because of its # import logic py_mod = None if node.names[0].name == '_six': self.submodules.add(('_six',)) elif node_module.startswith('ansible.module_utils'): # from ansible.module_utils.MODULE1[.MODULEn] import IDENTIFIER [as asname] # from ansible.module_utils.MODULE1[.MODULEn] import MODULEn+1 [as asname] # from ansible.module_utils.MODULE1[.MODULEn] import MODULEn+1 [,IDENTIFIER] [as asname] # from ansible.module_utils import MODULE1 [,MODULEn] [as asname] py_mod = tuple(node_module.split('.')) elif node_module.startswith('ansible_collections.'): if node_module.endswith('plugins.module_utils') or '.plugins.module_utils.' in node_module: # from ansible_collections.ns.coll.plugins.module_utils import MODULE [as aname] [,MODULE2] [as aname] # from ansible_collections.ns.coll.plugins.module_utils.MODULE import IDENTIFIER [as aname] # FIXME: Unhandled cornercase (needs to be ignored): # from ansible_collections.ns.coll.plugins.[!module_utils].[FOO].plugins.module_utils import IDENTIFIER py_mod = tuple(node_module.split('.')) else: # Not from module_utils so ignore. for instance: # from ansible_collections.ns.coll.plugins.lookup import IDENTIFIER pass if py_mod: for alias in node.names: self.submodules.add(py_mod + (alias.name,)) # if the import's parent is the root document, it's a required import, otherwise it's optional if node.parent != self._tree: self.optional_imports.add(py_mod + (alias.name,)) self.generic_visit(node) def _slurp(path): if not os.path.exists(path): raise AnsibleError("imported module support code does not exist at %s" % os.path.abspath(path)) with open(path, 'rb') as fd: data = fd.read() return data def _get_shebang(interpreter, task_vars, templar: _template.Templar, args=tuple(), remote_is_local=False): """ Handles the different ways ansible allows overriding the shebang target for a module. """ # FUTURE: add logical equivalence for python3 in the case of py3-only modules interpreter_name = os.path.basename(interpreter).strip() # name for interpreter var interpreter_config = u'ansible_%s_interpreter' % interpreter_name # key for config interpreter_config_key = "INTERPRETER_%s" % interpreter_name.upper() interpreter_out = None # looking for python, rest rely on matching vars if interpreter_name == 'python': # skip detection for network os execution, use playbook supplied one if possible if remote_is_local: interpreter_out = task_vars['ansible_playbook_python'] # a config def exists for this interpreter type; consult config for the value elif C.config.get_configuration_definition(interpreter_config_key): interpreter_from_config = C.config.get_config_value(interpreter_config_key, variables=task_vars) interpreter_out = templar._engine.template(_utils.str_problematic_strip(interpreter_from_config), options=TemplateOptions(value_for_omit=C.config.get_config_default(interpreter_config_key))) # handle interpreter discovery if requested or empty interpreter was provided if not interpreter_out or interpreter_out in ['auto', 'auto_legacy', 'auto_silent', 'auto_legacy_silent']: discovered_interpreter_config = u'discovered_interpreter_%s' % interpreter_name facts_from_task_vars = task_vars.get('ansible_facts', {}) if discovered_interpreter_config not in facts_from_task_vars: # interpreter discovery is desired, but has not been run for this host raise InterpreterDiscoveryRequiredError("interpreter discovery needed", interpreter_name=interpreter_name, discovery_mode=interpreter_out) else: interpreter_out = facts_from_task_vars[discovered_interpreter_config] else: raise InterpreterDiscoveryRequiredError("interpreter discovery required", interpreter_name=interpreter_name, discovery_mode='auto_legacy') elif interpreter_config in task_vars: # for non python we consult vars for a possible direct override interpreter_out = templar._engine.template(_utils.str_problematic_strip(task_vars.get(interpreter_config)), options=TemplateOptions(value_for_omit=None)) if not interpreter_out: # nothing matched(None) or in case someone configures empty string or empty intepreter interpreter_out = interpreter # set shebang shebang = u'#!{0}'.format(interpreter_out) if args: shebang = shebang + u' ' + u' '.join(args) return shebang, interpreter_out class ModuleUtilLocatorBase: def __init__(self, fq_name_parts, is_ambiguous=False, child_is_redirected=False, is_optional=False): self._is_ambiguous = is_ambiguous # a child package redirection could cause intermediate package levels to be missing, eg # from ansible.module_utils.x.y.z import foo; if x.y.z.foo is redirected, we may not have packages on disk for # the intermediate packages x.y.z, so we'll need to supply empty packages for those self._child_is_redirected = child_is_redirected self._is_optional = is_optional self.found = False self.redirected = False self.fq_name_parts = fq_name_parts self.source_code = '' self.output_path = '' self.is_package = False self._collection_name = None # for ambiguous imports, we should only test for things more than one level below module_utils # this lets us detect erroneous imports and redirections earlier if is_ambiguous and len(self._get_module_utils_remainder_parts(fq_name_parts)) > 1: self.candidate_names = [fq_name_parts, fq_name_parts[:-1]] else: self.candidate_names = [fq_name_parts] @property def candidate_names_joined(self): return ['.'.join(n) for n in self.candidate_names] def _handle_redirect(self, name_parts): module_utils_relative_parts = self._get_module_utils_remainder_parts(name_parts) # only allow redirects from below module_utils- if above that, bail out (eg, parent package names) if not module_utils_relative_parts: return False try: collection_metadata = _get_collection_metadata(self._collection_name) except ValueError as ve: # collection not found or some other error related to collection load if self._is_optional: return False raise AnsibleError('error processing module_util {0} loading redirected collection {1}: {2}' .format('.'.join(name_parts), self._collection_name, to_native(ve))) routing_entry = _nested_dict_get(collection_metadata, ['plugin_routing', 'module_utils', '.'.join(module_utils_relative_parts)]) if not routing_entry: return False # FIXME: add deprecation warning support dep_or_ts = routing_entry.get('tombstone') removed = dep_or_ts is not None if not removed: dep_or_ts = routing_entry.get('deprecation') if dep_or_ts: removal_date = dep_or_ts.get('removal_date') removal_version = dep_or_ts.get('removal_version') warning_text = dep_or_ts.get('warning_text') msg = 'module_util {0} has been removed'.format('.'.join(name_parts)) if warning_text: msg += ' ({0})'.format(warning_text) else: msg += '.' display.deprecated( # pylint: disable=ansible-deprecated-date-not-permitted,ansible-deprecated-unnecessary-collection-name msg=msg, version=removal_version, removed=removed, date=removal_date, deprecator=deprecator_from_collection_name(self._collection_name), ) if 'redirect' in routing_entry: self.redirected = True source_pkg = '.'.join(name_parts) self.is_package = True # treat all redirects as packages redirect_target_pkg = routing_entry['redirect'] # expand FQCN redirects if not redirect_target_pkg.startswith('ansible_collections'): split_fqcn = redirect_target_pkg.split('.') if len(split_fqcn) < 3: raise Exception('invalid redirect for {0}: {1}'.format(source_pkg, redirect_target_pkg)) # assume it's an FQCN, expand it redirect_target_pkg = 'ansible_collections.{0}.{1}.plugins.module_utils.{2}'.format( split_fqcn[0], # ns split_fqcn[1], # coll '.'.join(split_fqcn[2:]) # sub-module_utils remainder ) display.vvv('redirecting module_util {0} to {1}'.format(source_pkg, redirect_target_pkg)) self.source_code = self._generate_redirect_shim_source(source_pkg, redirect_target_pkg) return True return False def _get_module_utils_remainder_parts(self, name_parts): # subclasses should override to return the name parts after module_utils return [] def _get_module_utils_remainder(self, name_parts): # return the remainder parts as a package string return '.'.join(self._get_module_utils_remainder_parts(name_parts)) def _find_module(self, name_parts): return False def _locate(self, redirect_first=True): for candidate_name_parts in self.candidate_names: if redirect_first and self._handle_redirect(candidate_name_parts): break if self._find_module(candidate_name_parts): break if not redirect_first and self._handle_redirect(candidate_name_parts): break else: # didn't find what we were looking for- last chance for packages whose parents were redirected if self._child_is_redirected: # make fake packages self.is_package = True self.source_code = '' else: # nope, just bail return if self.is_package: path_parts = candidate_name_parts + ('__init__',) else: path_parts = candidate_name_parts self.found = True self.output_path = os.path.join(*path_parts) + '.py' self.fq_name_parts = candidate_name_parts def _generate_redirect_shim_source(self, fq_source_module, fq_target_module): return """ import sys import {1} as mod sys.modules['{0}'] = mod """.format(fq_source_module, fq_target_module) # FIXME: add __repr__ impl class LegacyModuleUtilLocator(ModuleUtilLocatorBase): def __init__(self, fq_name_parts, is_ambiguous=False, mu_paths=None, child_is_redirected=False): super(LegacyModuleUtilLocator, self).__init__(fq_name_parts, is_ambiguous, child_is_redirected) if fq_name_parts[0:2] != ('ansible', 'module_utils'): raise Exception('this class can only locate from ansible.module_utils, got {0}'.format(fq_name_parts)) if fq_name_parts[2] == 'six': # FIXME: handle the ansible.module_utils.six._six case with a redirect or an internal _six attr on six itself? # six creates its submodules at runtime; convert all these to just 'ansible.module_utils.six' fq_name_parts = ('ansible', 'module_utils', 'six') self.candidate_names = [fq_name_parts] self._mu_paths = mu_paths self._collection_name = 'ansible.builtin' # legacy module utils always look in ansible.builtin for redirects self._locate(redirect_first=False) # let local stuff override redirects for legacy def _get_module_utils_remainder_parts(self, name_parts): return name_parts[2:] # eg, foo.bar for ansible.module_utils.foo.bar def _find_module(self, name_parts): rel_name_parts = self._get_module_utils_remainder_parts(name_parts) # no redirection; try to find the module if len(rel_name_parts) == 1: # direct child of module_utils, just search the top-level dirs we were given paths = self._mu_paths else: # a nested submodule of module_utils, extend the paths given with the intermediate package names paths = [os.path.join(p, *rel_name_parts[:-1]) for p in self._mu_paths] # extend the MU paths with the relative bit # find_spec needs the full module name self._info = info = importlib.machinery.PathFinder.find_spec('.'.join(name_parts), paths) if info is not None and info.origin is not None and os.path.splitext(info.origin)[1] in importlib.machinery.SOURCE_SUFFIXES: self.is_package = info.origin.endswith('/__init__.py') path = info.origin else: return False self.source_code = Origin(path=path).tag(_slurp(path)) return True class CollectionModuleUtilLocator(ModuleUtilLocatorBase): def __init__(self, fq_name_parts, is_ambiguous=False, child_is_redirected=False, is_optional=False): super(CollectionModuleUtilLocator, self).__init__(fq_name_parts, is_ambiguous, child_is_redirected, is_optional) if fq_name_parts[0] != 'ansible_collections': raise Exception('CollectionModuleUtilLocator can only locate from ansible_collections, got {0}'.format(fq_name_parts)) elif len(fq_name_parts) >= 6 and fq_name_parts[3:5] != ('plugins', 'module_utils'): raise Exception('CollectionModuleUtilLocator can only locate below ansible_collections.(ns).(coll).plugins.module_utils, got {0}' .format(fq_name_parts)) self._collection_name = '.'.join(fq_name_parts[1:3]) self._locate() def _find_module(self, name_parts): # synthesize empty inits for packages down through module_utils- we don't want to allow those to be shipped over, but the # package hierarchy needs to exist if len(name_parts) < 6: self.source_code = '' self.is_package = True return True # NB: we can't use pkgutil.get_data safely here, since we don't want to import/execute package/module code on # the controller while analyzing/assembling the module, so we'll have to manually import the collection's # Python package to locate it (import root collection, reassemble resource path beneath, fetch source) collection_pkg_name = '.'.join(name_parts[0:3]) resource_base_path = os.path.join(*name_parts[3:]) src = None # look for package_dir first, then module src_path = to_native(os.path.join(resource_base_path, '__init__.py')) try: collection_pkg = importlib.import_module(collection_pkg_name) pkg_path = os.path.dirname(collection_pkg.__file__) except (ImportError, AttributeError): pkg_path = None try: src = pkgutil.get_data(collection_pkg_name, src_path) except ImportError: pass # TODO: we might want to synthesize fake inits for py3-style packages, for now they're required beneath module_utils if src is not None: # empty string is OK self.is_package = True else: src_path = to_native(resource_base_path + '.py') try: src = pkgutil.get_data(collection_pkg_name, src_path) except ImportError: pass if src is None: # empty string is OK return False # TODO: this feels brittle and funky; we should be able to more definitively assure the source path if pkg_path: origin = Origin(path=os.path.join(pkg_path, src_path)) else: # DTFIX-FUTURE: not sure if this case is even reachable origin = Origin(description=f'') self.source_code = origin.tag(src) return True def _get_module_utils_remainder_parts(self, name_parts): return name_parts[5:] # eg, foo.bar for ansible_collections.ns.coll.plugins.module_utils.foo.bar def _make_zinfo(filename: str, date_time: datetime.datetime, zf: zipfile.ZipFile | None = None) -> zipfile.ZipInfo: zinfo = zipfile.ZipInfo( filename=filename, date_time=date_time.utctimetuple()[:6], ) if zf: zinfo.compress_type = zf.compression return zinfo @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class ModuleMetadata: @classmethod def __post_init__(cls): _dataclass_validation.inject_post_init_validation(cls) @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class ModuleMetadataV1(ModuleMetadata): serialization_profile: str metadata_versions: dict[t.Any, type[ModuleMetadata]] = { 1: ModuleMetadataV1, } def _get_module_metadata(module: ast.Module) -> ModuleMetadata: # DTFIX2: while module metadata works, this feature isn't fully baked and should be turned off before release metadata_nodes: list[ast.Assign] = [] for node in module.body: if isinstance(node, ast.Assign): if len(node.targets) == 1: target = node.targets[0] if isinstance(target, ast.Name): if target.id == 'METADATA': metadata_nodes.append(node) if not metadata_nodes: return ModuleMetadataV1( serialization_profile='legacy', ) if len(metadata_nodes) > 1: raise ValueError('Module METADATA must defined only once.') metadata_node = metadata_nodes[0] if not isinstance(metadata_node.value, ast.Constant): raise TypeError(f'Module METADATA node must be {ast.Constant} not {type(metadata_node)}.') unparsed_metadata = metadata_node.value.value if not isinstance(unparsed_metadata, str): raise TypeError(f'Module METADATA must be {str} not {type(unparsed_metadata)}.') try: parsed_metadata = yaml_load(unparsed_metadata) except Exception as ex: raise ValueError('Module METADATA must be valid YAML.') from ex if not isinstance(parsed_metadata, dict): raise TypeError(f'Module METADATA must parse to {dict} not {type(parsed_metadata)}.') schema_version = parsed_metadata.pop('schema_version', None) if not (metadata_type := metadata_versions.get(schema_version)): raise ValueError(f'Module METADATA schema_version {schema_version} is unknown.') try: metadata = metadata_type(**parsed_metadata) # type: ignore except Exception as ex: raise ValueError('Module METADATA is invalid.') from ex return metadata def recursive_finder(name: str, module_fqn: str, module_data: str | bytes, zf: zipfile.ZipFile, date_time: datetime.datetime) -> ModuleMetadata: """ Using ModuleDepFinder, make sure we have all of the module_utils files that the module and its module_utils files needs. (no longer actually recursive) :arg name: Name of the python module we're examining :arg module_fqn: Fully qualified name of the python module we're scanning :arg module_data: string Python code of the module we're scanning :arg zf: An open :python:class:`zipfile.ZipFile` object that holds the Ansible module payload which we're assembling """ # py_module_cache maps python module names to a tuple of the code in the module # and the pathname to the module. # Here we pre-load it with modules which we create without bothering to # read from actual files (In some cases, these need to differ from what ansible # ships because they're namespace packages in the module) # FIXME: do we actually want ns pkg behavior for these? Seems like they should just be forced to emptyish pkg stubs py_module_cache = { ('ansible',): ( b'from pkgutil import extend_path\n' b'__path__=extend_path(__path__,__name__)\n' b'__version__="' + to_bytes(__version__) + b'"\n__author__="' + to_bytes(__author__) + b'"\n', 'ansible/__init__.py'), ('ansible', 'module_utils'): ( b'from pkgutil import extend_path\n' b'__path__=extend_path(__path__,__name__)\n', 'ansible/module_utils/__init__.py')} module_utils_paths = [p for p in module_utils_loader._get_paths(subdirs=False) if os.path.isdir(p)] module_utils_paths.append(_MODULE_UTILS_PATH) tree = _compile_module_ast(name, module_data) module_metadata = _get_module_metadata(tree) finder = ModuleDepFinder(module_fqn, tree) if not isinstance(module_metadata, ModuleMetadataV1): raise NotImplementedError() profile = module_metadata.serialization_profile # the format of this set is a tuple of the module name and whether the import is ambiguous as a module name # or an attribute of a module (e.g. from x.y import z <-- is z a module or an attribute of x.y?) modules_to_process = [_ModuleUtilsProcessEntry(m, True, False, is_optional=m in finder.optional_imports) for m in finder.submodules] # include module_utils that are always required modules_to_process.extend(( _ModuleUtilsProcessEntry.from_module(_ansiballz), _ModuleUtilsProcessEntry.from_module(_basic), _ModuleUtilsProcessEntry.from_module_name(_json.get_module_serialization_profile_module_name(profile, True)), _ModuleUtilsProcessEntry.from_module_name(_json.get_module_serialization_profile_module_name(profile, False)), )) module_info: ModuleUtilLocatorBase # we'll be adding new modules inline as we discover them, so just keep going til we've processed them all while modules_to_process: modules_to_process.sort() # not strictly necessary, but nice to process things in predictable and repeatable order entry = modules_to_process.pop(0) if entry.name_parts in py_module_cache: # this is normal; we'll often see the same module imported many times, but we only need to process it once continue if entry.name_parts[0:2] == ('ansible', 'module_utils'): module_info = LegacyModuleUtilLocator(entry.name_parts, is_ambiguous=entry.is_ambiguous, mu_paths=module_utils_paths, child_is_redirected=entry.child_is_redirected) elif entry.name_parts[0] == 'ansible_collections': module_info = CollectionModuleUtilLocator(entry.name_parts, is_ambiguous=entry.is_ambiguous, child_is_redirected=entry.child_is_redirected, is_optional=entry.is_optional) else: # FIXME: dot-joined result display.warning('ModuleDepFinder improperly found a non-module_utils import %s' % [entry.name_parts]) continue # Could not find the module. Construct a helpful error message. if not module_info.found: if entry.is_optional: # this was a best-effort optional import that we couldn't find, oh well, move along... continue # FIXME: use dot-joined candidate names msg = 'Could not find imported module support code for {0}. Looked for ({1})'.format(module_fqn, module_info.candidate_names_joined) raise AnsibleError(msg) # check the cache one more time with the module we actually found, since the name could be different than the input # eg, imported name vs module if module_info.fq_name_parts in py_module_cache: continue tree = _compile_module_ast('.'.join(module_info.fq_name_parts), module_info.source_code) finder = ModuleDepFinder('.'.join(module_info.fq_name_parts), tree, module_info.is_package) modules_to_process.extend(_ModuleUtilsProcessEntry(m, True, False, is_optional=m in finder.optional_imports) for m in finder.submodules if m not in py_module_cache) # we've processed this item, add it to the output list py_module_cache[module_info.fq_name_parts] = (module_info.source_code, module_info.output_path) # ensure we process all ancestor package inits accumulated_pkg_name = [] for pkg in module_info.fq_name_parts[:-1]: accumulated_pkg_name.append(pkg) # we're accumulating this across iterations normalized_name = tuple(accumulated_pkg_name) # extra machinations to get a hashable type (list is not) if normalized_name not in py_module_cache: modules_to_process.append(_ModuleUtilsProcessEntry(normalized_name, False, module_info.redirected, is_optional=entry.is_optional)) for py_module_name in py_module_cache: py_module_file_name = py_module_cache[py_module_name][1] zf.writestr( _make_zinfo(py_module_file_name, date_time, zf=zf), py_module_cache[py_module_name][0] ) mu_file = to_text(py_module_file_name, errors='surrogate_or_strict') display.vvvvv("Including module_utils file %s" % mu_file) return module_metadata def _compile_module_ast(module_name: str, source_code: str | bytes) -> ast.Module: origin = Origin.get_tag(source_code) or Origin.UNKNOWN # compile the source, process all relevant imported modules try: tree = t.cast(ast.Module, compile(source_code, str(origin), 'exec', ast.PyCF_ONLY_AST)) except SyntaxError as ex: raise AnsibleError(f"Unable to compile {module_name!r}.", obj=origin.replace(line_num=ex.lineno, col_num=ex.offset)) from ex return tree def _is_binary(b_module_data): """Heuristic to classify a file as binary by sniffing a 1k header; see https://stackoverflow.com/a/7392391""" textchars = bytearray(set([7, 8, 9, 10, 12, 13, 27]) | set(range(0x20, 0x100)) - set([0x7f])) start = b_module_data[:1024] return bool(start.translate(None, textchars)) def _get_ansible_module_fqn(module_path): """ Get the fully qualified name for an ansible module based on its pathname remote_module_fqn is the fully qualified name. Like ansible.modules.system.ping Or ansible_collections.Namespace.Collection_name.plugins.modules.ping .. warning:: This function is for ansible modules only. It won't work for other things (non-module plugins, etc) """ remote_module_fqn = None # Is this a core module? match = CORE_LIBRARY_PATH_RE.search(module_path) if not match: # Is this a module in a collection? match = COLLECTION_PATH_RE.search(module_path) # We can tell the FQN for core modules and collection modules if match: path = match.group('path') if '.' in path: # FQNs must be valid as python identifiers. This sanity check has failed. # we could check other things as well raise ValueError('Module name (or path) was not a valid python identifier') remote_module_fqn = '.'.join(path.split('/')) else: # Currently we do not handle modules in roles so we can end up here for that reason raise ValueError("Unable to determine module's fully qualified name") return remote_module_fqn def _add_module_to_zip(zf: zipfile.ZipFile, date_time: datetime.datetime, remote_module_fqn: str, b_module_data: bytes) -> None: """Add a module from ansible or from an ansible collection into the module zip""" module_path_parts = remote_module_fqn.split('.') # Write the module module_path = '/'.join(module_path_parts) + '.py' zf.writestr( _make_zinfo(module_path, date_time, zf=zf), b_module_data ) existing_paths: frozenset[str] # Write the __init__.py's necessary to get there if module_path_parts[0] == 'ansible': # The ansible namespace is setup as part of the module_utils setup... start = 2 existing_paths = frozenset() else: # ... but ansible_collections and other toplevels are not start = 1 existing_paths = frozenset(zf.namelist()) for idx in range(start, len(module_path_parts)): package_path = '/'.join(module_path_parts[:idx]) + '/__init__.py' # If a collections module uses module_utils from a collection then most packages will have already been added by recursive_finder. if package_path in existing_paths: continue # Note: We don't want to include more than one ansible module in a payload at this time # so no need to fill the __init__.py with namespace code zf.writestr( _make_zinfo(package_path, date_time, zf=zf), b'' ) @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class _BuiltModule: """Payload required to execute an Ansible module, along with information required to do so.""" b_module_data: bytes module_style: t.Literal['binary', 'new', 'non_native_want_json', 'old'] shebang: str | None serialization_profile: str @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) class _CachedModule: """Cached Python module created by AnsiballZ.""" # DTFIX5: secure this (locked down pickle, don't use pickle, etc.) zip_data: bytes metadata: ModuleMetadata def dump(self, path: str) -> None: temp_path = pathlib.Path(path + '-part') with temp_path.open('wb') as cache_file: pickle.dump(self, cache_file) temp_path.rename(path) @classmethod def load(cls, path: str) -> t.Self: with pathlib.Path(path).open('rb') as cache_file: return pickle.load(cache_file) def _find_module_utils( *, module_name: str, b_module_data: bytes, module_path: str, module_args: dict[object, object], task_vars: dict[str, object], templar: Templar, module_compression: str, async_timeout: int, become_plugin: BecomeBase | None, environment: dict[str, str], remote_is_local: bool = False ) -> _BuiltModule: """ Given the source of the module, convert it to a Jinja2 template to insert module code and return whether it's a new or old style module. """ module_substyle: t.Literal['binary', 'jsonargs', 'non_native_want_json', 'old', 'powershell', 'python'] module_style: t.Literal['binary', 'new', 'non_native_want_json', 'old'] module_substyle = module_style = 'old' # module_style is something important to calling code (ActionBase). It # determines how arguments are formatted (json vs k=v) and whether # a separate arguments file needs to be sent over the wire. # module_substyle is extra information that's useful internally. It tells # us what we have to look to substitute in the module files and whether # we're using module replacer or ansiballz to format the module itself. if _is_binary(b_module_data): module_substyle = module_style = 'binary' elif REPLACER in b_module_data: # Do REPLACER before from ansible.module_utils because we need make sure # we substitute "from ansible.module_utils basic" for REPLACER module_style = 'new' module_substyle = 'python' b_module_data = b_module_data.replace(REPLACER, b'from ansible.module_utils.basic import *') elif NEW_STYLE_PYTHON_MODULE_RE.search(b_module_data): module_style = 'new' module_substyle = 'python' elif REPLACER_WINDOWS in b_module_data: module_style = 'new' module_substyle = 'powershell' b_module_data = b_module_data.replace(REPLACER_WINDOWS, b'#AnsibleRequires -PowerShell Ansible.ModuleUtils.Legacy') elif re.search(b'#Requires -Module', b_module_data, re.IGNORECASE) \ or re.search(b'#Requires -Version', b_module_data, re.IGNORECASE) \ or re.search(b'#AnsibleRequires -(OSVersion|PowerShell|CSharpUtil|Wrapper)', b_module_data, re.IGNORECASE): module_style = 'new' module_substyle = 'powershell' elif REPLACER_JSONARGS in b_module_data: module_style = 'new' module_substyle = 'jsonargs' elif b'WANT_JSON' in b_module_data: module_substyle = module_style = 'non_native_want_json' shebang = None # Neither old-style, non_native_want_json nor binary modules should be modified # except for the shebang line (Done by modify_module) if module_style in ('old', 'non_native_want_json', 'binary'): return _BuiltModule( b_module_data=b_module_data, module_style=module_style, shebang=shebang, serialization_profile='legacy', ) output = BytesIO() try: remote_module_fqn = _get_ansible_module_fqn(module_path) except ValueError: # Modules in roles currently are not found by the fqn heuristic so we # fallback to this. This means that relative imports inside a module from # a role may fail. Absolute imports should be used for future-proofness. # People should start writing collections instead of modules in roles so we # may never fix this display.debug('ANSIBALLZ: Could not determine module FQN') # FIXME: add integration test to validate that builtins and legacy modules with the same name are tracked separately by the caching mechanism # FIXME: surrogate FQN should be unique per source path- role-packaged modules with name collisions can still be aliased remote_module_fqn = 'ansible.legacy.%s' % module_name if module_substyle == 'python': date_time = datetime.datetime.now(datetime.timezone.utc) if date_time.year < 1980: raise AnsibleError(f'Cannot create zipfile due to pre-1980 configured date: {date_time}') try: compression_method = getattr(zipfile, module_compression) except AttributeError: display.warning(u'Bad module compression string specified: %s. Using ZIP_STORED (no compression)' % module_compression) compression_method = zipfile.ZIP_STORED lookup_path = os.path.join(C.DEFAULT_LOCAL_TMP, 'ansiballz_cache') # type: ignore[attr-defined] cached_module_filename = os.path.join(lookup_path, "%s-%s" % (remote_module_fqn, module_compression)) os.makedirs(os.path.dirname(cached_module_filename), exist_ok=True) zipdata: bytes | None = None module_metadata: ModuleMetadata | None = None # Optimization -- don't lock if the module has already been cached if os.path.exists(cached_module_filename): display.debug('ANSIBALLZ: using cached module: %s' % cached_module_filename) cached_module = _CachedModule.load(cached_module_filename) zipdata, module_metadata = cached_module.zip_data, cached_module.metadata else: display.debug('ANSIBALLZ: Acquiring lock') lock_path = f'{cached_module_filename}.lock' with _locking.named_mutex(lock_path): display.debug(f'ANSIBALLZ: Lock acquired: {lock_path}') # Check that no other process has created this while we were # waiting for the lock if not os.path.exists(cached_module_filename): display.debug('ANSIBALLZ: Creating module') # Create the module zip data zipoutput = BytesIO() zf = zipfile.ZipFile(zipoutput, mode='w', compression=compression_method) # walk the module imports, looking for module_utils to send- they'll be added to the zipfile module_metadata = recursive_finder(module_name, remote_module_fqn, Origin(path=module_path).tag(b_module_data), zf, date_time) display.debug('ANSIBALLZ: Writing module into payload') _add_module_to_zip(zf, date_time, remote_module_fqn, b_module_data) zf.close() zipdata = base64.b64encode(zipoutput.getvalue()) # Write the assembled module to a temp file (write to temp # so that no one looking for the file reads a partially # written file) os.makedirs(lookup_path, exist_ok=True) display.debug('ANSIBALLZ: Writing module') cached_module = _CachedModule(zip_data=zipdata, metadata=module_metadata) cached_module.dump(cached_module_filename) display.debug('ANSIBALLZ: Done creating module') if not zipdata: display.debug('ANSIBALLZ: Reading module after lock') # Another process wrote the file while we were waiting for # the write lock. Go ahead and read the data from disk # instead of re-creating it. try: cached_module = _CachedModule.load(cached_module_filename) except IOError: raise AnsibleError('A different worker process failed to create module file. ' 'Look at traceback for that process for debugging information.') zipdata, module_metadata = cached_module.zip_data, cached_module.metadata o_interpreter, o_args = _extract_interpreter(b_module_data) if o_interpreter is None: o_interpreter = u'/usr/bin/python' shebang, interpreter = _get_shebang(o_interpreter, task_vars, templar, o_args, remote_is_local=remote_is_local) # FUTURE: the module cache entry should be invalidated if we got this value from a host-dependent source rlimit_nofile = C.config.get_config_value('PYTHON_MODULE_RLIMIT_NOFILE', variables=task_vars) if not isinstance(rlimit_nofile, int): rlimit_nofile = int(templar._engine.template(rlimit_nofile, options=TemplateOptions(value_for_omit=0))) coverage_config = os.environ.get('_ANSIBLE_COVERAGE_CONFIG') if coverage_config: coverage_output = os.environ['_ANSIBLE_COVERAGE_OUTPUT'] else: coverage_output = None if not isinstance(module_metadata, ModuleMetadataV1): raise NotImplementedError() params = dict(ANSIBLE_MODULE_ARGS=module_args,) encoder = get_module_encoder(module_metadata.serialization_profile, Direction.CONTROLLER_TO_MODULE) try: encoded_params = json.dumps(params, cls=encoder) except TypeError as ex: raise AnsibleError(f'Failed to serialize arguments for the {module_name!r} module.') from ex code = _get_ansiballz_code(shebang) args = dict( zipdata=to_text(zipdata), ansible_module=module_name, module_fqn=remote_module_fqn, params=encoded_params, profile=module_metadata.serialization_profile, date_time=date_time, coverage_config=coverage_config, coverage_output=coverage_output, rlimit_nofile=rlimit_nofile, ) args_string = '\n'.join(f'{key}={value!r},' for key, value in args.items()) wrapper = f"""{code} if __name__ == "__main__": _ansiballz_main( {args_string} ) """ output.write(to_bytes(wrapper)) b_module_data = output.getvalue() elif module_substyle == 'powershell': module_metadata = ModuleMetadataV1(serialization_profile='legacy') # DTFIX-FUTURE: support serialization profiles for PowerShell modules # Powershell/winrm don't actually make use of shebang so we can # safely set this here. If we let the fallback code handle this # it can fail in the presence of the UTF8 BOM commonly added by # Windows text editors shebang = '#!powershell' # create the common exec wrapper payload and set that as the module_data # bytes b_module_data = ps_manifest._create_powershell_wrapper( name=remote_module_fqn, module_data=b_module_data, module_path=module_path, module_args=module_args, environment=environment, async_timeout=async_timeout, become_plugin=become_plugin, substyle=module_substyle, task_vars=task_vars, profile=module_metadata.serialization_profile, ) elif module_substyle == 'jsonargs': encoder = get_module_encoder('legacy', Direction.CONTROLLER_TO_MODULE) module_args_json = to_bytes(json.dumps(module_args, cls=encoder)) # these strings could be included in a third-party module but # officially they were included in the 'basic' snippet for new-style # python modules (which has been replaced with something else in # ansiballz) If we remove them from jsonargs-style module replacer # then we can remove them everywhere. python_repred_args = to_bytes(repr(module_args_json)) b_module_data = b_module_data.replace(REPLACER_VERSION, to_bytes(repr(__version__))) b_module_data = b_module_data.replace(REPLACER_COMPLEX, python_repred_args) b_module_data = b_module_data.replace( REPLACER_SELINUX, to_bytes(','.join(C.DEFAULT_SELINUX_SPECIAL_FS))) # type: ignore[attr-defined] # The main event -- substitute the JSON args string into the module b_module_data = b_module_data.replace(REPLACER_JSONARGS, module_args_json) syslog_facility = task_vars.get( 'ansible_syslog_facility', C.DEFAULT_SYSLOG_FACILITY) # type: ignore[attr-defined] facility = b'syslog.' + to_bytes(syslog_facility, errors='surrogate_or_strict') b_module_data = b_module_data.replace(b'syslog.LOG_USER', facility) module_metadata = ModuleMetadataV1(serialization_profile='legacy') else: module_metadata = ModuleMetadataV1(serialization_profile='legacy') if not isinstance(module_metadata, ModuleMetadataV1): raise NotImplementedError(type(module_metadata)) return _BuiltModule( b_module_data=b_module_data, module_style=module_style, shebang=shebang, serialization_profile=module_metadata.serialization_profile, ) def _extract_interpreter(b_module_data): """ Used to extract shebang expression from binary module data and return a text string with the shebang, or None if no shebang is detected. """ interpreter = None args = [] b_lines = b_module_data.split(b"\n", 1) if b_lines[0].startswith(b"#!"): b_shebang = b_lines[0].strip() # shlex.split needs text on Python 3 cli_split = shlex.split(to_text(b_shebang[2:], errors='surrogate_or_strict')) # convert args to text cli_split = [to_text(a, errors='surrogate_or_strict') for a in cli_split] interpreter = cli_split[0] args = cli_split[1:] return interpreter, args def modify_module( *, module_name: str, module_path, module_args, templar, task_vars=None, module_compression='ZIP_STORED', async_timeout=0, become_plugin=None, environment=None, remote_is_local=False, ) -> _BuiltModule: """ Used to insert chunks of code into modules before transfer rather than doing regular python imports. This allows for more efficient transfer in a non-bootstrapping scenario by not moving extra files over the wire and also takes care of embedding arguments in the transferred modules. This version is done in such a way that local imports can still be used in the module code, so IDEs don't have to be aware of what is going on. Example: from ansible.module_utils.basic import * ... will result in the insertion of basic.py into the module from the module_utils/ directory in the source tree. For powershell, this code effectively no-ops, as the exec wrapper requires access to a number of properties not available here. """ task_vars = {} if task_vars is None else task_vars environment = {} if environment is None else environment with open(module_path, 'rb') as f: # read in the module source b_module_data = f.read() module_bits = _find_module_utils( module_name=module_name, b_module_data=b_module_data, module_path=module_path, module_args=module_args, task_vars=task_vars, templar=templar, module_compression=module_compression, async_timeout=async_timeout, become_plugin=become_plugin, environment=environment, remote_is_local=remote_is_local, ) b_module_data = module_bits.b_module_data shebang = module_bits.shebang if module_bits.module_style == 'binary': return _BuiltModule( b_module_data=module_bits.b_module_data, module_style=module_bits.module_style, shebang=to_text(module_bits.shebang, nonstring='passthru'), serialization_profile=module_bits.serialization_profile, ) elif shebang is None: interpreter, args = _extract_interpreter(b_module_data) # No interpreter/shebang, assume a binary module? if interpreter is not None: shebang, new_interpreter = _get_shebang(interpreter, task_vars, templar, args, remote_is_local=remote_is_local) # update shebang b_lines = b_module_data.split(b"\n", 1) if interpreter != new_interpreter: b_lines[0] = to_bytes(shebang, errors='surrogate_or_strict', nonstring='passthru') b_module_data = b"\n".join(b_lines) return _BuiltModule( b_module_data=b_module_data, module_style=module_bits.module_style, shebang=shebang, serialization_profile=module_bits.serialization_profile, ) def _get_action_arg_defaults(action: str, task: Task, templar: TemplateEngine) -> dict[str, t.Any]: action_groups = task._parent._play._action_groups defaults = task.module_defaults # Get the list of groups that contain this action if action_groups is None: msg = ( "Finding module_defaults for action %s. " "The caller has not passed the action_groups, so any " "that may include this action will be ignored." ) display.warning(msg=msg) group_names = [] else: group_names = action_groups.get(action, []) tmp_args: dict[str, t.Any] = {} module_defaults = {} # Merge latest defaults into dict, since they are a list of dicts if isinstance(defaults, list): for default in defaults: module_defaults.update(default) for default in module_defaults: if default.startswith('group/'): group_name = default.split('group/')[-1] if group_name in group_names: tmp_args.update(templar.resolve_to_container(module_defaults.get(f'group/{group_name}', {}))) # handle specific action defaults tmp_args.update(templar.resolve_to_container(module_defaults.get(action, {}))) return tmp_args def _apply_action_arg_defaults(action: str, task: Task, action_args: dict[str, t.Any], templar: Templar) -> dict[str, t.Any]: args = _get_action_arg_defaults(action, task, templar._engine) args.update(action_args) return args ansible_core-2.19.0b5/lib/ansible/executor/play_iterator.py0000644000000000000000000007703215017704211022475 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . from __future__ import annotations import fnmatch from enum import IntEnum, IntFlag from ansible import constants as C from ansible.errors import AnsibleAssertionError from ansible.module_utils.parsing.convert_bool import boolean from ansible.playbook.block import Block from ansible.playbook.task import Task from ansible.utils.display import Display display = Display() __all__ = ['PlayIterator', 'IteratingStates', 'FailedStates'] class IteratingStates(IntEnum): SETUP = 0 TASKS = 1 RESCUE = 2 ALWAYS = 3 HANDLERS = 4 COMPLETE = 5 class FailedStates(IntFlag): NONE = 0 SETUP = 1 TASKS = 2 RESCUE = 4 ALWAYS = 8 HANDLERS = 16 # NOTE not in use anymore class HostState: def __init__(self, blocks): self._blocks = blocks[:] self.handlers = [] self.handler_notifications = [] self.cur_block = 0 self.cur_regular_task = 0 self.cur_rescue_task = 0 self.cur_always_task = 0 self.cur_handlers_task = 0 self.run_state = IteratingStates.SETUP self.fail_state = FailedStates.NONE self.pre_flushing_run_state = None self.update_handlers = True self.pending_setup = False self.tasks_child_state = None self.rescue_child_state = None self.always_child_state = None self.did_rescue = False self.did_start_at_task = False def __repr__(self): return "HostState(%r)" % self._blocks def __str__(self): return ("HOST STATE: block=%d, task=%d, rescue=%d, always=%d, handlers=%d, run_state=%s, fail_state=%s, " "pre_flushing_run_state=%s, update_handlers=%s, pending_setup=%s, " "tasks child state? (%s), rescue child state? (%s), always child state? (%s), " "did rescue? %s, did start at task? %s" % ( self.cur_block, self.cur_regular_task, self.cur_rescue_task, self.cur_always_task, self.cur_handlers_task, self.run_state, self.fail_state, self.pre_flushing_run_state, self.update_handlers, self.pending_setup, self.tasks_child_state, self.rescue_child_state, self.always_child_state, self.did_rescue, self.did_start_at_task, )) def __eq__(self, other): if not isinstance(other, HostState): return False for attr in ('_blocks', 'cur_block', 'cur_regular_task', 'cur_rescue_task', 'cur_always_task', 'cur_handlers_task', 'run_state', 'fail_state', 'pre_flushing_run_state', 'update_handlers', 'pending_setup', 'tasks_child_state', 'rescue_child_state', 'always_child_state'): if getattr(self, attr) != getattr(other, attr): return False return True def get_current_block(self): return self._blocks[self.cur_block] def copy(self): new_state = HostState(self._blocks) new_state.handlers = self.handlers[:] new_state.handler_notifications = self.handler_notifications[:] new_state.cur_block = self.cur_block new_state.cur_regular_task = self.cur_regular_task new_state.cur_rescue_task = self.cur_rescue_task new_state.cur_always_task = self.cur_always_task new_state.cur_handlers_task = self.cur_handlers_task new_state.run_state = self.run_state new_state.fail_state = self.fail_state new_state.pre_flushing_run_state = self.pre_flushing_run_state new_state.update_handlers = self.update_handlers new_state.pending_setup = self.pending_setup new_state.did_rescue = self.did_rescue new_state.did_start_at_task = self.did_start_at_task if self.tasks_child_state is not None: new_state.tasks_child_state = self.tasks_child_state.copy() if self.rescue_child_state is not None: new_state.rescue_child_state = self.rescue_child_state.copy() if self.always_child_state is not None: new_state.always_child_state = self.always_child_state.copy() return new_state class PlayIterator: def __init__(self, inventory, play, play_context, variable_manager, all_vars, start_at_done=False): self._play = play self._blocks = [] self._variable_manager = variable_manager setup_block = Block(play=self._play) # Gathering facts with run_once would copy the facts from one host to # the others. setup_block.run_once = False setup_task = Task(block=setup_block) setup_task.action = 'gather_facts' setup_task.name = 'Gathering Facts' setup_task.args = {} # Unless play is specifically tagged, gathering should 'always' run if not self._play.tags: setup_task.tags = ['always'] # Default options to gather for option in ('gather_subset', 'gather_timeout', 'fact_path'): value = getattr(self._play, option, None) if value is not None: setup_task.args[option] = value setup_task.set_loader(self._play._loader) # short circuit fact gathering if the entire playbook is conditional if self._play._included_conditional is not None: setup_task.when = self._play._included_conditional[:] setup_block.block = [setup_task] setup_block = setup_block.filter_tagged_tasks(all_vars) self._blocks.append(setup_block) # keep flatten (no blocks) list of all tasks from the play # used for the lockstep mechanism in the linear strategy self.all_tasks = setup_block.get_tasks() for block in self._play.compile(): new_block = block.filter_tagged_tasks(all_vars) if new_block.has_tasks(): self._blocks.append(new_block) self.all_tasks.extend(new_block.get_tasks()) # keep list of all handlers, it is copied into each HostState # at the beginning of IteratingStates.HANDLERS # the copy happens at each flush in order to restore the original # list and remove any included handlers that might not be notified # at the particular flush self.handlers = [h for b in self._play.handlers for h in b.block] self._host_states = {} start_at_matched = False batch = inventory.get_hosts(self._play.hosts, order=self._play.order) self.batch_size = len(batch) for host in batch: self.set_state_for_host(host.name, HostState(blocks=self._blocks)) # if we're looking to start at a specific task, iterate through # the tasks for this host until we find the specified task if play_context.start_at_task is not None and not start_at_done: while True: (s, task) = self.get_next_task_for_host(host, peek=True) if s.run_state == IteratingStates.COMPLETE: break if task.name == play_context.start_at_task or (task.name and fnmatch.fnmatch(task.name, play_context.start_at_task)) or \ task.get_name() == play_context.start_at_task or fnmatch.fnmatch(task.get_name(), play_context.start_at_task): start_at_matched = True break self.set_state_for_host(host.name, s) # finally, reset the host's state to IteratingStates.SETUP if start_at_matched: self._host_states[host.name].did_start_at_task = True self._host_states[host.name].run_state = IteratingStates.SETUP if start_at_matched: # we have our match, so clear the start_at_task field on the # play context to flag that we've started at a task (and future # plays won't try to advance) play_context.start_at_task = None self.end_play = False self.cur_task = 0 def get_host_state(self, host): # Since we're using the PlayIterator to carry forward failed hosts, # in the event that a previous host was not in the current inventory # we create a stub state for it now if host.name not in self._host_states: self.set_state_for_host(host.name, HostState(blocks=[])) return self._host_states[host.name].copy() def get_next_task_for_host(self, host, peek=False): display.debug("getting the next task for host %s" % host.name) s = self.get_host_state(host) task = None if s.run_state == IteratingStates.COMPLETE: display.debug("host %s is done iterating, returning" % host.name) return (s, None) (s, task) = self._get_next_task_from_state(s, host=host) if not peek: self.set_state_for_host(host.name, s) display.debug("done getting next task for host %s" % host.name) display.debug(" ^ state is: %s" % s) return (s, task) def _get_next_task_from_state(self, state, host): task = None # try and find the next task, given the current state. while True: # try to get the current block from the list of blocks, and # if we run past the end of the list we know we're done with # this block try: block = state._blocks[state.cur_block] except IndexError: state.run_state = IteratingStates.COMPLETE return (state, None) if state.run_state == IteratingStates.SETUP: # First, we check to see if we were pending setup. If not, this is # the first trip through IteratingStates.SETUP, so we set the pending_setup # flag and try to determine if we do in fact want to gather facts for # the specified host. if not state.pending_setup: state.pending_setup = True # Gather facts if the default is 'smart' and we have not yet # done it for this host; or if 'explicit' and the play sets # gather_facts to True; or if 'implicit' and the play does # NOT explicitly set gather_facts to False. gathering = C.DEFAULT_GATHERING implied = self._play.gather_facts is None or boolean(self._play.gather_facts, strict=False) if (gathering == 'implicit' and implied) or \ (gathering == 'explicit' and boolean(self._play.gather_facts, strict=False)) or \ (gathering == 'smart' and implied and not self._variable_manager._facts_gathered_for_host(host.name)): # The setup block is always self._blocks[0], as we inject it # during the play compilation in __init__ above. setup_block = self._blocks[0] if setup_block.has_tasks() and len(setup_block.block) > 0: task = setup_block.block[0] else: # This is the second trip through IteratingStates.SETUP, so we clear # the flag and move onto the next block in the list while setting # the run state to IteratingStates.TASKS state.pending_setup = False state.run_state = IteratingStates.TASKS if not state.did_start_at_task: state.cur_block += 1 state.cur_regular_task = 0 state.cur_rescue_task = 0 state.cur_always_task = 0 state.tasks_child_state = None state.rescue_child_state = None state.always_child_state = None elif state.run_state == IteratingStates.TASKS: # clear the pending setup flag, since we're past that and it didn't fail if state.pending_setup: state.pending_setup = False # First, we check for a child task state that is not failed, and if we # have one recurse into it for the next task. If we're done with the child # state, we clear it and drop back to getting the next task from the list. if state.tasks_child_state: (state.tasks_child_state, task) = self._get_next_task_from_state(state.tasks_child_state, host=host) if self._check_failed_state(state.tasks_child_state): # failed child state, so clear it and move into the rescue portion state.tasks_child_state = None self._set_failed_state(state) else: # get the next task recursively if task is None or state.tasks_child_state.run_state == IteratingStates.COMPLETE: # we're done with the child state, so clear it and continue # back to the top of the loop to get the next task state.tasks_child_state = None continue else: # First here, we check to see if we've failed anywhere down the chain # of states we have, and if so we move onto the rescue portion. Otherwise, # we check to see if we've moved past the end of the list of tasks. If so, # we move into the always portion of the block, otherwise we get the next # task from the list. if self._check_failed_state(state): state.run_state = IteratingStates.RESCUE elif state.cur_regular_task >= len(block.block): state.run_state = IteratingStates.ALWAYS else: task = block.block[state.cur_regular_task] # if the current task is actually a child block, create a child # state for us to recurse into on the next pass if isinstance(task, Block): state.tasks_child_state = HostState(blocks=[task]) state.tasks_child_state.run_state = IteratingStates.TASKS # since we've created the child state, clear the task # so we can pick up the child state on the next pass task = None state.cur_regular_task += 1 elif state.run_state == IteratingStates.RESCUE: # The process here is identical to IteratingStates.TASKS, except instead # we move into the always portion of the block. if state.rescue_child_state: (state.rescue_child_state, task) = self._get_next_task_from_state(state.rescue_child_state, host=host) if self._check_failed_state(state.rescue_child_state): state.rescue_child_state = None self._set_failed_state(state) else: if task is None or state.rescue_child_state.run_state == IteratingStates.COMPLETE: state.rescue_child_state = None continue else: if state.fail_state & FailedStates.RESCUE == FailedStates.RESCUE: state.run_state = IteratingStates.ALWAYS elif state.cur_rescue_task >= len(block.rescue): if len(block.rescue) > 0: state.fail_state = FailedStates.NONE state.run_state = IteratingStates.ALWAYS state.did_rescue = True else: task = block.rescue[state.cur_rescue_task] if isinstance(task, Block): state.rescue_child_state = HostState(blocks=[task]) state.rescue_child_state.run_state = IteratingStates.TASKS task = None state.cur_rescue_task += 1 elif state.run_state == IteratingStates.ALWAYS: # And again, the process here is identical to IteratingStates.TASKS, except # instead we either move onto the next block in the list, or we set the # run state to IteratingStates.COMPLETE in the event of any errors, or when we # have hit the end of the list of blocks. if state.always_child_state: (state.always_child_state, task) = self._get_next_task_from_state(state.always_child_state, host=host) if self._check_failed_state(state.always_child_state): state.always_child_state = None self._set_failed_state(state) else: if task is None or state.always_child_state.run_state == IteratingStates.COMPLETE: state.always_child_state = None continue else: if state.cur_always_task >= len(block.always): if state.fail_state != FailedStates.NONE: state.run_state = IteratingStates.COMPLETE else: state.cur_block += 1 state.cur_regular_task = 0 state.cur_rescue_task = 0 state.cur_always_task = 0 state.run_state = IteratingStates.TASKS state.tasks_child_state = None state.rescue_child_state = None state.always_child_state = None state.did_rescue = False else: task = block.always[state.cur_always_task] if isinstance(task, Block): state.always_child_state = HostState(blocks=[task]) state.always_child_state.run_state = IteratingStates.TASKS task = None state.cur_always_task += 1 elif state.run_state == IteratingStates.HANDLERS: if state.update_handlers: # reset handlers for HostState since handlers from include_tasks # might be there from previous flush state.handlers = self.handlers[:] state.update_handlers = False while True: try: task = state.handlers[state.cur_handlers_task] except IndexError: task = None state.cur_handlers_task = 0 state.run_state = state.pre_flushing_run_state state.update_handlers = True break else: state.cur_handlers_task += 1 if task.is_host_notified(host): return state, task elif state.run_state == IteratingStates.COMPLETE: return (state, None) # if something above set the task, break out of the loop now if task: # skip implicit flush_handlers if there are no handlers notified if ( task.implicit and task._get_meta() == 'flush_handlers' and ( # the state store in the `state` variable could be a nested state, # notifications are always stored in the top level state, get it here not self.get_state_for_host(host.name).handler_notifications # in case handlers notifying other handlers, the notifications are not # saved in `handler_notifications` and handlers are notified directly # to prevent duplicate handler runs, so check whether any handler # is notified and all(not h.notified_hosts for h in self.handlers) ) ): display.debug("No handler notifications for %s, skipping." % host.name) elif ( (role := task._role) and role._metadata.allow_duplicates is False and host.name in self._play._get_cached_role(role)._completed ): display.debug("'%s' skipped because role has already run" % task) else: break return (state, task) def _set_failed_state(self, state): if state.run_state == IteratingStates.SETUP: state.fail_state |= FailedStates.SETUP state.run_state = IteratingStates.COMPLETE elif state.run_state == IteratingStates.TASKS: if state.tasks_child_state is not None: state.tasks_child_state = self._set_failed_state(state.tasks_child_state) else: state.fail_state |= FailedStates.TASKS if state._blocks[state.cur_block].rescue: state.run_state = IteratingStates.RESCUE elif state._blocks[state.cur_block].always: state.run_state = IteratingStates.ALWAYS else: state.run_state = IteratingStates.COMPLETE elif state.run_state == IteratingStates.RESCUE: if state.rescue_child_state is not None: state.rescue_child_state = self._set_failed_state(state.rescue_child_state) else: state.fail_state |= FailedStates.RESCUE if state._blocks[state.cur_block].always: state.run_state = IteratingStates.ALWAYS else: state.run_state = IteratingStates.COMPLETE elif state.run_state == IteratingStates.ALWAYS: if state.always_child_state is not None: state.always_child_state = self._set_failed_state(state.always_child_state) else: state.fail_state |= FailedStates.ALWAYS state.run_state = IteratingStates.COMPLETE return state def mark_host_failed(self, host): s = self.get_host_state(host) display.debug("marking host %s failed, current state: %s" % (host, s)) if s.run_state == IteratingStates.HANDLERS: # we are failing `meta: flush_handlers`, so just reset the state to whatever # it was before and let `_set_failed_state` figure out the next state s.run_state = s.pre_flushing_run_state s.update_handlers = True s = self._set_failed_state(s) display.debug("^ failed state is now: %s" % s) self.set_state_for_host(host.name, s) self._play._removed_hosts.append(host.name) def get_failed_hosts(self): return dict((host, True) for (host, state) in self._host_states.items() if self._check_failed_state(state)) def _check_failed_state(self, state): if state is None: return False elif state.run_state == IteratingStates.RESCUE and self._check_failed_state(state.rescue_child_state): return True elif state.run_state == IteratingStates.ALWAYS and self._check_failed_state(state.always_child_state): return True elif state.fail_state != FailedStates.NONE: if state.run_state == IteratingStates.RESCUE and state.fail_state & FailedStates.RESCUE == 0: return False elif state.run_state == IteratingStates.ALWAYS and state.fail_state & FailedStates.ALWAYS == 0: return False else: return not (state.did_rescue and state.fail_state & FailedStates.ALWAYS == 0) elif state.run_state == IteratingStates.TASKS and self._check_failed_state(state.tasks_child_state): cur_block = state._blocks[state.cur_block] if len(cur_block.rescue) > 0 and state.fail_state & FailedStates.RESCUE == 0: return False else: return True return False def is_failed(self, host): s = self.get_host_state(host) return self._check_failed_state(s) def clear_host_errors(self, host): self._clear_state_errors(self.get_state_for_host(host.name)) def _clear_state_errors(self, state: HostState) -> None: state.fail_state = FailedStates.NONE if state.tasks_child_state is not None: self._clear_state_errors(state.tasks_child_state) elif state.rescue_child_state is not None: self._clear_state_errors(state.rescue_child_state) elif state.always_child_state is not None: self._clear_state_errors(state.always_child_state) def get_active_state(self, state): """ Finds the active state, recursively if necessary when there are child states. """ if state.run_state == IteratingStates.TASKS and state.tasks_child_state is not None: return self.get_active_state(state.tasks_child_state) elif state.run_state == IteratingStates.RESCUE and state.rescue_child_state is not None: return self.get_active_state(state.rescue_child_state) elif state.run_state == IteratingStates.ALWAYS and state.always_child_state is not None: return self.get_active_state(state.always_child_state) return state def is_any_block_rescuing(self, state): """ Given the current HostState state, determines if the current block, or any child blocks, are in rescue mode. """ if state.run_state == IteratingStates.TASKS and state.get_current_block().rescue: return True if state.tasks_child_state is not None: return self.is_any_block_rescuing(state.tasks_child_state) if state.rescue_child_state is not None: return self.is_any_block_rescuing(state.rescue_child_state) if state.always_child_state is not None: return self.is_any_block_rescuing(state.always_child_state) return False def _insert_tasks_into_state(self, state, task_list): # if we've failed at all, or if the task list is empty, just return the current state if (state.fail_state != FailedStates.NONE and state.run_state == IteratingStates.TASKS) or not task_list: return state if state.run_state == IteratingStates.TASKS: if state.tasks_child_state: state.tasks_child_state = self._insert_tasks_into_state(state.tasks_child_state, task_list) else: target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) target_block.block[state.cur_regular_task:state.cur_regular_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.RESCUE: if state.rescue_child_state: state.rescue_child_state = self._insert_tasks_into_state(state.rescue_child_state, task_list) else: target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) target_block.rescue[state.cur_rescue_task:state.cur_rescue_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.ALWAYS: if state.always_child_state: state.always_child_state = self._insert_tasks_into_state(state.always_child_state, task_list) else: target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) target_block.always[state.cur_always_task:state.cur_always_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.HANDLERS: state.handlers[state.cur_handlers_task:state.cur_handlers_task] = [h for b in task_list for h in b.block] return state def add_tasks(self, host, task_list): self.set_state_for_host(host.name, self._insert_tasks_into_state(self.get_host_state(host), task_list)) @property def host_states(self): return self._host_states def get_state_for_host(self, hostname: str) -> HostState: return self._host_states[hostname] def set_state_for_host(self, hostname: str, state: HostState) -> None: if not isinstance(state, HostState): raise AnsibleAssertionError('Expected state to be a HostState but was a %s' % type(state)) self._host_states[hostname] = state def set_run_state_for_host(self, hostname: str, run_state: IteratingStates) -> None: if not isinstance(run_state, IteratingStates): raise AnsibleAssertionError('Expected run_state to be a IteratingStates but was %s' % (type(run_state))) self._host_states[hostname].run_state = run_state def set_fail_state_for_host(self, hostname: str, fail_state: FailedStates) -> None: if not isinstance(fail_state, FailedStates): raise AnsibleAssertionError('Expected fail_state to be a FailedStates but was %s' % (type(fail_state))) self._host_states[hostname].fail_state = fail_state def add_notification(self, hostname: str, notification: str) -> None: # preserve order host_state = self._host_states[hostname] if notification not in host_state.handler_notifications: host_state.handler_notifications.append(notification) def clear_notification(self, hostname: str, notification: str) -> None: self._host_states[hostname].handler_notifications.remove(notification) def end_host(self, hostname: str) -> None: """Used by ``end_host``, ``end_batch`` and ``end_play`` meta tasks to end executing given host.""" state = self.get_active_state(self.get_state_for_host(hostname)) if state.run_state == IteratingStates.RESCUE: # This is a special case for when ending a host occurs in rescue. # By definition the meta task responsible for ending the host # is the last task, so we need to clear the fail state to mark # the host as rescued. # The reason we need to do that is because this operation is # normally done when PlayIterator transitions from rescue to # always when only then we can say that rescue didn't fail # but with ending a host via meta task, we don't get to that transition. self.set_fail_state_for_host(hostname, FailedStates.NONE) self.set_run_state_for_host(hostname, IteratingStates.COMPLETE) self._play._removed_hosts.append(hostname) ansible_core-2.19.0b5/lib/ansible/executor/playbook_executor.py0000644000000000000000000003472615017704211023360 0ustar00rootroot# (c) 2012-2014, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . from __future__ import annotations import os from ansible import constants as C from ansible import context from ansible.executor.task_queue_manager import TaskQueueManager, AnsibleEndPlay from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.parsing.convert_bool import boolean from ansible.plugins.loader import become_loader, connection_loader, shell_loader from ansible.playbook import Playbook from ansible._internal._templating._engine import TemplateEngine from ansible.utils.helpers import pct_to_int from ansible.utils.collection_loader import AnsibleCollectionConfig from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path, _get_collection_playbook_path from ansible.utils.path import makedirs_safe from ansible.utils.ssh_functions import set_default_transport from ansible.utils.display import Display display = Display() class PlaybookExecutor: """ This is the primary class for executing playbooks, and thus the basis for bin/ansible-playbook operation. """ def __init__(self, playbooks, inventory, variable_manager, loader, passwords): self._playbooks = playbooks self._inventory = inventory self._variable_manager = variable_manager self._loader = loader self.passwords = passwords self._unreachable_hosts = dict() if context.CLIARGS.get('listhosts') or context.CLIARGS.get('listtasks') or \ context.CLIARGS.get('listtags') or context.CLIARGS.get('syntax'): self._tqm = None else: self._tqm = TaskQueueManager( inventory=inventory, variable_manager=variable_manager, loader=loader, passwords=self.passwords, forks=context.CLIARGS.get('forks'), ) # Note: We run this here to cache whether the default ansible ssh # executable supports control persist. Sometime in the future we may # need to enhance this to check that ansible_ssh_executable specified # in inventory is also cached. We can't do this caching at the point # where it is used (in task_executor) because that is post-fork and # therefore would be discarded after every task. set_default_transport() def run(self): """ Run the given playbook, based on the settings in the play which may limit the runs to serialized groups, etc. """ result = 0 entrylist = [] entry = {} try: # preload become/connection/shell to set config defs cached list(connection_loader.all(class_only=True)) list(shell_loader.all(class_only=True)) list(become_loader.all(class_only=True)) for playbook in self._playbooks: # deal with FQCN resource = _get_collection_playbook_path(playbook) if resource is not None: playbook_path = resource[1] playbook_collection = resource[2] else: playbook_path = playbook # not fqcn, but might still be collection playbook playbook_collection = _get_collection_name_from_path(playbook) if playbook_collection: display.v("running playbook inside collection {0}".format(playbook_collection)) AnsibleCollectionConfig.default_collection = playbook_collection else: AnsibleCollectionConfig.default_collection = None pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader) # FIXME: move out of inventory self._inventory.set_playbook_basedir(os.path.realpath(os.path.dirname(playbook_path))) if self._tqm is None: # we are doing a listing entry = {'playbook': playbook_path} entry['plays'] = [] else: # make sure the tqm has callbacks loaded self._tqm.load_callbacks() self._tqm.send_callback('v2_playbook_on_start', pb) i = 1 plays = pb.get_plays() display.vv(u'%d plays in %s' % (len(plays), to_text(playbook_path))) for play in plays: if play._included_path is not None: self._loader.set_basedir(play._included_path) else: self._loader.set_basedir(pb._basedir) # clear any filters which may have been applied to the inventory self._inventory.remove_restriction() # Allow variables to be used in vars_prompt fields. all_vars = self._variable_manager.get_vars(play=play) templar = TemplateEngine(loader=self._loader, variables=all_vars) setattr(play, 'vars_prompt', templar.template(play.vars_prompt)) # FIXME: this should be a play 'sub object' like loop_control if play.vars_prompt: for var in play.vars_prompt: vname = var['name'] prompt = var.get("prompt", vname) default = var.get("default", None) private = boolean(var.get("private", True)) confirm = boolean(var.get("confirm", False)) encrypt = var.get("encrypt", None) salt_size = var.get("salt_size", None) salt = var.get("salt", None) unsafe = boolean(var.get("unsafe", False)) if vname not in self._variable_manager.extra_vars: if self._tqm: self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe) play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default, unsafe) else: # we are either in --list-