diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 20:03:01 +0000 |
commit | a453ac31f3428614cceb99027f8efbdb9258a40b (patch) | |
tree | f61f87408f32a8511cbd91799f9cececb53e0374 /collections-debian-merged/ansible_collections/ngine_io | |
parent | Initial commit. (diff) | |
download | ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.tar.xz ansible-a453ac31f3428614cceb99027f8efbdb9258a40b.zip |
Adding upstream version 2.10.7+merged+base+2.10.8+dfsg.upstream/2.10.7+merged+base+2.10.8+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collections-debian-merged/ansible_collections/ngine_io')
411 files changed, 54748 insertions, 0 deletions
diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml new file mode 100644 index 00000000..1ddc5e29 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/integration.yml @@ -0,0 +1,80 @@ +name: Collection integration + +on: + push: + branches: + - master + pull_request: + schedule: + - cron: 30 6 * * * + +jobs: + integration-test: + name: Integration v${{ matrix.container-version }} Ansible-${{ matrix.ansible-branch }} group${{ matrix.group }} Py${{ matrix.python-version }} + defaults: + run: + working-directory: ansible_collections/ngine_io/cloudstack + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - 3.6 + - 2.7 + group: + - 1 + - 2 + ansible-branch: + - devel + container-version: + - 1.4.0 + - 1.2.0 + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/cloudstack + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install ansible and collection dependencies + run: | + python -m pip install --upgrade pip + pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible-branch }}.tar.gz + pip install -r requirements.txt + + - name: Build and install collection + run: | + ansible-galaxy collection build . + ansible-galaxy collection install *.gz + + - name: Run the tests + run: >- + ansible-test + integration + --docker + -v + --diff + --color + --retry-on-error + --python ${{ matrix.python-version }} + --continue-on-error + --coverage + shippable/cs/group${{ matrix.group }}/ + env: + ANSIBLE_CLOUDSTACK_CONTAINER: quay.io/ansible/cloudstack-test-container:${{ matrix.container-version }} + + - name: Generate coverage report. + run: >- + ansible-test + coverage xml + -v + --requirements + --group-by command + --group-by version + - uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: false diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml new file mode 100644 index 00000000..7d7df0f7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Upload release to Galaxy + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ansible_collections/ngine_io/cloudstack + steps: + - uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/cloudstack + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ansible + - name: Build and publish + env: + ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} + run: | + ansible-galaxy collection build . + ansible-galaxy collection publish *.tar.gz --api-key $ANSIBLE_GALAXY_API_KEY diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml new file mode 100644 index 00000000..3329a194 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/.github/workflows/sanity.yml @@ -0,0 +1,35 @@ +name: Sanity +on: + schedule: + - cron: "* 12 * * *" + pull_request: + +jobs: + sanity: + name: Sanity (${{ matrix.ansible }}) + defaults: + run: + working-directory: ansible_collections/ngine_io/cloudstack + strategy: + matrix: + ansible: + - stable-2.10 + - stable-2.9 + - devel + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/cloudstack + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + - name: Run sanity tests + run: ansible-test sanity --docker -v --color diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst new file mode 100644 index 00000000..fd6f1c08 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CHANGELOG.rst @@ -0,0 +1,49 @@ +========================================== +Apache CloudStack Collection Release Notes +========================================== + +.. contents:: Topics + + +v1.2.0 +====== + +Minor Changes +------------- + +- cs_instance - Fixed an edge case caused by `displaytext` not available (https://github.com/ngine-io/ansible-collection-cloudstack/pull/49). +- cs_network - Fixed constraints when creating networks. The param `gateway` is no longer required if the param `netmask` is given (https://github.com/ngine-io/ansible-collection-cloudstack/pull/54). + +v1.1.0 +====== + +Minor Changes +------------- + +- Deprecated the funtionality of first returned zone to be the default zone because of an unreliable API. Zone will be required beginning with next major version 2.0.0. +- cs_ip_address - allow to pick a particular IP address for a network, available since CloudStack v4.13 (https://github.com/ngine-io/ansible-collection-cloudstack/issues/30). + +v1.0.1 +====== + +Minor Changes +------------- + +- cs_configuration - Workaround for empty global settings idempotency (https://github.com/ngine-io/ansible-collection-cloudstack/pull/25). + +v1.0.0 +====== + +Minor Changes +------------- + +- cs_vlan_ip_range - Added support to set IP range for system VMs (https://github.com/ngine-io/ansible-collection-cloudstack/pull/18) +- cs_vlan_ip_range - Added support to specify pod name (https://github.com/ngine-io/ansible-collection-cloudstack/pull/20) + +v0.3.0 +====== + +Minor Changes +------------- + +- Added support for SSL CA cert verification (https://github.com/ngine-io/ansible-collection-cloudstack/pull/3) diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md new file mode 100644 index 00000000..44683c13 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# Contributing + +Any contribution is welcome and we only ask contributors to: + +- Create an issues for any significant contribution that would change a large portion of the code base. +- Provide at least integration tests for any contribution diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING new file mode 100644 index 00000000..94a04532 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/COPYING @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + 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 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json new file mode 100644 index 00000000..53e7f294 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/FILES.json @@ -0,0 +1,3155 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/integration.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "901ae9494070cfaf2888a55873e289c5c491af91044a86cc99e647b92f1d8b11", + "format": 1 + }, + { + "name": ".github/workflows/sanity.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1b573d0df42509a12dc498f0275e0d799b6876b25b7ff72702b6ea70d449abfd", + "format": 1 + }, + { + "name": ".github/workflows/publish.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4e3a3b338deb27ec8dbfce3a48ddfe9585063e1ebfd80135fd04180cb9e47fe3", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d61725d614410e2ee0a900fb0f6b6d742ad8fb689ae27c4d6a3a7f89e82fc791", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a20a58050d96de9b31b7c34d59344a0e66ca78ccdf4a3362edaf7aeb587f7808", + "format": 1 + }, + { + "name": "codecov.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "afc8758de58128c25c317b7e0577948745e05ad8f5d9e2e6b398fe351f237c4d", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "578cefb3377270135166cd40a2464cb2726f1cb331c830110ee05b200667560f", + "format": 1 + }, + { + "name": "scripts", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "scripts/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "scripts/inventory/cloudstack.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "478052455665ad0f9af2a25636d2635d800893fdcf44234a4c9bd7ae02eab3a8", + "format": 1 + }, + { + "name": "scripts/inventory/cloudstack.ini", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "68687bdf204b24ce911c14663b8e69acb388c328779449bda69cc0828e548e16", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/unit/modules/test_cs_traffic_type.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d2b4ed18f086f4f0a8579f32e3b3decabfbbe586d3a1af78ee5462314d46d2f7", + "format": 1 + }, + { + "name": "tests/sanity", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.9.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/sanity/requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c8a4ac4bfdef88e75d6e748e35a42fb4915947dfa2b7dd788626fd829600e014", + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.10.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/integration", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2f76af19234a916542ea1bc51dcfc63f2ee5fba78562ae4fbc052be036812035", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vlan_ip_range/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "78ffd37aa31959ad88ab02c30493979cb82904da3fd584ae36a851b9f7aae534", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3cd6a215c3f8e43d39b6a2e04e3ff76f0bcbf3edfeafdd1554615b6a9b4f8ff1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0b725eee393b6b5fa1a51131498bdb40f94841a4430d9c38894146f8e764b679", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c3438cb3148e9d0988a7ea4375dfd89d2c2dab0d67257177f11c2ecff61698d9", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_disk_offering/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2e70d8fb8c7855c7247a697738e6a0971a87ee6d51cbe2ea3f9c05c6d777a698", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_domain/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e2c8bb27e2b569449117fac8b22f1c46ab3bc46309b0b9a1dd1502c450f5b058", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instancegroup/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "88ac6be7215520f724b5a5c379c8a60d18da7a804dfcfbd7ebdfc6d29f54be4b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_loadbalancer_rule/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "344c52179d018ce4e7156048768afc9d7b8a96447b937e1cbe57e8903a78b839", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6c59ba59148b0d1320caa47f882209934ee727522070decdff4442b9969f9922", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_portforward/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "02998a58ac5e2d50a05ea38a9fe9147dabc50c66e6a704d313abd815f0c7a5ab", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2502c1a6bee1dfd83edf7607b8990cd96e252cb9fc09924e0b3ef63d68d065ff", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc_offering/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f161ed7ac158aed2aae7466b5b4a76cfe9022e36c015eb1fef38cea4b980b627", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/tasks/instance.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1d89acf95bdbab94aed21af8979b6e6a279b6230be7defd96d20c1fdab51eea5", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/tasks/cpu.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9eaa824708a27315ec1ba5c3b8ad94916857bb744743d66a4424bb95b4b66851", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_resourcelimit/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3b07f0a3e941192fa759956eefa6c37b91f386effa4cb9494dcb698d5db5184a", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_account/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9035d7e10eabaa16be3d35db67a0fe267f1db7eca09ed29f669913c4c7789fda", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/tasks/vpc.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "155dba88a0af93a0060b710c523a9810bf75d8f2dc861e25d4f1dab858c1c86e", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/tasks/network.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "15d3f1a3307082ddedfb26d2512e1f8685d13cfa9656f018fca2bf0a04ca1510", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_ip_address/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d3bc0dde667bd969a99c8bd162ca2f45f309b8e0cc88862f3e7719f57522324", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "33c9d5e8514301ea8a08b25615c62068f5b431c2eb74eebed63f98c49abf6b4c", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "033109b067b97d720aae0d7c05b52cb75d5cbd489e0a0071e259117ebe8f8917", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks/present.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "11c980afde092def9b1786574f57aafe6c8575edd4b6f3043439c24e7c1ff840", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6d66e31908ee8d1f26a41413faa748bede36b4978de7463627d259efeb631722", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup_rule/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5761da50b470ecdac2717f281f58cf92772cc72f5ddc37cfa70c2b3cea4af0cb", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dad8be1dcf1a0aff3f6b298b7eff915c0686516288012389d6c2a0a0f8a51c7b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_storage_pool/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3cd6a215c3f8e43d39b6a2e04e3ff76f0bcbf3edfeafdd1554615b6a9b4f8ff1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d16390e4bc6fa20a760046083a7618be45b6837d9089f0f578aa07c5b0520de2", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vmsnapshot/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c535689653a4fa17f81e799bfd08233c8e6c922aa39a0b6f11d059f36e3669f6", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_pod/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f34435f3e10a5b795d59cb93cbe5be3f076e392ae95aa71633da6a197f161dc2", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "901a810242c3925f1b4bddda46b2d88f67e519f4b6083bcf8fb2558606183051", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/tasks/extract_upload.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "080aa10d4de85b9b1362bddaff92f98541c8938eaf029025badd07be5810b65b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/tasks/common.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "efe358347a46c9fa323eafb0cb3d13dc00acf12ac91f27801fd72e13f0d749f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_volume/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "81c00882d5027750debd495ca52af872f0598e5b1ab8149fad9cf917fdb43a99", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4e431dd4b7e38c2015973f2c38df88fafdb8fabc0d6cd324896d6e5d55c6a7bd", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks/storage.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fdba85274478328bc23c3c27b2281758e7917dd6f20cb4dc4f299c2489452fd7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks/cluster.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b7391db25eb343fc12282964e43a5901ff4f412cdf155636dc76074255efb92c", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks/zone.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7fde8940bfecb63f5f6a066462df151d00f04653fa505fdae6b92cb27af818f4", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/tasks/account.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f6c463b2e203267b31c12d4434dc4fdb630ecaf1bb2d486e6d826eff1e49b7a1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_configuration/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "68a32931f33f79650f95a87b32b3433e4381338d5b1ca31f2ebc9b731bea933b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5ba905c63b22589086a7c6a30846142a6b952fe16594c91aaf5a8714d089847b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_host/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1df97d660547f55323b190118a233cc0e4aae5a634e9c691e8fee64dba46b933", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "93d9e466eda38393a5c61922128f6a08d660ae6ac7247f404db75337d966333d", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_zone_info/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e59e06cbfaa08da5d22a5e8ceb6438830027bde749902aaa6610644556cc1ae1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "82fefd0a537a0944caa4c0cc27fa910f0f4be3af7721b3e153fe221dc861abd1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_securitygroup/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f60ff37c5d6bc0eb7a1775deb3d95769d50acb19147d0224026bfa3663f47940", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_gateway/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "37e3d450b66d55ebe6bd62e95227e7f577b574cd49c462d339d0fc40c436aa57", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_image_store/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d089bedcbdca8f8f9958db1f15641382f596cfc57fcab6953699d97c2f83988e", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_snapshot_policy/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b300f611e7e7135993a4723c687b1cafd7645ebe364a1b5e8346f2e56022a19d", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_iso/vars/main", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ceaa440c1cbe8e00a79d7e38d80a8a5cbcac80433ef5635757beeed08ffdf7f5", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "436edb2efdcc5a081992d0373ef892a8f8365845bda44ca74858dc5b17a3168a", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance_password_reset/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "69c3dde280feba63615cc92b06915f92e3d97eead5249c92736815719427e3b0", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpn_connection/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e9f171e3921423692918610c59f13b2e3f54c2257333b5c5b3372f4b31341477", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c04acf19293639e0d95ee7a7b96e21b98b2012d008f2b21c81a3acabf7da71ef", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/tasks/test2.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5a46fd33b402c788ae3d984e3e8fa472f960769d4e899f74d082d4d16d18c539", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/tasks/test1.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b49ca50601acc42f14c9344acacd5078b28dff511b9afac5a6fa8ff05e4a4cd2", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_template/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4bdf9f930a44fc7b940bec01380b8c0f4a6a8094aee598778af2dd4f45672bef", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_physical_network/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "555e1db2372cf69d3a8f52f92be3bfae504bb9d17733c3de1af27819555d3c6c", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_traffic_type/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b221ca593f1d6cc4423409c2907520009ce5a0b9d76b959e30aaae1e953995b1", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_cluster/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "835daf7a42f92968a97750b8b57def374a4d095a1ea4bfbf248dfb1852930138", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl_rule/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2e814b9b39cde2e07fcf66c75ea960cec7285f8ba6f3eacda68e504ba4d9f0e7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_region/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b333f132afa4d635d3d65906788d29230338a0421004bd632bda0ab5b824a671", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e88e45b01f0fd3179502e864d02eb9565a5c8af81ca64be8ace5c9f6a91463c8", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/sshkeys.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "27b7d8a289e9a8eae40c0cb7a910df2216db3ff331f4c1ef846b63f5a24d7a8a", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/project.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "be774b436b890ef832c7828bff578bd11d71ca38dc20bb837b3ca27c3e568eb0", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/absent_display_name.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9fa46c79ea412b09525494b95e37ae0f69af77554f669faeb708d1c4325f486e", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/host.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2369176246b141fbe33eeb3d2a5831434d90d585588cb59640c5e76a8bc35052", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/absent.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "584ef507f41cd26f390a1577a4a4ec8222af585a8bc208cedcd8a67201da8b9c", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/cleanup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "45b55ab87c0e6f0618a2b787749a16eea5505feaf7c63ddf36b677347fae40f8", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/present.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "36d3f3f5716c6bcf992d9dc5ca89e73ad39d4d0caf0cc5066d374eeb56ea9c51", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/present_display_name.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8e750ce18fc78fc6a80816e8e8f8f782bbcfce5b063b850f8d0a3ba7f1df9814", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/setup.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c101e2db52029f736527268279eef4989371bb17b37ee1ed22249d8cba50b7e6", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/tasks/tags.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "55f84d21aec9825c83de1c89184d2d5e24ee09230d754ca7bffc9b07b668dff5", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_instance/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "616327d556e1811bf053b650fd4d39f86c5725601251926a6adf9e97dd0ca2ac", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6d24a28d3e2f90db822b1a43239bdcae7366c592c0494fb53d66efc24f210dab", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_common/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e084a3683ef795d1cdbf5e9b253f2ca1f783ae0d0d6e47e419acbbc4fc80bbfa", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d13fd3db2ddc6b26b21a32ee63bfc8b837ab918a2b3f134b451156fcd09a7844", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_vpc/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bce5685bb3f56dcfb18126f2dab2bcb20b0227ec5af2626a0ea99592d3837908", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d2924b0f2adf14b7dfd6c808cca36a5e11491e1c81954f8bd4814acc8de71224", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_firewall/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "723bfa451f6b5fa598677b451b81a93eca4dd7ec004e7bc5b1bff865389280f6", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_user/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7e5a4ec5322983b45afa12ae5e7ce6fe9cf98684d1ed3556e8947d84e3be61b0", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_sshkeypair/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9cd1515f2e8a1e3e66f2d95d9112d7f9deddf7a6800d791dfd5b54264bb6f217", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_acl/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "018b8d542e2352e52319c4fc33991f80899e82cea1b0bc6f34428fd73c553ded", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network_offering/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "440a776e871e1e719a5f6aaa2c0fcdd32a68991ad416c3c09e3a8beb7f207466", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/tasks/vpc_network_tier.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7a62edd637b4c99aa83306cbba8e355ae565ec5e9bbceb6849493b6c3289d8ad", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_network/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5f680e43c73283119136e0210f40d3b7224393a0c27dee9feb34e095f9055b33", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_role_permission/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3826fd7a8983ae5350ba356789a8d6d3c196081326b1d47f7325d6e07b1fdb2c", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_project/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fee4f4a1d95c32a864529c3aa66e4a5842566759600498962c616d774c780560", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "31e3c9afe6035e7e19861c1456984b055cbde8ae27dd61fe1651b8b1d7f821f7", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_affinitygroup/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "162ccba75799e1764a780a3efabbd083b8999b04c6fb010b73cee5ff4c6b2400", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "08e092f11a312f6509e172b83079f86ae4f623fb140c212129cd4bc168156f00", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5e3355d332a1366ac284c390396b41df25b5d05824d1f0ff3ff5d7b1cae96e1b", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_service_offering/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7a04fd3a4077d4b7aa61897011b17349358e0a4e18cccb1df4e8c6ebcc3ac5", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecee22da10186fa1783c73525d77fd4344b7c0232764d03fa104642776ee722f", + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/cs_router/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed7caf41ac4d9aa3e19694a1561c3211589a9e672ae762f9418aca890a29e536", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments/cloudstack.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1dc4d5b06785e750f58dea4908c7eadb72b2b8afb1e3a6c8827c030a62dc09e0", + "format": 1 + }, + { + "name": "plugins/doc_fragments/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/inventory/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/cloudstack.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f8550690f9781333d7d2dd0004d1ef2c7371c20bb740f271f73271cca7c32bc0", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/cs_user.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f88272e1c57a99e1dfc3c7d15387be9ba1cee7dcb8c006a3a139a00c51d2f9cd", + "format": 1 + }, + { + "name": "plugins/modules/cs_vmsnapshot.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b05403414eda51030bf22bb684b092e38f66362412a9c0bbbc98e804744acb3a", + "format": 1 + }, + { + "name": "plugins/modules/cs_instance_nic.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bb6635c5bc7043e24cd4934c5b166d939ce6a7e52d81ac308fea4547dc159765", + "format": 1 + }, + { + "name": "plugins/modules/cs_router.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "77e68182ff9763e80f186730eb7e4317732a5f18feda5f55f551427bf2b674e4", + "format": 1 + }, + { + "name": "plugins/modules/cs_facts.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "90babadf599efc7386d2330e11c2dc0dc5942024314865beada155b706235f1f", + "format": 1 + }, + { + "name": "plugins/modules/cs_storage_pool.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "858db5a5c6bc8dd0068173287ed2f9f20b44458f26a29eceb19c88312335038f", + "format": 1 + }, + { + "name": "plugins/modules/cs_pod.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8208a91b94512910ccbbab450d56b0fcf27c031b65566fdbebaa1a42fcdf1a14", + "format": 1 + }, + { + "name": "plugins/modules/cs_configuration.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f36ad5c05a8d90658fa764b26bf8d1f48f914636e04a0b43439ad383300b16fd", + "format": 1 + }, + { + "name": "plugins/modules/cs_vpn_gateway.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4fea1f6802bcd3e072f25019d145392065dd8448077f89bf57727853a874b6df", + "format": 1 + }, + { + "name": "plugins/modules/cs_vpn_connection.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "86cdc94e4c32a7f1e92a8699f8f7a30d0d6c08d71b5d9bd79753fc15fd03d8b1", + "format": 1 + }, + { + "name": "plugins/modules/cs_vpn_customer_gateway.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "19a4b82df0d58b2d74e270e484ed700687cd6c017df41d2db20ceaa7f33d02e0", + "format": 1 + }, + { + "name": "plugins/modules/cs_cluster.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bdadc9c314b4360254c6d1fbc2d99c2c49bbb279b8688b7ea1e7ecc0ae376b8b", + "format": 1 + }, + { + "name": "plugins/modules/cs_traffic_type.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "26fa654a85cd1084c25b9342828f1e9465379853b2e2bd9a5f9b73a93f4baa7a", + "format": 1 + }, + { + "name": "plugins/modules/cs_physical_network.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3cb9342b03424b394310b4bc6ce959bcde8abe5a1297daab0b2cf2594e282e50", + "format": 1 + }, + { + "name": "plugins/modules/cs_domain.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e1792de992e67d1d35332be1c1a266bfb4844ad734e9306038fafb7f29e856a7", + "format": 1 + }, + { + "name": "plugins/modules/cs_loadbalancer_rule_member.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b86ad01dd0f0c28e94566d11e0bb5f30602db95c114269cec4f32582ba11b46e", + "format": 1 + }, + { + "name": "plugins/modules/cs_instance_nic_secondaryip.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "416e26b7a322f3639e46aa3baebf916437d5ab7a5267b16926d04f4902e27b5f", + "format": 1 + }, + { + "name": "plugins/modules/cs_snapshot_policy.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5464689f73fb50206aa91c04df89f50ae649fb86a1d577b59b53f32636899908", + "format": 1 + }, + { + "name": "plugins/modules/cs_instance.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "39a33cd4487edd75005aec6e5c00657d48ba3e1e683f0efa0b3e23d1fdb04ac9", + "format": 1 + }, + { + "name": "plugins/modules/cs_volume.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "41981cfd82c9afd850bb76fa6b178fa21bb58061d0e6a8db39c5c94362cdbd92", + "format": 1 + }, + { + "name": "plugins/modules/cs_instance_password_reset.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "00b1bb39cb5134ca8beadc8dd3d651a1b7987b4f52d410bf6c720e643748fa07", + "format": 1 + }, + { + "name": "plugins/modules/cs_loadbalancer_rule.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d255a1a2646f86197322c62d4aeb4b5a5f87f47815501f66f5220d793461e647", + "format": 1 + }, + { + "name": "plugins/modules/cs_disk_offering.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e67dfad492025f3b1b94faf32dd02fc7a15ddfafbda8af1d23409b0e227a4f7d", + "format": 1 + }, + { + "name": "plugins/modules/cs_firewall.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "600e65641433ad461384bda7a92c941c75f9e202df17a847f7a208dc7d6751b4", + "format": 1 + }, + { + "name": "plugins/modules/cs_securitygroup_rule.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a8ad4f4fa55a24b3df7990d06cc90dd5aa7a01dcec3e06f8b81c6ed4f36b33da", + "format": 1 + }, + { + "name": "plugins/modules/cs_instance_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "987b16953b28e483046a59ff1b79a1b0f07b31eab05713757ee2b3e931835f46", + "format": 1 + }, + { + "name": "plugins/modules/cs_account.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "50f82f57ec698a243f290ee9e0c61db7aa04bc5dd9057e8b3651b477d019a33b", + "format": 1 + }, + { + "name": "plugins/modules/cs_instancegroup.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "33828978e373f0a3fc9e212bdde35e990e02b46c6db9b0d74c2db9d29218f3ba", + "format": 1 + }, + { + "name": "plugins/modules/cs_securitygroup.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8cfb4d57198cdf397e86331b0a30fec8cffd85d04ab1d66c46310fd7e15596c6", + "format": 1 + }, + { + "name": "plugins/modules/cs_network.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7e682efa26cabca448fe874b79ae4fed44a896e8ac91f71e6951fccd5d858faf", + "format": 1 + }, + { + "name": "plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/modules/cs_project.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "083ac8aa569b719589c462eb79cceb8b02cccdf7665c2b1e60097195e3ae3466", + "format": 1 + }, + { + "name": "plugins/modules/cs_zone.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4504a896257a783eec3634b54f560fe5ac5497556abb6716f5eec1a744b5ccb0", + "format": 1 + }, + { + "name": "plugins/modules/cs_network_acl.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95bdf3daeab85335f79033ec894a683583993ee344e3a6c2366271a7c86a7388", + "format": 1 + }, + { + "name": "plugins/modules/cs_template.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "139ea6f288b7a9ab9b47c9687baa4ab5a702b340f6405f2fdfe81148a3026fb3", + "format": 1 + }, + { + "name": "plugins/modules/cs_zone_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8f07b8091bcfca69c6aea9eabad4fd21db193502b13460e1653848637d58a8e2", + "format": 1 + }, + { + "name": "plugins/modules/cs_network_acl_rule.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c31328ad56bf7c19b9fe497f51a96c886c4d56271d836fa1bd7b08003b026266", + "format": 1 + }, + { + "name": "plugins/modules/cs_iso.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6b5b90fb2651a7e201841fb92788949f0a682dca715cb5c0daa84bfedae4e653", + "format": 1 + }, + { + "name": "plugins/modules/cs_resourcelimit.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f5f011e307013938087cc17f9b12f53db18fe921386553bce32a17cff61f2e8e", + "format": 1 + }, + { + "name": "plugins/modules/cs_region.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "40b8580c476de8e7e090e4d3531f777fe2284867c93265034099f927f2841601", + "format": 1 + }, + { + "name": "plugins/modules/cs_role_permission.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3c43f7ab6a107f046a195ecf639a102ebf6f50091c3d3a007b30cdc735188d2d", + "format": 1 + }, + { + "name": "plugins/modules/cs_vpc.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8737ac56bc12ca7283ce098f89384ba3d3a746b42310a80d53e497ef7cbfa816", + "format": 1 + }, + { + "name": "plugins/modules/cs_vpc_offering.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f55428af6c509516322db6489f7f6c7d80e1a8cb14cfc2192f82d9b45b51bd31", + "format": 1 + }, + { + "name": "plugins/modules/cs_role.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9ecac2c3bfb4f7343e4787a2335f0a9ae13b8dc4ee9f0c2bc590cbbb80760bbb", + "format": 1 + }, + { + "name": "plugins/modules/cs_sshkeypair.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9050e14109a0f8fbc0c761a115bf727bfda3e1a0d254a838c543e2e1634a57b8", + "format": 1 + }, + { + "name": "plugins/modules/cs_service_offering.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4f38f829a1ae6b297cdd4e58f8d2b6e3906c60752fc0fb24432627ace509ccbf", + "format": 1 + }, + { + "name": "plugins/modules/cs_host.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "11d5cca2e6bf0f534d21dd268cb96cabe932be47cec148ed427a7783704c7b06", + "format": 1 + }, + { + "name": "plugins/modules/cs_affinitygroup.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fc89dbe37b31267715eaf1037ccc92c787c93f7aaee4c0dfc42e9c9a8c397a86", + "format": 1 + }, + { + "name": "plugins/modules/cs_ip_address.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ec0664301eef74063ec7eac629e848e0b092350a9affe067bcea182c4e1ab5b8", + "format": 1 + }, + { + "name": "plugins/modules/cs_network_offering.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1880e7f84fa082439c7969c41c95faedf45300ee0283fb000968e9e881bd356f", + "format": 1 + }, + { + "name": "plugins/modules/cs_portforward.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a6b8333a131cdbb419d623f709712f3a2d52c6994fc6a8a5d30c3171a45782e6", + "format": 1 + }, + { + "name": "plugins/modules/cs_staticnat.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2dbdf658a2bf86366669dbe012196fce657e125fc3fc3fc12bdce84911138966", + "format": 1 + }, + { + "name": "plugins/modules/cs_image_store.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b6a0c66f180bc32b9994fe355c742c03400b946cb36aac0b121782da61845eb2", + "format": 1 + }, + { + "name": "plugins/modules/cs_vlan_ip_range.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cd724e08554b029c827a2d9e1e43d39c945484d41577a6673f5dff88c34b9579", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7903e82601897dc35af9245b374058d1fb712bcb3d1c4f7c53d2d6eb29a000e8", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.keep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed86f4354405bab1f95e13c965959d170fdd4bbc5757dd0326f0c1237324930e", + "format": 1 + }, + { + "name": "changelogs/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "919ef00776e7d2ff349950ac4b806132aa9faf006e214d5285de54533e443b33", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "bbbd9964907510188daf90dbf5618d86e0e0f359032711c367b0e20844148412", + "format": 1 + }, + { + "name": "requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e5fe54d7f891bf3cdb4831fe2029e870514833d7813fcb55561a1103860f36db", + "format": 1 + }, + { + "name": "COPYING", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c61f12da7cdad526bdcbed47a4c0a603e60dbbfdaf8b66933cd088e9132c303f", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json new file mode 100644 index 00000000..3c2c4a0b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/MANIFEST.json @@ -0,0 +1,41 @@ +{ + "collection_info": { + "namespace": "ngine_io", + "name": "cloudstack", + "version": "1.2.0", + "authors": [ + "Ren\u00e9 Moser <mail@renemoser.net>", + "David Passante (@dpassante)", + "Netservers Ltd. <support@netservers.co.uk>", + "Patryk D. Cichy <patryk.d.cichy@gmail.com>", + "Darren Worrall <darren@iweb.co.uk>", + "Marc-Aur\u00e8le Brothier (@marcaurele)", + "Jefferson Gir\u00e3o <jefferson@girao.net>", + "Gregor Riepl (@onitake)" + ], + "readme": "README.md", + "tags": [ + "cloud", + "cloudstack", + "ngine_io" + ], + "description": "Ansible Collection for Apache CloudStack based clouds", + "license": [ + "GPL-3.0-or-later" + ], + "license_file": null, + "dependencies": {}, + "repository": "https://github.com/ngine-io/ansible-collection-cloudstack", + "documentation": "", + "homepage": "https://github.com/ngine-io/ansible-collection-cloudstack", + "issues": "https://github.com/ngine-io/ansible-collection-cloudstack/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d3565502e4872c321d5cd6bc49a05a497f5fdea67c8542c50701c3ec02a10905", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md new file mode 100644 index 00000000..4e5b3e59 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/README.md @@ -0,0 +1,80 @@ +![Collection integration](https://github.com/ngine-io/ansible-collection-cloudstack/workflows/Collection%20integration/badge.svg) + [![Codecov](https://img.shields.io/codecov/c/github/ngine-io/ansible-collection-cloudstack)](https://codecov.io/gh/ngine-io/ansible-collection-cloudstack) +[![License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](LICENSE) + +# Ansible Collection for Apache CloudStack Clouds + +This collection provides a series of Ansible modules and plugins for interacting with the [Apache CloudStack](https://cloudstack.apache.org) Cloud. + +## Requirements + +- ansible version >= 2.9 + +## Installation + +To install the collection hosted in Galaxy: + +```bash +ansible-galaxy collection install ngine_io.cloudstack +``` + +To upgrade to the latest version of the collection: + +```bash +ansible-galaxy collection install ngine_io.cloudstack --force +``` + +## Usage + +### Playbooks + +To use a module from Apache CloudStack collection, please reference the full namespace, collection name, and modules name that you want to use: + +```yaml +--- +- name: Using Apache CloudStack collection + hosts: localhost + tasks: + - ngine_io.cloudstack.cs_instance: + ... +``` + +Or you can add full namepsace and collecton name in the `collections` element: + +```yaml +--- +- name: Using Apache CloudStack collection + hosts: localhost + collections: + - ngine_io.cloudstack + tasks: + - cs_instance: + ... +``` + +### Roles + +For existing Ansible roles, please also reference the full namespace, collection name, and modules name which used in tasks instead of just modules name. + +### Plugins + +To use a plugin, please reference the full namespace, collection name, and plugin name that you want to use: + +```yaml +plugin: ngine_io.cloudstack.cloudstack +``` + +## Contributing + +There are many ways in which you can participate in the project, for example: + +- Submit bugs and feature requests, and help us verify as they are checked in +- Review source code changes +- Review the documentation and make pull requests for anything from typos to new content +- If you are interested in fixing issues and contributing directly to the code base, please see the [CONTRIBUTING](CONTRIBUTING.md) document. + +## License + +GNU General Public License v3.0 + +See [COPYING](COPYING) to see the full text. diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore new file mode 100644 index 00000000..6be6b533 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/.gitignore @@ -0,0 +1 @@ +/.plugin-cache.yaml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml new file mode 100644 index 00000000..aa38f675 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/changelog.yaml @@ -0,0 +1,47 @@ +ancestor: null +releases: + 0.3.0: + changes: + minor_changes: + - Added support for SSL CA cert verification (https://github.com/ngine-io/ansible-collection-cloudstack/pull/3) + fragments: + - 3-ca-cert-verification.yml + release_date: '2020-07-04' + 1.0.0: + changes: + minor_changes: + - cs_vlan_ip_range - Added support to set IP range for system VMs (https://github.com/ngine-io/ansible-collection-cloudstack/pull/18) + - cs_vlan_ip_range - Added support to specify pod name (https://github.com/ngine-io/ansible-collection-cloudstack/pull/20) + fragments: + - 18-for_system_vms_cs_vlan_ip_range.yml + - 20-cs_vlan_ip_range_pod.yml + release_date: '2020-08-15' + 1.0.1: + changes: + minor_changes: + - cs_configuration - Workaround for empty global settings idempotency (https://github.com/ngine-io/ansible-collection-cloudstack/pull/25). + fragments: + - 25-empty_config_idempotency.yml + release_date: '2020-08-30' + 1.1.0: + changes: + minor_changes: + - Deprecated the funtionality of first returned zone to be the default zone + because of an unreliable API. Zone will be required beginning with next major + version 2.0.0. + - cs_ip_address - allow to pick a particular IP address for a network, available + since CloudStack v4.13 (https://github.com/ngine-io/ansible-collection-cloudstack/issues/30). + fragments: + - cs_ip_address_reservation.yaml + - default_zone_deprecation.yaml + release_date: '2020-11-26' + 1.2.0: + changes: + minor_changes: + - cs_instance - Fixed an edge case caused by `displaytext` not available (https://github.com/ngine-io/ansible-collection-cloudstack/pull/49). + - cs_network - Fixed constraints when creating networks. The param `gateway` + is no longer required if the param `netmask` is given (https://github.com/ngine-io/ansible-collection-cloudstack/pull/54). + fragments: + - 49-cs_instance-fix-keyerror.yml + - 54-cs_network-fix-constraints.yml + release_date: '2021-02-02' diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml new file mode 100644 index 00000000..3cb90f28 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/config.yaml @@ -0,0 +1,29 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +keep_fragments: false +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: Apache CloudStack Collection +trivial_section_name: trivial diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/changelogs/fragments/.keep diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml new file mode 100644 index 00000000..0815ba0e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/codecov.yml @@ -0,0 +1,15 @@ +--- +coverage: + precision: 2 + round: down + range: "70...100" + status: + project: + default: + informational: true + threshold: 10% + patch: + default: + threshold: 10% +fixes: + - "/ansible_collections/ngine_io/cloudstack/::" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml new file mode 100644 index 00000000..22f211d6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/meta/runtime.yml @@ -0,0 +1,68 @@ +requires_ansible: '>=2.9.10' +action_groups: + cloudstack: + - cs_traffic_type + - cs_cluster + - cs_network_acl + - cs_affinitygroup + - cs_user + - cs_host + - cs_resourcelimit + - cs_zone_info + - cs_loadbalancer_rule + - cs_vpn_connection + - cs_iso + - cs_sshkeypair + - cs_instancegroup + - cs_securitygroup + - cs_vlan_ip_range + - cs_vpn_gateway + - cs_loadbalancer_rule_member + - cs_ip_address + - cs_pod + - cs_portforward + - cs_role_permission + - cs_vpc_offering + - cs_securitygroup_rule + - cs_vpc + - cs_instance_nic + - cs_region + - cs_firewall + - cs_role + - cs_router + - cs_template + - cs_disk_offering + - cs_vpn_customer_gateway + - cs_snapshot_policy + - cs_project + - cs_instance_password_reset + - cs_staticnat + - cs_storage_pool + - cs_zone + - cs_configuration + - cs_service_offering + - cs_vmsnapshot + - cs_network_offering + - cs_physical_network + - cs_instance_nic_secondaryip + - cs_network_acl_rule + - cs_image_store + - cs_domain + - cs_network + - cs_instance_info + - cs_account + - cs_instance + - cs_volume + +plugin_routing: + modules: + cs_instance_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed to ngine_io.cloudstack.cs_instance_info + redirect: ngine_io.cloudstack.cs_instance_info + cs_zone_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed to ngine_io.cloudstack.cs_zone_info + redirect: ngine_io.cloudstack.cs_zone_info diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py new file mode 100644 index 00000000..af13a3af --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/doc_fragments/cloudstack.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Standard cloudstack documentation fragment + DOCUMENTATION = r''' +options: + api_key: + description: + - API key of the CloudStack API. + - If not given, the C(CLOUDSTACK_KEY) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + type: str + api_secret: + description: + - Secret key of the CloudStack API. + - If not set, the C(CLOUDSTACK_SECRET) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + type: str + api_url: + description: + - URL of the CloudStack API e.g. https://cloud.example.com/client/api. + - If not given, the C(CLOUDSTACK_ENDPOINT) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + type: str + api_http_method: + description: + - HTTP method used to query the API endpoint. + - If not given, the C(CLOUDSTACK_METHOD) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + - Fallback value is C(get) if not specified. + type: str + choices: [ get, post ] + api_timeout: + description: + - HTTP timeout in seconds. + - If not given, the C(CLOUDSTACK_TIMEOUT) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + - Fallback value is 10 seconds if not specified. + type: int + api_region: + description: + - Name of the ini section in the C(cloustack.ini) file. + - If not given, the C(CLOUDSTACK_REGION) env variable is considered. + type: str + default: cloudstack + api_verify_ssl_cert: + description: + - CA authority cert file. + - If not given, the C(CLOUDSTACK_VERIFY) env variable is considered. + - As the last option, the value is taken from the ini config file, also see the notes. + - Fallback value is C(null) if not specified. + type: str +requirements: + - python >= 2.6 + - cs >= 0.9.0 +notes: + - Ansible uses the C(cs) library's configuration method if credentials are not + provided by the arguments C(api_url), C(api_key), C(api_secret). + Configuration is read from several locations, in the following order. + The C(CLOUDSTACK_ENDPOINT), C(CLOUDSTACK_KEY), C(CLOUDSTACK_SECRET) and + C(CLOUDSTACK_METHOD). C(CLOUDSTACK_TIMEOUT) environment variables. + A C(CLOUDSTACK_CONFIG) environment variable pointing to an C(.ini) file. + A C(cloudstack.ini) file in the current working directory. + A C(.cloudstack.ini) file in the users home directory. + Optionally multiple credentials and endpoints can be specified using ini sections in C(cloudstack.ini). + Use the argument C(api_region) to select the section name, default section is C(cloudstack). + See https://github.com/exoscale/cs for more information. + - A detailed guide about cloudstack modules can be found in the L(CloudStack Cloud Guide,../scenario_guides/guide_cloudstack.html). + - This module supports check mode. +''' diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/inventory/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py new file mode 100644 index 00000000..ac310ecb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/module_utils/cloudstack.py @@ -0,0 +1,685 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +import os +import sys +import time +import traceback + +from ansible.module_utils._text import to_text, to_native +from ansible.module_utils.basic import missing_required_lib + +CS_IMP_ERR = None +try: + from cs import CloudStack, CloudStackException, read_config + HAS_LIB_CS = True +except ImportError: + CS_IMP_ERR = traceback.format_exc() + HAS_LIB_CS = False + + +if sys.version_info > (3,): + long = int + + +def cs_argument_spec(): + return dict( + api_key=dict(default=os.environ.get('CLOUDSTACK_KEY')), + api_secret=dict(default=os.environ.get('CLOUDSTACK_SECRET'), no_log=True), + api_url=dict(default=os.environ.get('CLOUDSTACK_ENDPOINT')), + api_http_method=dict(choices=['get', 'post'], default=os.environ.get('CLOUDSTACK_METHOD')), + api_timeout=dict(type='int', default=os.environ.get('CLOUDSTACK_TIMEOUT')), + api_region=dict(default=os.environ.get('CLOUDSTACK_REGION') or 'cloudstack'), + api_verify_ssl_cert=dict(default=os.environ.get('CLOUDSTACK_VERIFY')), + ) + + +def cs_required_together(): + return [['api_key', 'api_secret']] + + +class AnsibleCloudStack: + + def __init__(self, module): + if not HAS_LIB_CS: + module.fail_json(msg=missing_required_lib('cs'), exception=CS_IMP_ERR) + + self.result = { + 'changed': False, + 'diff': { + 'before': dict(), + 'after': dict() + } + } + + # Common returns, will be merged with self.returns + # search_for_key: replace_with_key + self.common_returns = { + 'id': 'id', + 'name': 'name', + 'created': 'created', + 'zonename': 'zone', + 'state': 'state', + 'project': 'project', + 'account': 'account', + 'domain': 'domain', + 'displaytext': 'display_text', + 'displayname': 'display_name', + 'description': 'description', + } + + # Init returns dict for use in subclasses + self.returns = {} + # these values will be casted to int + self.returns_to_int = {} + # these keys will be compared case sensitive in self.has_changed() + self.case_sensitive_keys = [ + 'id', + 'displaytext', + 'displayname', + 'description', + ] + + self.module = module + self._cs = None + + # Helper for VPCs + self._vpc_networks_ids = None + + self.domain = None + self.account = None + self.project = None + self.ip_address = None + self.network = None + self.physical_network = None + self.vpc = None + self.zone = None + self.vm = None + self.vm_default_nic = None + self.os_type = None + self.hypervisor = None + self.capabilities = None + self.network_acl = None + + @property + def cs(self): + if self._cs is None: + api_config = self.get_api_config() + self._cs = CloudStack(**api_config) + return self._cs + + def get_api_config(self): + api_region = self.module.params.get('api_region') or os.environ.get('CLOUDSTACK_REGION') + try: + config = read_config(api_region) + except KeyError: + config = {} + + api_config = { + 'endpoint': self.module.params.get('api_url') or config.get('endpoint'), + 'key': self.module.params.get('api_key') or config.get('key'), + 'secret': self.module.params.get('api_secret') or config.get('secret'), + 'timeout': self.module.params.get('api_timeout') or config.get('timeout') or 10, + 'method': self.module.params.get('api_http_method') or config.get('method') or 'get', + 'verify': self.module.params.get('api_verify_ssl_cert') or config.get('verify'), + } + self.result.update({ + 'api_region': api_region, + 'api_url': api_config['endpoint'], + 'api_key': api_config['key'], + 'api_timeout': int(api_config['timeout']), + 'api_http_method': api_config['method'], + 'api_verify_ssl_cert': api_config['verify'], + }) + if not all([api_config['endpoint'], api_config['key'], api_config['secret']]): + self.fail_json(msg="Missing api credentials: can not authenticate") + return api_config + + def fail_json(self, **kwargs): + self.result.update(kwargs) + self.module.fail_json(**self.result) + + def get_or_fallback(self, key=None, fallback_key=None): + value = self.module.params.get(key) + if not value: + value = self.module.params.get(fallback_key) + return value + + def has_changed(self, want_dict, current_dict, only_keys=None, skip_diff_for_keys=None): + result = False + for key, value in want_dict.items(): + + # Optionally limit by a list of keys + if only_keys and key not in only_keys: + continue + + # Skip None values + if value is None: + continue + + if key in current_dict: + if isinstance(value, (int, float, long, complex)): + + # ensure we compare the same type + if isinstance(value, int): + current_dict[key] = int(current_dict[key]) + elif isinstance(value, float): + current_dict[key] = float(current_dict[key]) + elif isinstance(value, long): + current_dict[key] = long(current_dict[key]) + elif isinstance(value, complex): + current_dict[key] = complex(current_dict[key]) + + if value != current_dict[key]: + if skip_diff_for_keys and key not in skip_diff_for_keys: + self.result['diff']['before'][key] = current_dict[key] + self.result['diff']['after'][key] = value + result = True + else: + before_value = to_text(current_dict[key]) + after_value = to_text(value) + + if self.case_sensitive_keys and key in self.case_sensitive_keys: + if before_value != after_value: + if skip_diff_for_keys and key not in skip_diff_for_keys: + self.result['diff']['before'][key] = before_value + self.result['diff']['after'][key] = after_value + result = True + + # Test for diff in case insensitive way + elif before_value.lower() != after_value.lower(): + if skip_diff_for_keys and key not in skip_diff_for_keys: + self.result['diff']['before'][key] = before_value + self.result['diff']['after'][key] = after_value + result = True + else: + if skip_diff_for_keys and key not in skip_diff_for_keys: + self.result['diff']['before'][key] = None + self.result['diff']['after'][key] = to_text(value) + result = True + return result + + def _get_by_key(self, key=None, my_dict=None): + if my_dict is None: + my_dict = {} + if key: + if key in my_dict: + return my_dict[key] + self.fail_json(msg="Something went wrong: %s not found" % key) + return my_dict + + def query_api(self, command, **args): + try: + res = getattr(self.cs, command)(**args) + + if 'errortext' in res: + self.fail_json(msg="Failed: '%s'" % res['errortext']) + + except CloudStackException as e: + self.fail_json(msg='CloudStackException: %s' % to_native(e)) + + except Exception as e: + self.fail_json(msg=to_native(e)) + + return res + + def get_network_acl(self, key=None): + if self.network_acl is None: + args = { + 'name': self.module.params.get('network_acl'), + 'vpcid': self.get_vpc(key='id'), + } + network_acls = self.query_api('listNetworkACLLists', **args) + if network_acls: + self.network_acl = network_acls['networkacllist'][0] + self.result['network_acl'] = self.network_acl['name'] + if self.network_acl: + return self._get_by_key(key, self.network_acl) + else: + self.fail_json(msg="Network ACL %s not found" % self.module.params.get('network_acl')) + + def get_vpc(self, key=None): + """Return a VPC dictionary or the value of given key of.""" + if self.vpc: + return self._get_by_key(key, self.vpc) + + vpc = self.module.params.get('vpc') + if not vpc: + vpc = os.environ.get('CLOUDSTACK_VPC') + if not vpc: + return None + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + } + vpcs = self.query_api('listVPCs', **args) + if not vpcs: + self.fail_json(msg="No VPCs available.") + + for v in vpcs['vpc']: + if vpc in [v['name'], v['displaytext'], v['id']]: + # Fail if the identifyer matches more than one VPC + if self.vpc: + self.fail_json(msg="More than one VPC found with the provided identifyer '%s'" % vpc) + else: + self.vpc = v + self.result['vpc'] = v['name'] + if self.vpc: + return self._get_by_key(key, self.vpc) + self.fail_json(msg="VPC '%s' not found" % vpc) + + def is_vpc_network(self, network_id): + """Returns True if network is in VPC.""" + # This is an efficient way to query a lot of networks at a time + if self._vpc_networks_ids is None: + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + } + vpcs = self.query_api('listVPCs', **args) + self._vpc_networks_ids = [] + if vpcs: + for vpc in vpcs['vpc']: + for n in vpc.get('network', []): + self._vpc_networks_ids.append(n['id']) + return network_id in self._vpc_networks_ids + + def get_physical_network(self, key=None): + if self.physical_network: + return self._get_by_key(key, self.physical_network) + physical_network = self.module.params.get('physical_network') + args = { + 'zoneid': self.get_zone(key='id') + } + physical_networks = self.query_api('listPhysicalNetworks', **args) + if not physical_networks: + self.fail_json(msg="No physical networks available.") + + for net in physical_networks['physicalnetwork']: + if physical_network in [net['name'], net['id']]: + self.physical_network = net + self.result['physical_network'] = net['name'] + return self._get_by_key(key, self.physical_network) + self.fail_json(msg="Physical Network '%s' not found" % physical_network) + + def get_network(self, key=None): + """Return a network dictionary or the value of given key of.""" + if self.network: + return self._get_by_key(key, self.network) + + network = self.module.params.get('network') + if not network: + vpc_name = self.get_vpc(key='name') + if vpc_name: + self.fail_json(msg="Could not find network for VPC '%s' due missing argument: network" % vpc_name) + return None + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'vpcid': self.get_vpc(key='id') + } + networks = self.query_api('listNetworks', **args) + if not networks: + self.fail_json(msg="No networks available.") + + for n in networks['network']: + # ignore any VPC network if vpc param is not given + if 'vpcid' in n and not self.get_vpc(key='id'): + continue + if network in [n['displaytext'], n['name'], n['id']]: + self.result['network'] = n['name'] + self.network = n + return self._get_by_key(key, self.network) + self.fail_json(msg="Network '%s' not found" % network) + + def get_project(self, key=None): + if self.project: + return self._get_by_key(key, self.project) + + project = self.module.params.get('project') + if not project: + project = os.environ.get('CLOUDSTACK_PROJECT') + if not project: + return None + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id') + } + projects = self.query_api('listProjects', **args) + if projects: + for p in projects['project']: + if project.lower() in [p['name'].lower(), p['id']]: + self.result['project'] = p['name'] + self.project = p + return self._get_by_key(key, self.project) + self.fail_json(msg="project '%s' not found" % project) + + def get_pod(self, key=None): + pod_name = self.module.params.get('pod') + if not pod_name: + return None + args = { + 'name': pod_name, + 'zoneid': self.get_zone(key='id'), + } + pods = self.query_api('listPods', **args) + if pods: + return self._get_by_key(key, pods['pod'][0]) + self.module.fail_json(msg="Pod %s not found in zone %s" % (self.module.params.get('pod'), self.get_zone(key='name'))) + + def get_ip_address(self, key=None): + if self.ip_address: + return self._get_by_key(key, self.ip_address) + + ip_address = self.module.params.get('ip_address') + if not ip_address: + self.fail_json(msg="IP address param 'ip_address' is required") + + args = { + 'ipaddress': ip_address, + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'vpcid': self.get_vpc(key='id'), + } + + ip_addresses = self.query_api('listPublicIpAddresses', **args) + + if not ip_addresses: + self.fail_json(msg="IP address '%s' not found" % args['ipaddress']) + + self.ip_address = ip_addresses['publicipaddress'][0] + return self._get_by_key(key, self.ip_address) + + def get_vm_guest_ip(self): + vm_guest_ip = self.module.params.get('vm_guest_ip') + default_nic = self.get_vm_default_nic() + + if not vm_guest_ip: + return default_nic['ipaddress'] + + for secondary_ip in default_nic['secondaryip']: + if vm_guest_ip == secondary_ip['ipaddress']: + return vm_guest_ip + self.fail_json(msg="Secondary IP '%s' not assigned to VM" % vm_guest_ip) + + def get_vm_default_nic(self): + if self.vm_default_nic: + return self.vm_default_nic + + nics = self.query_api('listNics', virtualmachineid=self.get_vm(key='id')) + if nics: + for n in nics['nic']: + if n['isdefault']: + self.vm_default_nic = n + return self.vm_default_nic + self.fail_json(msg="No default IP address of VM '%s' found" % self.module.params.get('vm')) + + def get_vm(self, key=None, filter_zone=True): + if self.vm: + return self._get_by_key(key, self.vm) + + vm = self.module.params.get('vm') + if not vm: + self.fail_json(msg="Virtual machine param 'vm' is required") + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id') if filter_zone else None, + 'fetch_list': True, + } + vms = self.query_api('listVirtualMachines', **args) + if vms: + for v in vms: + if vm.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]: + self.vm = v + return self._get_by_key(key, self.vm) + self.fail_json(msg="Virtual machine '%s' not found" % vm) + + def get_disk_offering(self, key=None): + disk_offering = self.module.params.get('disk_offering') + if not disk_offering: + return None + + # Do not add domain filter for disk offering listing. + disk_offerings = self.query_api('listDiskOfferings') + if disk_offerings: + for d in disk_offerings['diskoffering']: + if disk_offering in [d['displaytext'], d['name'], d['id']]: + return self._get_by_key(key, d) + self.fail_json(msg="Disk offering '%s' not found" % disk_offering) + + def get_zone(self, key=None): + if self.zone: + return self._get_by_key(key, self.zone) + + zone = self.module.params.get('zone') + if not zone: + zone = os.environ.get('CLOUDSTACK_ZONE') + zones = self.query_api('listZones') + + if not zones: + self.fail_json(msg="No zones available. Please create a zone first") + + # use the first zone if no zone param given + if not zone: + self.module.deprecate( + msg="Using first zone as default is deprecated because of unreliable API, zone needs to be defined.", + version="2.0.0", + collection_name="ngine_io.cloudstack" + ) + self.zone = zones['zone'][0] + self.result['zone'] = self.zone['name'] + return self._get_by_key(key, self.zone) + + if zones: + for z in zones['zone']: + if zone.lower() in [z['name'].lower(), z['id']]: + self.result['zone'] = z['name'] + self.zone = z + return self._get_by_key(key, self.zone) + self.fail_json(msg="zone '%s' not found" % zone) + + def get_os_type(self, key=None): + if self.os_type: + return self._get_by_key(key, self.zone) + + os_type = self.module.params.get('os_type') + if not os_type: + return None + + os_types = self.query_api('listOsTypes') + if os_types: + for o in os_types['ostype']: + if os_type in [o['description'], o['id']]: + self.os_type = o + return self._get_by_key(key, self.os_type) + self.fail_json(msg="OS type '%s' not found" % os_type) + + def get_hypervisor(self): + if self.hypervisor: + return self.hypervisor + + hypervisor = self.module.params.get('hypervisor') + hypervisors = self.query_api('listHypervisors') + + # use the first hypervisor if no hypervisor param given + if not hypervisor: + self.hypervisor = hypervisors['hypervisor'][0]['name'] + return self.hypervisor + + for h in hypervisors['hypervisor']: + if hypervisor.lower() == h['name'].lower(): + self.hypervisor = h['name'] + return self.hypervisor + self.fail_json(msg="Hypervisor '%s' not found" % hypervisor) + + def get_account(self, key=None): + if self.account: + return self._get_by_key(key, self.account) + + account = self.module.params.get('account') + if not account: + account = os.environ.get('CLOUDSTACK_ACCOUNT') + if not account: + return None + + domain = self.module.params.get('domain') + if not domain: + self.fail_json(msg="Account must be specified with Domain") + + args = { + 'name': account, + 'domainid': self.get_domain(key='id'), + 'listall': True + } + accounts = self.query_api('listAccounts', **args) + if accounts: + self.account = accounts['account'][0] + self.result['account'] = self.account['name'] + return self._get_by_key(key, self.account) + self.fail_json(msg="Account '%s' not found" % account) + + def get_domain(self, key=None): + if self.domain: + return self._get_by_key(key, self.domain) + + domain = self.module.params.get('domain') + if not domain: + domain = os.environ.get('CLOUDSTACK_DOMAIN') + if not domain: + return None + + args = { + 'listall': True, + } + domains = self.query_api('listDomains', **args) + if domains: + for d in domains['domain']: + if d['path'].lower() in [domain.lower(), "root/" + domain.lower(), "root" + domain.lower()]: + self.domain = d + self.result['domain'] = d['path'] + return self._get_by_key(key, self.domain) + self.fail_json(msg="Domain '%s' not found" % domain) + + def query_tags(self, resource, resource_type): + args = { + 'resourceid': resource['id'], + 'resourcetype': resource_type, + } + tags = self.query_api('listTags', **args) + return self.get_tags(resource=tags, key='tag') + + def get_tags(self, resource=None, key='tags'): + existing_tags = [] + for tag in resource.get(key) or []: + existing_tags.append({'key': tag['key'], 'value': tag['value']}) + return existing_tags + + def _process_tags(self, resource, resource_type, tags, operation="create"): + if tags: + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'resourceids': resource['id'], + 'resourcetype': resource_type, + 'tags': tags, + } + if operation == "create": + response = self.query_api('createTags', **args) + else: + response = self.query_api('deleteTags', **args) + self.poll_job(response) + + def _tags_that_should_exist_or_be_updated(self, resource, tags): + existing_tags = self.get_tags(resource) + return [tag for tag in tags if tag not in existing_tags] + + def _tags_that_should_not_exist(self, resource, tags): + existing_tags = self.get_tags(resource) + return [tag for tag in existing_tags if tag not in tags] + + def ensure_tags(self, resource, resource_type=None): + if not resource_type or not resource: + self.fail_json(msg="Error: Missing resource or resource_type for tags.") + + if 'tags' in resource: + tags = self.module.params.get('tags') + if tags is not None: + self._process_tags(resource, resource_type, self._tags_that_should_not_exist(resource, tags), operation="delete") + self._process_tags(resource, resource_type, self._tags_that_should_exist_or_be_updated(resource, tags)) + resource['tags'] = self.query_tags(resource=resource, resource_type=resource_type) + return resource + + def get_capabilities(self, key=None): + if self.capabilities: + return self._get_by_key(key, self.capabilities) + capabilities = self.query_api('listCapabilities') + self.capabilities = capabilities['capability'] + return self._get_by_key(key, self.capabilities) + + def poll_job(self, job=None, key=None): + if 'jobid' in job: + while True: + res = self.query_api('queryAsyncJobResult', jobid=job['jobid']) + if res['jobstatus'] != 0 and 'jobresult' in res: + + if 'errortext' in res['jobresult']: + self.fail_json(msg="Failed: '%s'" % res['jobresult']['errortext']) + + if key and key in res['jobresult']: + job = res['jobresult'][key] + + break + time.sleep(2) + return job + + def update_result(self, resource, result=None): + if result is None: + result = dict() + if resource: + returns = self.common_returns.copy() + returns.update(self.returns) + for search_key, return_key in returns.items(): + if search_key in resource: + result[return_key] = resource[search_key] + + # Bad bad API does not always return int when it should. + for search_key, return_key in self.returns_to_int.items(): + if search_key in resource: + result[return_key] = int(resource[search_key]) + + if 'tags' in resource: + result['tags'] = resource['tags'] + return result + + def get_result(self, resource): + return self.update_result(resource, self.result) + + def get_result_and_facts(self, facts_name, resource): + result = self.get_result(resource) + + ansible_facts = { + facts_name: result.copy() + } + for k in ['diff', 'changed']: + if k in ansible_facts[facts_name]: + del ansible_facts[facts_name][k] + + result.update(ansible_facts=ansible_facts) + return result diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py new file mode 100644 index 00000000..694f62d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_account.py @@ -0,0 +1,450 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_account +short_description: Manages accounts on Apache CloudStack based clouds. +description: + - Create, disable, lock, enable and remove accounts. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of account. + type: str + required: true + username: + description: + - Username of the user to be created if account did not exist. + - Required on I(state=present). + type: str + password: + description: + - Password of the user to be created if account did not exist. + - Required on I(state=present) if I(ldap_domain) is not set. + type: str + first_name: + description: + - First name of the user to be created if account did not exist. + - Required on I(state=present) if I(ldap_domain) is not set. + type: str + last_name: + description: + - Last name of the user to be created if account did not exist. + - Required on I(state=present) if I(ldap_domain) is not set. + type: str + email: + description: + - Email of the user to be created if account did not exist. + - Required on I(state=present) if I(ldap_domain) is not set. + type: str + timezone: + description: + - Timezone of the user to be created if account did not exist. + type: str + network_domain: + description: + - Network domain of the account. + type: str + account_type: + description: + - Type of the account. + type: str + choices: [ user, root_admin, domain_admin ] + default: user + domain: + description: + - Domain the account is related to. + type: str + default: ROOT + role: + description: + - Creates the account under the specified role name or id. + type: str + ldap_domain: + description: + - Name of the LDAP group or OU to bind. + - If set, account will be linked to LDAP. + type: str + ldap_type: + description: + - Type of the ldap name. GROUP or OU, defaults to GROUP. + type: str + choices: [ GROUP, OU ] + default: GROUP + state: + description: + - State of the account. + - C(unlocked) is an alias for C(enabled). + type: str + choices: [ present, absent, enabled, disabled, locked, unlocked ] + default: present + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack + +''' + +EXAMPLES = ''' +- name: create an account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + username: customer_xy + password: S3Cur3 + last_name: Doe + first_name: John + email: john.doe@example.com + domain: CUSTOMERS + role: Domain Admin + +- name: Lock an existing account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + domain: CUSTOMERS + state: locked + +- name: Disable an existing account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + domain: CUSTOMERS + state: disabled + +- name: Enable an existing account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + domain: CUSTOMERS + state: enabled + +- name: Remove an account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + domain: CUSTOMERS + state: absent + +- name: Create a single user LDAP account in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_account: + name: customer_xy + username: customer_xy + domain: CUSTOMERS + ldap_domain: cn=customer_xy,cn=team_xy,ou=People,dc=domain,dc=local + +- name: Create a LDAP account in domain 'CUSTOMERS' and bind it to a LDAP group + ngine_io.cloudstack.cs_account: + name: team_xy + username: customer_xy + domain: CUSTOMERS + ldap_domain: cn=team_xy,ou=People,dc=domain,dc=local +''' + +RETURN = ''' +--- +id: + description: UUID of the account. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +name: + description: Name of the account. + returned: success + type: str + sample: linus@example.com +account_type: + description: Type of the account. + returned: success + type: str + sample: user +state: + description: State of the account. + returned: success + type: str + sample: enabled +network_domain: + description: Network domain of the account. + returned: success + type: str + sample: example.local +domain: + description: Domain the account is related. + returned: success + type: str + sample: ROOT +role: + description: The role name of the account + returned: success + type: str + sample: Domain Admin +''' + +# import cloudstack common +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackAccount(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackAccount, self).__init__(module) + self.returns = { + 'networkdomain': 'network_domain', + 'rolename': 'role', + } + self.account = None + self.account_types = { + 'user': 0, + 'root_admin': 1, + 'domain_admin': 2, + } + + def get_role_id(self): + role_param = self.module.params.get('role') + role_id = None + + if role_param: + role_list = self.query_api('listRoles') + for role in role_list['role']: + if role_param in [role['name'], role['id']]: + role_id = role['id'] + + if not role_id: + self.module.fail_json(msg="Role not found: %s" % role_param) + + return role_id + + def get_account_type(self): + account_type = self.module.params.get('account_type') + return self.account_types[account_type] + + def get_account(self): + if not self.account: + args = { + 'listall': True, + 'domainid': self.get_domain(key='id'), + 'fetch_list': True, + } + accounts = self.query_api('listAccounts', **args) + if accounts: + account_name = self.module.params.get('name') + for a in accounts: + if account_name == a['name']: + self.account = a + break + + return self.account + + def enable_account(self): + account = self.get_account() + if not account: + account = self.present_account() + + if account['state'].lower() != 'enabled': + self.result['changed'] = True + args = { + 'id': account['id'], + 'account': self.module.params.get('name'), + 'domainid': self.get_domain(key='id') + } + if not self.module.check_mode: + res = self.query_api('enableAccount', **args) + account = res['account'] + return account + + def lock_account(self): + return self.lock_or_disable_account(lock=True) + + def disable_account(self): + return self.lock_or_disable_account() + + def lock_or_disable_account(self, lock=False): + account = self.get_account() + if not account: + account = self.present_account() + + # we need to enable the account to lock it. + if lock and account['state'].lower() == 'disabled': + account = self.enable_account() + + if (lock and account['state'].lower() != 'locked' or + not lock and account['state'].lower() != 'disabled'): + self.result['changed'] = True + args = { + 'id': account['id'], + 'account': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + 'lock': lock, + } + if not self.module.check_mode: + account = self.query_api('disableAccount', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + account = self.poll_job(account, 'account') + return account + + def present_account(self): + account = self.get_account() + + if not account: + self.result['changed'] = True + + if self.module.params.get('ldap_domain'): + required_params = [ + 'domain', + 'username', + ] + self.module.fail_on_missing_params(required_params=required_params) + + account = self.create_ldap_account(account) + + else: + required_params = [ + 'email', + 'username', + 'password', + 'first_name', + 'last_name', + ] + self.module.fail_on_missing_params(required_params=required_params) + + account = self.create_account(account) + + return account + + def create_ldap_account(self, account): + args = { + 'account': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + 'accounttype': self.get_account_type(), + 'networkdomain': self.module.params.get('network_domain'), + 'username': self.module.params.get('username'), + 'timezone': self.module.params.get('timezone'), + 'roleid': self.get_role_id() + } + if not self.module.check_mode: + res = self.query_api('ldapCreateAccount', **args) + account = res['account'] + + args = { + 'account': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + 'accounttype': self.get_account_type(), + 'ldapdomain': self.module.params.get('ldap_domain'), + 'type': self.module.params.get('ldap_type') + } + + self.query_api('linkAccountToLdap', **args) + + return account + + def create_account(self, account): + args = { + 'account': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + 'accounttype': self.get_account_type(), + 'networkdomain': self.module.params.get('network_domain'), + 'username': self.module.params.get('username'), + 'password': self.module.params.get('password'), + 'firstname': self.module.params.get('first_name'), + 'lastname': self.module.params.get('last_name'), + 'email': self.module.params.get('email'), + 'timezone': self.module.params.get('timezone'), + 'roleid': self.get_role_id() + } + if not self.module.check_mode: + res = self.query_api('createAccount', **args) + account = res['account'] + + return account + + def absent_account(self): + account = self.get_account() + if account: + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('deleteAccount', id=account['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'account') + return account + + def get_result(self, account): + super(AnsibleCloudStackAccount, self).get_result(account) + if account: + if 'accounttype' in account: + for key, value in self.account_types.items(): + if value == account['accounttype']: + self.result['account_type'] = key + break + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + state=dict(choices=['present', 'absent', 'enabled', 'disabled', 'locked', 'unlocked'], default='present'), + account_type=dict(choices=['user', 'root_admin', 'domain_admin'], default='user'), + network_domain=dict(), + domain=dict(default='ROOT'), + email=dict(), + first_name=dict(), + last_name=dict(), + username=dict(), + password=dict(no_log=True), + timezone=dict(), + role=dict(), + ldap_domain=dict(), + ldap_type=dict(choices=['GROUP', 'OU'], default='GROUP'), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_acc = AnsibleCloudStackAccount(module) + + state = module.params.get('state') + + if state in ['absent']: + account = acs_acc.absent_account() + + elif state in ['enabled', 'unlocked']: + account = acs_acc.enable_account() + + elif state in ['disabled']: + account = acs_acc.disable_account() + + elif state in ['locked']: + account = acs_acc.lock_account() + + else: + account = acs_acc.present_account() + + result = acs_acc.get_result(account) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py new file mode 100644 index 00000000..46c1b176 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_affinitygroup.py @@ -0,0 +1,230 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_affinitygroup +short_description: Manages affinity groups on Apache CloudStack based clouds. +description: + - Create and remove affinity groups. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the affinity group. + type: str + required: true + affinity_type: + description: + - Type of the affinity group. If not specified, first found affinity type is used. + type: str + description: + description: + - Description of the affinity group. + type: str + state: + description: + - State of the affinity group. + type: str + choices: [ present, absent ] + default: present + domain: + description: + - Domain the affinity group is related to. + type: str + account: + description: + - Account the affinity group is related to. + type: str + project: + description: + - Name of the project the affinity group is related to. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack + +''' + +EXAMPLES = ''' +- name: Create a affinity group + ngine_io.cloudstack.cs_affinitygroup: + name: haproxy + affinity_type: host anti-affinity + +- name: Remove a affinity group + ngine_io.cloudstack.cs_affinitygroup: + name: haproxy + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the affinity group. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +name: + description: Name of affinity group. + returned: success + type: str + sample: app +description: + description: Description of affinity group. + returned: success + type: str + sample: application affinity group +affinity_type: + description: Type of affinity group. + returned: success + type: str + sample: host anti-affinity +project: + description: Name of project the affinity group is related to. + returned: success + type: str + sample: Production +domain: + description: Domain the affinity group is related to. + returned: success + type: str + sample: example domain +account: + description: Account the affinity group is related to. + returned: success + type: str + sample: example account +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackAffinityGroup(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackAffinityGroup, self).__init__(module) + self.returns = { + 'type': 'affinity_type', + } + self.affinity_group = None + + def get_affinity_group(self): + if not self.affinity_group: + + args = { + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'name': self.module.params.get('name'), + } + affinity_groups = self.query_api('listAffinityGroups', **args) + if affinity_groups: + self.affinity_group = affinity_groups['affinitygroup'][0] + return self.affinity_group + + def get_affinity_type(self): + affinity_type = self.module.params.get('affinity_type') + + affinity_types = self.query_api('listAffinityGroupTypes', ) + if affinity_types: + if not affinity_type: + return affinity_types['affinityGroupType'][0]['type'] + + for a in affinity_types['affinityGroupType']: + if a['type'] == affinity_type: + return a['type'] + self.module.fail_json(msg="affinity group type not found: %s" % affinity_type) + + def create_affinity_group(self): + affinity_group = self.get_affinity_group() + if not affinity_group: + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'type': self.get_affinity_type(), + 'description': self.module.params.get('description'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + } + if not self.module.check_mode: + res = self.query_api('createAffinityGroup', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + affinity_group = self.poll_job(res, 'affinitygroup') + return affinity_group + + def remove_affinity_group(self): + affinity_group = self.get_affinity_group() + if affinity_group: + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + } + if not self.module.check_mode: + res = self.query_api('deleteAffinityGroup', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + self.poll_job(res, 'affinitygroup') + return affinity_group + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + affinity_type=dict(), + description=dict(), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_ag = AnsibleCloudStackAffinityGroup(module) + + state = module.params.get('state') + if state in ['absent']: + affinity_group = acs_ag.remove_affinity_group() + else: + affinity_group = acs_ag.create_affinity_group() + + result = acs_ag.get_result(affinity_group) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py new file mode 100644 index 00000000..88ea35f2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_cluster.py @@ -0,0 +1,375 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_cluster +short_description: Manages host clusters on Apache CloudStack based clouds. +description: + - Create, update and remove clusters. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - name of the cluster. + type: str + required: true + zone: + description: + - Name of the zone in which the cluster belongs to. + - If not set, default zone is used. + type: str + pod: + description: + - Name of the pod in which the cluster belongs to. + type: str + cluster_type: + description: + - Type of the cluster. + - Required if I(state=present) + type: str + choices: [ CloudManaged, ExternalManaged ] + hypervisor: + description: + - Name the hypervisor to be used. + - Required if I(state=present). + - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator). + type: str + url: + description: + - URL for the cluster + type: str + username: + description: + - Username for the cluster. + type: str + password: + description: + - Password for the cluster. + type: str + guest_vswitch_name: + description: + - Name of virtual switch used for guest traffic in the cluster. + - This would override zone wide traffic label setting. + type: str + guest_vswitch_type: + description: + - Type of virtual switch used for guest traffic in the cluster. + - Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch) + type: str + choices: [ vmwaresvs, vmwaredvs ] + public_vswitch_name: + description: + - Name of virtual switch used for public traffic in the cluster. + - This would override zone wide traffic label setting. + type: str + public_vswitch_type: + description: + - Type of virtual switch used for public traffic in the cluster. + - Allowed values are, vmwaresvs (for VMware standard vSwitch) and vmwaredvs (for VMware distributed vSwitch) + type: str + choices: [ vmwaresvs, vmwaredvs ] + vms_ip_address: + description: + - IP address of the VSM associated with this cluster. + type: str + vms_username: + description: + - Username for the VSM associated with this cluster. + type: str + vms_password: + description: + - Password for the VSM associated with this cluster. + type: str + ovm3_cluster: + description: + - Ovm3 native OCFS2 clustering enabled for cluster. + type: str + ovm3_pool: + description: + - Ovm3 native pooling enabled for cluster. + type: str + ovm3_vip: + description: + - Ovm3 vip to use for pool (and cluster). + type: str + state: + description: + - State of the cluster. + type: str + choices: [ present, absent, disabled, enabled ] + default: present +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a cluster is present + ngine_io.cloudstack.cs_cluster: + name: kvm-cluster-01 + zone: ch-zrh-ix-01 + hypervisor: KVM + cluster_type: CloudManaged + +- name: Ensure a cluster is disabled + ngine_io.cloudstack.cs_cluster: + name: kvm-cluster-01 + zone: ch-zrh-ix-01 + state: disabled + +- name: Ensure a cluster is enabled + ngine_io.cloudstack.cs_cluster: + name: kvm-cluster-01 + zone: ch-zrh-ix-01 + state: enabled + +- name: Ensure a cluster is absent + ngine_io.cloudstack.cs_cluster: + name: kvm-cluster-01 + zone: ch-zrh-ix-01 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the cluster. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the cluster. + returned: success + type: str + sample: cluster01 +allocation_state: + description: State of the cluster. + returned: success + type: str + sample: Enabled +cluster_type: + description: Type of the cluster. + returned: success + type: str + sample: ExternalManaged +cpu_overcommit_ratio: + description: The CPU overcommit ratio of the cluster. + returned: success + type: str + sample: 1.0 +memory_overcommit_ratio: + description: The memory overcommit ratio of the cluster. + returned: success + type: str + sample: 1.0 +managed_state: + description: Whether this cluster is managed by CloudStack. + returned: success + type: str + sample: Managed +ovm3_vip: + description: Ovm3 VIP to use for pooling and/or clustering + returned: success + type: str + sample: 10.10.10.101 +hypervisor: + description: Hypervisor of the cluster + returned: success + type: str + sample: VMware +zone: + description: Name of zone the cluster is in. + returned: success + type: str + sample: ch-gva-2 +pod: + description: Name of pod the cluster is in. + returned: success + type: str + sample: pod01 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackCluster(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackCluster, self).__init__(module) + self.returns = { + 'allocationstate': 'allocation_state', + 'hypervisortype': 'hypervisor', + 'clustertype': 'cluster_type', + 'podname': 'pod', + 'managedstate': 'managed_state', + 'memoryovercommitratio': 'memory_overcommit_ratio', + 'cpuovercommitratio': 'cpu_overcommit_ratio', + 'ovm3vip': 'ovm3_vip', + } + self.cluster = None + + def _get_common_cluster_args(self): + args = { + 'clustername': self.module.params.get('name'), + 'hypervisor': self.module.params.get('hypervisor'), + 'clustertype': self.module.params.get('cluster_type'), + } + state = self.module.params.get('state') + if state in ['enabled', 'disabled']: + args['allocationstate'] = state.capitalize() + return args + + def get_cluster(self): + if not self.cluster: + args = {} + + uuid = self.module.params.get('id') + if uuid: + args['id'] = uuid + clusters = self.query_api('listClusters', **args) + if clusters: + self.cluster = clusters['cluster'][0] + return self.cluster + + args['name'] = self.module.params.get('name') + clusters = self.query_api('listClusters', **args) + if clusters: + self.cluster = clusters['cluster'][0] + # fix different return from API then request argument given + self.cluster['hypervisor'] = self.cluster['hypervisortype'] + self.cluster['clustername'] = self.cluster['name'] + return self.cluster + + def present_cluster(self): + cluster = self.get_cluster() + if cluster: + cluster = self._update_cluster() + else: + cluster = self._create_cluster() + return cluster + + def _create_cluster(self): + required_params = [ + 'cluster_type', + 'hypervisor', + ] + self.module.fail_on_missing_params(required_params=required_params) + + args = self._get_common_cluster_args() + args['zoneid'] = self.get_zone(key='id') + args['podid'] = self.get_pod(key='id') + args['url'] = self.module.params.get('url') + args['username'] = self.module.params.get('username') + args['password'] = self.module.params.get('password') + args['guestvswitchname'] = self.module.params.get('guest_vswitch_name') + args['guestvswitchtype'] = self.module.params.get('guest_vswitch_type') + args['publicvswitchtype'] = self.module.params.get('public_vswitch_name') + args['publicvswitchtype'] = self.module.params.get('public_vswitch_type') + args['vsmipaddress'] = self.module.params.get('vms_ip_address') + args['vsmusername'] = self.module.params.get('vms_username') + args['vmspassword'] = self.module.params.get('vms_password') + args['ovm3cluster'] = self.module.params.get('ovm3_cluster') + args['ovm3pool'] = self.module.params.get('ovm3_pool') + args['ovm3vip'] = self.module.params.get('ovm3_vip') + + self.result['changed'] = True + + cluster = None + if not self.module.check_mode: + res = self.query_api('addCluster', **args) + + # API returns a list as result CLOUDSTACK-9205 + if isinstance(res['cluster'], list): + cluster = res['cluster'][0] + else: + cluster = res['cluster'] + return cluster + + def _update_cluster(self): + cluster = self.get_cluster() + + args = self._get_common_cluster_args() + args['id'] = cluster['id'] + + if self.has_changed(args, cluster): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateCluster', **args) + cluster = res['cluster'] + + return cluster + + def absent_cluster(self): + cluster = self.get_cluster() + if cluster: + self.result['changed'] = True + + args = { + 'id': cluster['id'], + } + + if not self.module.check_mode: + self.query_api('deleteCluster', **args) + + return cluster + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + zone=dict(), + pod=dict(), + cluster_type=dict(choices=['CloudManaged', 'ExternalManaged']), + hypervisor=dict(), + state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'), + url=dict(), + username=dict(), + password=dict(no_log=True), + guest_vswitch_name=dict(), + guest_vswitch_type=dict(choices=['vmwaresvs', 'vmwaredvs']), + public_vswitch_name=dict(), + public_vswitch_type=dict(choices=['vmwaresvs', 'vmwaredvs']), + vms_ip_address=dict(), + vms_username=dict(), + vms_password=dict(no_log=True), + ovm3_cluster=dict(), + ovm3_pool=dict(), + ovm3_vip=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_cluster = AnsibleCloudStackCluster(module) + + state = module.params.get('state') + if state in ['absent']: + cluster = acs_cluster.absent_cluster() + else: + cluster = acs_cluster.present_cluster() + + result = acs_cluster.get_result(cluster) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py new file mode 100644 index 00000000..dd11d932 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_configuration.py @@ -0,0 +1,270 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_configuration +short_description: Manages configuration on Apache CloudStack based clouds. +description: + - Manages global, zone, account, storage and cluster configurations. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the configuration. + type: str + required: true + value: + description: + - Value of the configuration. + type: str + required: true + account: + description: + - Ensure the value for corresponding account. + type: str + domain: + description: + - Domain the account is related to. + - Only considered if I(account) is used. + type: str + default: ROOT + zone: + description: + - Ensure the value for corresponding zone. + type: str + storage: + description: + - Ensure the value for corresponding storage pool. + type: str + cluster: + description: + - Ensure the value for corresponding cluster. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure global configuration + ngine_io.cloudstack.cs_configuration: + name: router.reboot.when.outofband.migrated + value: false + +- name: Ensure zone configuration + ngine_io.cloudstack.cs_configuration: + name: router.reboot.when.outofband.migrated + zone: ch-gva-01 + value: true + +- name: Ensure storage configuration + ngine_io.cloudstack.cs_configuration: + name: storage.overprovisioning.factor + storage: storage01 + value: 2.0 + +- name: Ensure account configuration + ngine_io.cloudstack.cs_configuration: + name: allow.public.user.templates + value: false + account: acme inc + domain: customers +''' + +RETURN = ''' +--- +category: + description: Category of the configuration. + returned: success + type: str + sample: Advanced +scope: + description: Scope (zone/cluster/storagepool/account) of the parameter that needs to be updated. + returned: success + type: str + sample: storagepool +description: + description: Description of the configuration. + returned: success + type: str + sample: Setup the host to do multipath +name: + description: Name of the configuration. + returned: success + type: str + sample: zone.vlan.capacity.notificationthreshold +value: + description: Value of the configuration. + returned: success + type: str + sample: "0.75" +account: + description: Account of the configuration. + returned: success + type: str + sample: admin +Domain: + description: Domain of account of the configuration. + returned: success + type: str + sample: ROOT +zone: + description: Zone of the configuration. + returned: success + type: str + sample: ch-gva-01 +cluster: + description: Cluster of the configuration. + returned: success + type: str + sample: cluster01 +storage: + description: Storage of the configuration. + returned: success + type: str + sample: storage01 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackConfiguration(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackConfiguration, self).__init__(module) + self.returns = { + 'category': 'category', + 'scope': 'scope', + 'value': 'value', + } + self.storage = None + self.account = None + self.cluster = None + + def _get_common_configuration_args(self): + args = { + 'name': self.module.params.get('name'), + 'accountid': self.get_account(key='id'), + 'storageid': self.get_storage(key='id'), + 'zoneid': self.get_zone(key='id'), + 'clusterid': self.get_cluster(key='id'), + } + return args + + def get_zone(self, key=None): + # make sure we do net use the default zone + zone = self.module.params.get('zone') + if zone: + return super(AnsibleCloudStackConfiguration, self).get_zone(key=key) + + def get_cluster(self, key=None): + if not self.cluster: + cluster_name = self.module.params.get('cluster') + if not cluster_name: + return None + args = { + 'name': cluster_name, + } + clusters = self.query_api('listClusters', **args) + if clusters: + self.cluster = clusters['cluster'][0] + self.result['cluster'] = self.cluster['name'] + else: + self.module.fail_json(msg="Cluster %s not found." % cluster_name) + return self._get_by_key(key=key, my_dict=self.cluster) + + def get_storage(self, key=None): + if not self.storage: + storage_pool_name = self.module.params.get('storage') + if not storage_pool_name: + return None + args = { + 'name': storage_pool_name, + } + storage_pools = self.query_api('listStoragePools', **args) + if storage_pools: + self.storage = storage_pools['storagepool'][0] + self.result['storage'] = self.storage['name'] + else: + self.module.fail_json(msg="Storage pool %s not found." % storage_pool_name) + return self._get_by_key(key=key, my_dict=self.storage) + + def get_configuration(self): + configuration = None + args = self._get_common_configuration_args() + args['fetch_list'] = True + configurations = self.query_api('listConfigurations', **args) + if not configurations: + self.module.fail_json(msg="Configuration %s not found." % args['name']) + for config in configurations: + if args['name'] == config['name']: + configuration = config + return configuration + + def get_value(self): + value = str(self.module.params.get('value')) + if value in ('True', 'False'): + value = value.lower() + return value + + def present_configuration(self): + configuration = self.get_configuration() + args = self._get_common_configuration_args() + args['value'] = self.get_value() + empty_value = args['value'] in [None, ''] and 'value' not in configuration + if self.has_changed(args, configuration, ['value']) and not empty_value: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateConfiguration', **args) + configuration = res['configuration'] + return configuration + + def get_result(self, configuration): + self.result = super(AnsibleCloudStackConfiguration, self).get_result(configuration) + if self.account: + self.result['account'] = self.account['name'] + self.result['domain'] = self.domain['path'] + elif self.zone: + self.result['zone'] = self.zone['name'] + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + value=dict(type='str', required=True), + zone=dict(), + storage=dict(), + cluster=dict(), + account=dict(), + domain=dict(default='ROOT') + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_configuration = AnsibleCloudStackConfiguration(module) + configuration = acs_configuration.present_configuration() + result = acs_configuration.get_result(configuration) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py new file mode 100644 index 00000000..b9bd4570 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_disk_offering.py @@ -0,0 +1,375 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, David Passante <@dpassante> +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_disk_offering +description: + - Create and delete disk offerings for guest VMs. + - Update display_text or display_offering of existing disk offering. +short_description: Manages disk offerings on Apache CloudStack based clouds. +author: + - David Passante (@dpassante) + - René Moser (@resmo) +version_added: 0.1.0 +options: + disk_size: + description: + - Size of the disk offering in GB (1GB = 1,073,741,824 bytes). + type: int + bytes_read_rate: + description: + - Bytes read rate of the disk offering. + type: int + bytes_write_rate: + description: + - Bytes write rate of the disk offering. + type: int + display_text: + description: + - Display text of the disk offering. + - If not set, C(name) will be used as C(display_text) while creating. + type: str + domain: + description: + - Domain the disk offering is related to. + - Public for all domains and subdomains if not set. + type: str + hypervisor_snapshot_reserve: + description: + - Hypervisor snapshot reserve space as a percent of a volume. + - Only for managed storage using Xen or VMware. + type: int + customized: + description: + - Whether disk offering iops is custom or not. + type: bool + iops_read_rate: + description: + - IO requests read rate of the disk offering. + type: int + iops_write_rate: + description: + - IO requests write rate of the disk offering. + type: int + iops_max: + description: + - Max. iops of the disk offering. + type: int + iops_min: + description: + - Min. iops of the disk offering. + type: int + name: + description: + - Name of the disk offering. + type: str + required: true + provisioning_type: + description: + - Provisioning type used to create volumes. + type: str + choices: [ thin, sparse, fat ] + state: + description: + - State of the disk offering. + type: str + choices: [ present, absent ] + default: present + storage_type: + description: + - The storage type of the disk offering. + type: str + choices: [ local, shared ] + storage_tags: + description: + - The storage tags for this disk offering. + type: list + elements: str + aliases: [ storage_tag ] + display_offering: + description: + - An optional field, whether to display the offering to the end user or not. + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a disk offering with local storage + ngine_io.cloudstack.cs_disk_offering: + name: small + display_text: Small 10GB + disk_size: 10 + storage_type: local + +- name: Create or update a disk offering with shared storage + ngine_io.cloudstack.cs_disk_offering: + name: small + display_text: Small 10GB + disk_size: 10 + storage_type: shared + storage_tags: SAN01 + +- name: Remove a disk offering + ngine_io.cloudstack.cs_disk_offering: + name: small + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the disk offering + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +disk_size: + description: Size of the disk offering in GB + returned: success + type: int + sample: 10 +iops_max: + description: Max iops of the disk offering + returned: success + type: int + sample: 1000 +iops_min: + description: Min iops of the disk offering + returned: success + type: int + sample: 500 +bytes_read_rate: + description: Bytes read rate of the disk offering + returned: success + type: int + sample: 1000 +bytes_write_rate: + description: Bytes write rate of the disk offering + returned: success + type: int + sample: 1000 +iops_read_rate: + description: IO requests per second read rate of the disk offering + returned: success + type: int + sample: 1000 +iops_write_rate: + description: IO requests per second write rate of the disk offering + returned: success + type: int + sample: 1000 +created: + description: Date the offering was created + returned: success + type: str + sample: 2017-11-19T10:48:59+0000 +display_text: + description: Display text of the offering + returned: success + type: str + sample: Small 10GB +domain: + description: Domain the offering is into + returned: success + type: str + sample: ROOT +storage_tags: + description: List of storage tags + returned: success + type: list + sample: [ 'eco' ] +customized: + description: Whether the offering uses custom IOPS or not + returned: success + type: bool + sample: false +name: + description: Name of the system offering + returned: success + type: str + sample: Micro +provisioning_type: + description: Provisioning type used to create volumes + returned: success + type: str + sample: thin +storage_type: + description: Storage type used to create volumes + returned: success + type: str + sample: shared +display_offering: + description: Whether to display the offering to the end user or not. + returned: success + type: bool + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackDiskOffering(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackDiskOffering, self).__init__(module) + self.returns = { + 'disksize': 'disk_size', + 'diskBytesReadRate': 'bytes_read_rate', + 'diskBytesWriteRate': 'bytes_write_rate', + 'diskIopsReadRate': 'iops_read_rate', + 'diskIopsWriteRate': 'iops_write_rate', + 'maxiops': 'iops_max', + 'miniops': 'iops_min', + 'hypervisorsnapshotreserve': 'hypervisor_snapshot_reserve', + 'customized': 'customized', + 'provisioningtype': 'provisioning_type', + 'storagetype': 'storage_type', + 'tags': 'storage_tags', + 'displayoffering': 'display_offering', + } + + self.disk_offering = None + + def get_disk_offering(self): + args = { + 'name': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + } + disk_offerings = self.query_api('listDiskOfferings', **args) + if disk_offerings: + for disk_offer in disk_offerings['diskoffering']: + if args['name'] == disk_offer['name']: + self.disk_offering = disk_offer + + return self.disk_offering + + def present_disk_offering(self): + disk_offering = self.get_disk_offering() + if not disk_offering: + disk_offering = self._create_offering(disk_offering) + else: + disk_offering = self._update_offering(disk_offering) + + return disk_offering + + def absent_disk_offering(self): + disk_offering = self.get_disk_offering() + if disk_offering: + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'id': disk_offering['id'], + } + self.query_api('deleteDiskOffering', **args) + return disk_offering + + def _create_offering(self, disk_offering): + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'disksize': self.module.params.get('disk_size'), + 'bytesreadrate': self.module.params.get('bytes_read_rate'), + 'byteswriterate': self.module.params.get('bytes_write_rate'), + 'customized': self.module.params.get('customized'), + 'domainid': self.get_domain(key='id'), + 'hypervisorsnapshotreserve': self.module.params.get('hypervisor_snapshot_reserve'), + 'iopsreadrate': self.module.params.get('iops_read_rate'), + 'iopswriterate': self.module.params.get('iops_write_rate'), + 'maxiops': self.module.params.get('iops_max'), + 'miniops': self.module.params.get('iops_min'), + 'provisioningtype': self.module.params.get('provisioning_type'), + 'diskofferingdetails': self.module.params.get('disk_offering_details'), + 'storagetype': self.module.params.get('storage_type'), + 'tags': self.module.params.get('storage_tags'), + 'displayoffering': self.module.params.get('display_offering'), + } + if not self.module.check_mode: + res = self.query_api('createDiskOffering', **args) + disk_offering = res['diskoffering'] + return disk_offering + + def _update_offering(self, disk_offering): + args = { + 'id': disk_offering['id'], + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'displayoffering': self.module.params.get('display_offering'), + } + if self.has_changed(args, disk_offering): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateDiskOffering', **args) + disk_offering = res['diskoffering'] + return disk_offering + + def get_result(self, disk_offering): + super(AnsibleCloudStackDiskOffering, self).get_result(disk_offering) + if disk_offering: + # Prevent confusion, the api returns a tags key for storage tags. + if 'tags' in disk_offering: + self.result['storage_tags'] = disk_offering['tags'].split(',') or [disk_offering['tags']] + if 'tags' in self.result: + del self.result['tags'] + + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + domain=dict(), + disk_size=dict(type='int'), + display_offering=dict(type='bool'), + hypervisor_snapshot_reserve=dict(type='int'), + bytes_read_rate=dict(type='int'), + bytes_write_rate=dict(type='int'), + customized=dict(type='bool'), + iops_read_rate=dict(type='int'), + iops_write_rate=dict(type='int'), + iops_max=dict(type='int'), + iops_min=dict(type='int'), + provisioning_type=dict(choices=['thin', 'sparse', 'fat']), + storage_type=dict(choices=['local', 'shared']), + storage_tags=dict(type='list', elements='str', aliases=['storage_tag']), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_do = AnsibleCloudStackDiskOffering(module) + + state = module.params.get('state') + if state == "absent": + disk_offering = acs_do.absent_disk_offering() + else: + disk_offering = acs_do.present_disk_offering() + + result = acs_do.get_result(disk_offering) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py new file mode 100644 index 00000000..68177164 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_domain.py @@ -0,0 +1,244 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_domain +short_description: Manages domains on Apache CloudStack based clouds. +description: + - Create, update and remove domains. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + path: + description: + - Path of the domain. + - Prefix C(ROOT/) or C(/ROOT/) in path is optional. + type: str + required: true + network_domain: + description: + - Network domain for networks in the domain. + type: str + clean_up: + description: + - Clean up all domain resources like child domains and accounts. + - Considered on I(state=absent). + type: bool + default: no + state: + description: + - State of the domain. + type: str + choices: [ present, absent ] + default: present + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a domain + ngine_io.cloudstack.cs_domain: + path: ROOT/customers + network_domain: customers.example.com + +- name: Create another subdomain + ngine_io.cloudstack.cs_domain: + path: ROOT/customers/xy + network_domain: xy.customers.example.com + +- name: Remove a domain + ngine_io.cloudstack.cs_domain: + path: ROOT/customers/xy + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the domain. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +name: + description: Name of the domain. + returned: success + type: str + sample: customers +path: + description: Domain path. + returned: success + type: str + sample: /ROOT/customers +parent_domain: + description: Parent domain of the domain. + returned: success + type: str + sample: ROOT +network_domain: + description: Network domain of the domain. + returned: success + type: str + sample: example.local +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackDomain(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackDomain, self).__init__(module) + self.returns = { + 'path': 'path', + 'networkdomain': 'network_domain', + 'parentdomainname': 'parent_domain', + } + self.domain = None + + def _get_domain_internal(self, path=None): + if not path: + path = self.module.params.get('path') + + if path.endswith('/'): + self.module.fail_json(msg="Path '%s' must not end with /" % path) + + path = path.lower() + + if path.startswith('/') and not path.startswith('/root/'): + path = "root" + path + elif not path.startswith('root/'): + path = "root/" + path + + args = { + 'listall': True, + 'fetch_list': True, + } + + domains = self.query_api('listDomains', **args) + if domains: + for d in domains: + if path == d['path'].lower(): + return d + return None + + def get_name(self): + # last part of the path is the name + name = self.module.params.get('path').split('/')[-1:] + return name + + def get_domain(self, key=None): + if not self.domain: + self.domain = self._get_domain_internal() + return self._get_by_key(key, self.domain) + + def get_parent_domain(self, key=None): + path = self.module.params.get('path') + # cut off last /* + path = '/'.join(path.split('/')[:-1]) + if not path: + return None + parent_domain = self._get_domain_internal(path=path) + if not parent_domain: + self.module.fail_json(msg="Parent domain path %s does not exist" % path) + return self._get_by_key(key, parent_domain) + + def present_domain(self): + domain = self.get_domain() + if not domain: + domain = self.create_domain(domain) + else: + domain = self.update_domain(domain) + return domain + + def create_domain(self, domain): + self.result['changed'] = True + + args = { + 'name': self.get_name(), + 'parentdomainid': self.get_parent_domain(key='id'), + 'networkdomain': self.module.params.get('network_domain') + } + if not self.module.check_mode: + res = self.query_api('createDomain', **args) + domain = res['domain'] + return domain + + def update_domain(self, domain): + args = { + 'id': domain['id'], + 'networkdomain': self.module.params.get('network_domain') + } + if self.has_changed(args, domain): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateDomain', **args) + domain = res['domain'] + return domain + + def absent_domain(self): + domain = self.get_domain() + if domain: + self.result['changed'] = True + + if not self.module.check_mode: + args = { + 'id': domain['id'], + 'cleanup': self.module.params.get('clean_up') + } + res = self.query_api('deleteDomain', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + res = self.poll_job(res, 'domain') + return domain + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + path=dict(required=True), + state=dict(choices=['present', 'absent'], default='present'), + network_domain=dict(), + clean_up=dict(type='bool', default=False), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_dom = AnsibleCloudStackDomain(module) + + state = module.params.get('state') + if state in ['absent']: + domain = acs_dom.absent_domain() + else: + domain = acs_dom.present_domain() + + result = acs_dom.get_result(domain) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py new file mode 100644 index 00000000..e60d5e80 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_facts.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_facts +short_description: Gather facts on instances of Apache CloudStack based clouds. +description: + - This module fetches data from the metadata API in CloudStack. The module must be called from within the instance itself. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + filter: + description: + - Filter for a specific fact. + type: str + choices: + - cloudstack_service_offering + - cloudstack_availability_zone + - cloudstack_public_hostname + - cloudstack_public_ipv4 + - cloudstack_local_hostname + - cloudstack_local_ipv4 + - cloudstack_instance_id + - cloudstack_user_data + meta_data_host: + description: + - Host or IP of the meta data API service. + - If not set, determination by parsing the dhcp lease file. + type: str +requirements: [ yaml ] +''' + +EXAMPLES = ''' +# Gather all facts on instances +- name: Gather cloudstack facts + ngine_io.cloudstack.cs_facts: + +# Gather specific fact on instances +- name: Gather cloudstack facts + ngine_io.cloudstack.cs_facts: filter=cloudstack_instance_id + +# Gather specific fact on instances with a given meta_data_host +- name: Gather cloudstack facts + ngine_io.cloudstack.cs_facts: + filter: cloudstack_instance_id + meta_data_host: 169.254.169.254 +''' + +RETURN = ''' +--- +cloudstack_availability_zone: + description: zone the instance is deployed in. + returned: success + type: str + sample: ch-gva-2 +cloudstack_instance_id: + description: UUID of the instance. + returned: success + type: str + sample: ab4e80b0-3e7e-4936-bdc5-e334ba5b0139 +cloudstack_local_hostname: + description: local hostname of the instance. + returned: success + type: str + sample: VM-ab4e80b0-3e7e-4936-bdc5-e334ba5b0139 +cloudstack_local_ipv4: + description: local IPv4 of the instance. + returned: success + type: str + sample: 185.19.28.35 +cloudstack_public_hostname: + description: public IPv4 of the router. Same as I(cloudstack_public_ipv4). + returned: success + type: str + sample: VM-ab4e80b0-3e7e-4936-bdc5-e334ba5b0139 +cloudstack_public_ipv4: + description: public IPv4 of the router. + returned: success + type: str + sample: 185.19.28.35 +cloudstack_service_offering: + description: service offering of the instance. + returned: success + type: str + sample: Micro 512mb 1cpu +cloudstack_user_data: + description: data of the instance provided by users. + returned: success + type: dict + sample: { "bla": "foo" } +''' + +import os +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils.urls import fetch_url +from ansible.module_utils.facts import ansible_collector, default_collectors + +YAML_IMP_ERR = None +try: + import yaml + HAS_LIB_YAML = True +except ImportError: + YAML_IMP_ERR = traceback.format_exc() + HAS_LIB_YAML = False + +CS_METADATA_BASE_URL = "http://%s/latest/meta-data" +CS_USERDATA_BASE_URL = "http://%s/latest/user-data" + + +class CloudStackFacts(object): + + def __init__(self): + collector = ansible_collector.get_ansible_collector(all_collector_classes=default_collectors.collectors, + filter_spec='default_ipv4', + gather_subset=['!all', 'network'], + gather_timeout=10) + self.facts = collector.collect(module) + + self.api_ip = None + self.fact_paths = { + 'cloudstack_service_offering': 'service-offering', + 'cloudstack_availability_zone': 'availability-zone', + 'cloudstack_public_hostname': 'public-hostname', + 'cloudstack_public_ipv4': 'public-ipv4', + 'cloudstack_local_hostname': 'local-hostname', + 'cloudstack_local_ipv4': 'local-ipv4', + 'cloudstack_instance_id': 'instance-id' + } + + def run(self): + result = {} + filter = module.params.get('filter') + if not filter: + for key, path in self.fact_paths.items(): + result[key] = self._fetch(CS_METADATA_BASE_URL + "/" + path) + result['cloudstack_user_data'] = self._get_user_data_json() + else: + if filter == 'cloudstack_user_data': + result['cloudstack_user_data'] = self._get_user_data_json() + elif filter in self.fact_paths: + result[filter] = self._fetch(CS_METADATA_BASE_URL + "/" + self.fact_paths[filter]) + return result + + def _get_user_data_json(self): + try: + # this data come form users, we try what we can to parse it... + return yaml.safe_load(self._fetch(CS_USERDATA_BASE_URL)) + except Exception: + return None + + def _fetch(self, path): + api_ip = self._get_api_ip() + if not api_ip: + return None + api_url = path % api_ip + (response, info) = fetch_url(module, api_url, force=True) + if response: + data = response.read() + else: + data = None + return data + + def _get_dhcp_lease_file(self): + """Return the path of the lease file.""" + default_iface = self.facts['default_ipv4']['interface'] + dhcp_lease_file_locations = [ + '/var/lib/dhcp/dhclient.%s.leases' % default_iface, # debian / ubuntu + '/var/lib/dhclient/dhclient-%s.leases' % default_iface, # centos 6 + '/var/lib/dhclient/dhclient--%s.lease' % default_iface, # centos 7 + '/var/db/dhclient.leases.%s' % default_iface, # openbsd + ] + for file_path in dhcp_lease_file_locations: + if os.path.exists(file_path): + return file_path + module.fail_json(msg="Could not find dhclient leases file.") + + def _get_api_ip(self): + """Return the IP of the DHCP server.""" + if module.params.get('meta_data_host'): + return module.params.get('meta_data_host') + elif not self.api_ip: + dhcp_lease_file = self._get_dhcp_lease_file() + for line in open(dhcp_lease_file): + if 'dhcp-server-identifier' in line: + # get IP of string "option dhcp-server-identifier 185.19.28.176;" + line = line.translate(None, ';') + self.api_ip = line.split()[2] + break + if not self.api_ip: + module.fail_json(msg="No dhcp-server-identifier found in leases file.") + return self.api_ip + + +def main(): + global module + module = AnsibleModule( + argument_spec=dict( + filter=dict(default=None, choices=[ + 'cloudstack_service_offering', + 'cloudstack_availability_zone', + 'cloudstack_public_hostname', + 'cloudstack_public_ipv4', + 'cloudstack_local_hostname', + 'cloudstack_local_ipv4', + 'cloudstack_instance_id', + 'cloudstack_user_data', + ]), + meta_data_host=dict(), + ), + supports_check_mode=True + ) + + if not HAS_LIB_YAML: + module.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR) + + cs_facts = CloudStackFacts().run() + cs_facts_result = dict(changed=False, ansible_facts=cs_facts) + module.exit_json(**cs_facts_result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py new file mode 100644 index 00000000..f8878877 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_firewall.py @@ -0,0 +1,439 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright: (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_firewall +short_description: Manages firewall rules on Apache CloudStack based clouds. +description: + - Creates and removes firewall rules. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + ip_address: + description: + - Public IP address the ingress rule is assigned to. + - Required if I(type=ingress). + type: str + network: + description: + - Network the egress rule is related to. + - Required if I(type=egress). + type: str + state: + description: + - State of the firewall rule. + type: str + default: present + choices: [ present, absent ] + type: + description: + - Type of the firewall rule. + type: str + default: ingress + choices: [ ingress, egress ] + protocol: + description: + - Protocol of the firewall rule. + - C(all) is only available if I(type=egress). + type: str + default: tcp + choices: [ tcp, udp, icmp, all ] + cidrs: + description: + - List of CIDRs (full notation) to be used for firewall rule. + - Since version 2.5, it is a list of CIDR. + elements: str + type: list + default: 0.0.0.0/0 + aliases: [ cidr ] + start_port: + description: + - Start port for this rule. + - Considered if I(protocol=tcp) or I(protocol=udp). + type: int + aliases: [ port ] + end_port: + description: + - End port for this rule. Considered if I(protocol=tcp) or I(protocol=udp). + - If not specified, equal I(start_port). + type: int + icmp_type: + description: + - Type of the icmp message being sent. + - Considered if I(protocol=icmp). + type: int + icmp_code: + description: + - Error code for this icmp message. + - Considered if I(protocol=icmp). + type: int + domain: + description: + - Domain the firewall rule is related to. + type: str + account: + description: + - Account the firewall rule is related to. + type: str + project: + description: + - Name of the project the firewall rule is related to. + type: str + zone: + description: + - Name of the zone in which the virtual machine is in. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set an empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Allow inbound port 80/tcp from 1.2.3.4 to 4.3.2.1 + ngine_io.cloudstack.cs_firewall: + ip_address: 4.3.2.1 + port: 80 + cidr: 1.2.3.4/32 + +- name: Allow inbound tcp/udp port 53 to 4.3.2.1 + ngine_io.cloudstack.cs_firewall: + ip_address: 4.3.2.1 + port: 53 + protocol: '{{ item }}' + with_items: + - tcp + - udp + +- name: Ensure firewall rule is removed + ngine_io.cloudstack.cs_firewall: + ip_address: 4.3.2.1 + start_port: 8000 + end_port: 8888 + cidr: 17.0.0.0/8 + state: absent + +- name: Allow all outbound traffic + ngine_io.cloudstack.cs_firewall: + network: my_network + type: egress + protocol: all + +- name: Allow only HTTP outbound traffic for an IP + ngine_io.cloudstack.cs_firewall: + network: my_network + type: egress + port: 80 + cidr: 10.101.1.20 +''' + +RETURN = ''' +--- +id: + description: UUID of the rule. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +ip_address: + description: IP address of the rule if C(type=ingress) + returned: success + type: str + sample: 10.100.212.10 +type: + description: Type of the rule. + returned: success + type: str + sample: ingress +cidr: + description: CIDR string of the rule. + returned: success + type: str + sample: 0.0.0.0/0 +cidrs: + description: CIDR list of the rule. + returned: success + type: list + sample: [ '0.0.0.0/0' ] +protocol: + description: Protocol of the rule. + returned: success + type: str + sample: tcp +start_port: + description: Start port of the rule. + returned: success + type: int + sample: 80 +end_port: + description: End port of the rule. + returned: success + type: int + sample: 80 +icmp_code: + description: ICMP code of the rule. + returned: success + type: int + sample: 1 +icmp_type: + description: ICMP type of the rule. + returned: success + type: int + sample: 1 +network: + description: Name of the network if C(type=egress) + returned: success + type: str + sample: my_network +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackFirewall(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackFirewall, self).__init__(module) + self.returns = { + 'cidrlist': 'cidr', + 'startport': 'start_port', + 'endport': 'end_port', + 'protocol': 'protocol', + 'ipaddress': 'ip_address', + 'icmpcode': 'icmp_code', + 'icmptype': 'icmp_type', + } + self.firewall_rule = None + self.network = None + + def get_firewall_rule(self): + if not self.firewall_rule: + cidrs = self.module.params.get('cidrs') + protocol = self.module.params.get('protocol') + start_port = self.module.params.get('start_port') + end_port = self.get_or_fallback('end_port', 'start_port') + icmp_code = self.module.params.get('icmp_code') + icmp_type = self.module.params.get('icmp_type') + fw_type = self.module.params.get('type') + + if protocol in ['tcp', 'udp'] and not (start_port and end_port): + self.module.fail_json(msg="missing required argument for protocol '%s': start_port or end_port" % protocol) + + if protocol == 'icmp' and not icmp_type: + self.module.fail_json(msg="missing required argument for protocol 'icmp': icmp_type") + + if protocol == 'all' and fw_type != 'egress': + self.module.fail_json(msg="protocol 'all' could only be used for type 'egress'") + + args = { + 'account': self.get_account('name'), + 'domainid': self.get_domain('id'), + 'projectid': self.get_project('id'), + 'fetch_list': True, + } + if fw_type == 'egress': + args['networkid'] = self.get_network(key='id') + if not args['networkid']: + self.module.fail_json(msg="missing required argument for type egress: network") + + # CloudStack 4.11 use the network cidr for 0.0.0.0/0 in egress + # That is why we need to replace it. + network_cidr = self.get_network(key='cidr') + egress_cidrs = [network_cidr if cidr == '0.0.0.0/0' else cidr for cidr in cidrs] + + firewall_rules = self.query_api('listEgressFirewallRules', **args) + else: + args['ipaddressid'] = self.get_ip_address('id') + if not args['ipaddressid']: + self.module.fail_json(msg="missing required argument for type ingress: ip_address") + egress_cidrs = None + + firewall_rules = self.query_api('listFirewallRules', **args) + + if firewall_rules: + for rule in firewall_rules: + type_match = self._type_cidrs_match(rule, cidrs, egress_cidrs) + + protocol_match = ( + self._tcp_udp_match(rule, protocol, start_port, end_port) or + self._icmp_match(rule, protocol, icmp_code, icmp_type) or + self._egress_all_match(rule, protocol, fw_type) + ) + + if type_match and protocol_match: + self.firewall_rule = rule + break + return self.firewall_rule + + def _tcp_udp_match(self, rule, protocol, start_port, end_port): + return ( + protocol in ['tcp', 'udp'] and + protocol == rule['protocol'] and + start_port == int(rule['startport']) and + end_port == int(rule['endport']) + ) + + def _egress_all_match(self, rule, protocol, fw_type): + return ( + protocol in ['all'] and + protocol == rule['protocol'] and + fw_type == 'egress' + ) + + def _icmp_match(self, rule, protocol, icmp_code, icmp_type): + return ( + protocol == 'icmp' and + protocol == rule['protocol'] and + icmp_code == rule['icmpcode'] and + icmp_type == rule['icmptype'] + ) + + def _type_cidrs_match(self, rule, cidrs, egress_cidrs): + if egress_cidrs is not None: + return ",".join(egress_cidrs) == rule['cidrlist'] or ",".join(cidrs) == rule['cidrlist'] + else: + return ",".join(cidrs) == rule['cidrlist'] + + def create_firewall_rule(self): + firewall_rule = self.get_firewall_rule() + if not firewall_rule: + self.result['changed'] = True + + args = { + 'cidrlist': self.module.params.get('cidrs'), + 'protocol': self.module.params.get('protocol'), + 'startport': self.module.params.get('start_port'), + 'endport': self.get_or_fallback('end_port', 'start_port'), + 'icmptype': self.module.params.get('icmp_type'), + 'icmpcode': self.module.params.get('icmp_code') + } + + fw_type = self.module.params.get('type') + if not self.module.check_mode: + if fw_type == 'egress': + args['networkid'] = self.get_network(key='id') + res = self.query_api('createEgressFirewallRule', **args) + else: + args['ipaddressid'] = self.get_ip_address('id') + res = self.query_api('createFirewallRule', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + firewall_rule = self.poll_job(res, 'firewallrule') + + if firewall_rule: + firewall_rule = self.ensure_tags(resource=firewall_rule, resource_type='Firewallrule') + self.firewall_rule = firewall_rule + + return firewall_rule + + def remove_firewall_rule(self): + firewall_rule = self.get_firewall_rule() + if firewall_rule: + self.result['changed'] = True + + args = { + 'id': firewall_rule['id'] + } + + fw_type = self.module.params.get('type') + if not self.module.check_mode: + if fw_type == 'egress': + res = self.query_api('deleteEgressFirewallRule', **args) + else: + res = self.query_api('deleteFirewallRule', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'firewallrule') + return firewall_rule + + def get_result(self, firewall_rule): + super(AnsibleCloudStackFirewall, self).get_result(firewall_rule) + if firewall_rule: + self.result['type'] = self.module.params.get('type') + if self.result['type'] == 'egress': + self.result['network'] = self.get_network(key='displaytext') + if 'cidrlist' in firewall_rule: + self.result['cidrs'] = firewall_rule['cidrlist'].split(',') or [firewall_rule['cidrlist']] + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + ip_address=dict(), + network=dict(), + cidrs=dict(type='list', elements='str', default='0.0.0.0/0', aliases=['cidr']), + protocol=dict(choices=['tcp', 'udp', 'icmp', 'all'], default='tcp'), + type=dict(choices=['ingress', 'egress'], default='ingress'), + icmp_type=dict(type='int'), + icmp_code=dict(type='int'), + start_port=dict(type='int', aliases=['port']), + end_port=dict(type='int'), + state=dict(choices=['present', 'absent'], default='present'), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + required_together = cs_required_together() + required_together.extend([ + ['icmp_type', 'icmp_code'], + ]) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=required_together, + required_one_of=( + ['ip_address', 'network'], + ), + mutually_exclusive=( + ['icmp_type', 'start_port'], + ['icmp_type', 'end_port'], + ['ip_address', 'network'], + ), + supports_check_mode=True + ) + + acs_fw = AnsibleCloudStackFirewall(module) + + state = module.params.get('state') + if state in ['absent']: + fw_rule = acs_fw.remove_firewall_rule() + else: + fw_rule = acs_fw.create_firewall_rule() + + result = acs_fw.get_result(fw_rule) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py new file mode 100644 index 00000000..111b4e0e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_host.py @@ -0,0 +1,607 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_host +short_description: Manages hosts on Apache CloudStack based clouds. +description: + - Create, update and remove hosts. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the host. + type: str + required: true + aliases: [ ip_address ] + url: + description: + - Url of the host used to create a host. + - If not provided, C(http://) and param I(name) is used as url. + - Only considered if I(state=present) and host does not yet exist. + type: str + username: + description: + - Username for the host. + - Required if I(state=present) and host does not yet exist. + type: str + password: + description: + - Password for the host. + - Required if I(state=present) and host does not yet exist. + type: str + pod: + description: + - Name of the pod. + - Required if I(state=present) and host does not yet exist. + type: str + cluster: + description: + - Name of the cluster. + type: str + hypervisor: + description: + - Name of the cluster. + - Required if I(state=present) and host does not yet exist. + - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator). + type: str + allocation_state: + description: + - Allocation state of the host. + type: str + choices: [ enabled, disabled, maintenance ] + host_tags: + description: + - Tags of the host. + type: list + elements: str + aliases: [ host_tag ] + state: + description: + - State of the host. + type: str + default: present + choices: [ present, absent ] + zone: + description: + - Name of the zone in which the host should be deployed. + - If not set, default zone is used. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a host is present but disabled + ngine_io.cloudstack.cs_host: + name: pod01.zone01.example.com + cluster: vcenter.example.com/zone01/cluster01 + pod: pod01 + zone: zone01 + hypervisor: VMware + allocation_state: disabled + host_tags: + - perf + - gpu + +- name: Ensure an existing host is disabled + ngine_io.cloudstack.cs_host: + name: pod01.zone01.example.com + zone: zone01 + allocation_state: disabled + +- name: Ensure an existing host is enabled + ngine_io.cloudstack.cs_host: + name: pod01.zone01.example.com + zone: zone01 + allocation_state: enabled + +- name: Ensure a host is absent + ngine_io.cloudstack.cs_host: + name: pod01.zone01.example.com + zone: zone01 + state: absent +''' + +RETURN = ''' +--- +capabilities: + description: Capabilities of the host. + returned: success + type: str + sample: hvm +cluster: + description: Cluster of the host. + returned: success + type: str + sample: vcenter.example.com/zone/cluster01 +cluster_type: + description: Type of the cluster of the host. + returned: success + type: str + sample: ExternalManaged +cpu_allocated: + description: Amount in percent of the host's CPU currently allocated. + returned: success + type: str + sample: 166.25% +cpu_number: + description: Number of CPUs of the host. + returned: success + type: str + sample: 24 +cpu_sockets: + description: Number of CPU sockets of the host. + returned: success + type: int + sample: 2 +cpu_speed: + description: CPU speed in Mhz + returned: success + type: int + sample: 1999 +cpu_used: + description: Amount of the host's CPU currently used. + returned: success + type: str + sample: 33.6% +cpu_with_overprovisioning: + description: Amount of the host's CPU after applying the cpu.overprovisioning.factor. + returned: success + type: str + sample: 959520.0 +created: + description: Date when the host was created. + returned: success + type: str + sample: 2015-05-03T15:05:51+0200 +disconnected: + description: Date when the host was disconnected. + returned: success + type: str + sample: 2015-05-03T15:05:51+0200 +disk_size_allocated: + description: Host's currently allocated disk size. + returned: success + type: int + sample: 2593 +disk_size_total: + description: Total disk size of the host + returned: success + type: int + sample: 259300 +events: + description: Events available for the host + returned: success + type: str + sample: "Ping; HostDown; AgentConnected; AgentDisconnected; PingTimeout; ShutdownRequested; Remove; StartAgentRebalance; ManagementServerDown" +ha_host: + description: Whether the host is a HA host. + returned: success + type: bool + sample: false +has_enough_capacity: + description: Whether the host has enough CPU and RAM capacity to migrate a VM to it. + returned: success + type: bool + sample: true +host_tags: + description: Comma-separated list of tags for the host. + returned: success + type: str + sample: "perf" +hypervisor: + description: Host's hypervisor. + returned: success + type: str + sample: VMware +hypervisor_version: + description: Hypervisor version. + returned: success + type: str + sample: 5.1 +ip_address: + description: IP address of the host + returned: success + type: str + sample: 10.10.10.1 +is_local_storage_active: + description: Whether the local storage is available or not. + returned: success + type: bool + sample: false +last_pinged: + description: Date and time the host was last pinged. + returned: success + type: str + sample: "1970-01-17T17:27:32+0100" +management_server_id: + description: Management server ID of the host. + returned: success + type: int + sample: 345050593418 +memory_allocated: + description: Amount of the host's memory currently allocated. + returned: success + type: int + sample: 69793218560 +memory_total: + description: Total of memory of the host. + returned: success + type: int + sample: 206085263360 +memory_used: + description: Amount of the host's memory currently used. + returned: success + type: int + sample: 65504776192 +name: + description: Name of the host. + returned: success + type: str + sample: esx32.example.com +network_kbs_read: + description: Incoming network traffic on the host. + returned: success + type: int + sample: 0 +network_kbs_write: + description: Outgoing network traffic on the host. + returned: success + type: int + sample: 0 +os_category: + description: OS category name of the host. + returned: success + type: str + sample: ... +out_of_band_management: + description: Host out-of-band management information. + returned: success + type: str + sample: ... +pod: + description: Pod name of the host. + returned: success + type: str + sample: Pod01 +removed: + description: Date and time the host was removed. + returned: success + type: str + sample: "1970-01-17T17:27:32+0100" +resource_state: + description: Resource state of the host. + returned: success + type: str + sample: Enabled +allocation_state:: + description: Allocation state of the host. + returned: success + type: str + sample: enabled +state: + description: State of the host. + returned: success + type: str + sample: Up +suitable_for_migration: + description: Whether this host is suitable (has enough capacity and satisfies all conditions like hosttags, max guests VM limit, etc) to migrate a VM + to it or not. + returned: success + type: str + sample: true +host_type: + description: Type of the host. + returned: success + type: str + sample: Routing +host_version: + description: Version of the host. + returned: success + type: str + sample: 4.5.2 +gpu_group: + description: GPU cards present in the host. + returned: success + type: list + sample: [] +zone: + description: Zone of the host. + returned: success + type: str + sample: zone01 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) +import time + + +class AnsibleCloudStackHost(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackHost, self).__init__(module) + self.returns = { + 'averageload': 'average_load', + 'capabilities': 'capabilities', + 'clustername': 'cluster', + 'clustertype': 'cluster_type', + 'cpuallocated': 'cpu_allocated', + 'cpunumber': 'cpu_number', + 'cpusockets': 'cpu_sockets', + 'cpuspeed': 'cpu_speed', + 'cpuused': 'cpu_used', + 'cpuwithoverprovisioning': 'cpu_with_overprovisioning', + 'disconnected': 'disconnected', + 'details': 'details', + 'disksizeallocated': 'disk_size_allocated', + 'disksizetotal': 'disk_size_total', + 'events': 'events', + 'hahost': 'ha_host', + 'hasenoughcapacity': 'has_enough_capacity', + 'hypervisor': 'hypervisor', + 'hypervisorversion': 'hypervisor_version', + 'ipaddress': 'ip_address', + 'islocalstorageactive': 'is_local_storage_active', + 'lastpinged': 'last_pinged', + 'managementserverid': 'management_server_id', + 'memoryallocated': 'memory_allocated', + 'memorytotal': 'memory_total', + 'memoryused': 'memory_used', + 'networkkbsread': 'network_kbs_read', + 'networkkbswrite': 'network_kbs_write', + 'oscategoryname': 'os_category', + 'outofbandmanagement': 'out_of_band_management', + 'podname': 'pod', + 'removed': 'removed', + 'resourcestate': 'resource_state', + 'suitableformigration': 'suitable_for_migration', + 'type': 'host_type', + 'version': 'host_version', + 'gpugroup': 'gpu_group', + } + # States only usable by the updateHost API + self.allocation_states_for_update = { + 'enabled': 'Enable', + 'disabled': 'Disable', + } + self.host = None + + def get_cluster(self, key=None): + cluster_name = self.module.params.get('cluster') + if not cluster_name: + return None + args = { + 'name': cluster_name, + 'zoneid': self.get_zone(key='id'), + } + clusters = self.query_api('listClusters', **args) + if clusters: + return self._get_by_key(key, clusters['cluster'][0]) + self.module.fail_json(msg="Cluster %s not found" % cluster_name) + + def get_host_tags(self): + host_tags = self.module.params.get('host_tags') + if host_tags is None: + return None + return ','.join(host_tags) + + def get_host(self, refresh=False): + if self.host is not None and not refresh: + return self.host + + name = self.module.params.get('name') + args = { + 'zoneid': self.get_zone(key='id'), + 'fetch_list': True, + } + res = self.query_api('listHosts', **args) + if res: + for h in res: + if name in [h['ipaddress'], h['name']]: + self.host = h + return self.host + + def _handle_allocation_state(self, host): + allocation_state = self.module.params.get('allocation_state') + if not allocation_state: + return host + + host = self._set_host_allocation_state(host) + + # In case host in maintenance and target is maintenance + if host['allocationstate'].lower() == allocation_state and allocation_state == 'maintenance': + return host + + # Cancel maintenance if target state is enabled/disabled + elif allocation_state in list(self.allocation_states_for_update.keys()): + host = self.disable_maintenance(host) + host = self._update_host(host, self.allocation_states_for_update[allocation_state]) + + # Only an enabled host can put in maintenance + elif allocation_state == 'maintenance': + host = self._update_host(host, 'Enable') + host = self.enable_maintenance(host) + + return host + + def _set_host_allocation_state(self, host): + if host is None: + host['allocationstate'] = 'Enable' + + # Set host allocationstate to be disabled/enabled + elif host['resourcestate'].lower() in list(self.allocation_states_for_update.keys()): + host['allocationstate'] = self.allocation_states_for_update[host['resourcestate'].lower()] + + else: + host['allocationstate'] = host['resourcestate'] + + return host + + def present_host(self): + host = self.get_host() + + if not host: + host = self._create_host(host) + else: + host = self._update_host(host) + + if host: + host = self._handle_allocation_state(host) + + return host + + def _get_url(self): + url = self.module.params.get('url') + if url: + return url + else: + return "http://%s" % self.module.params.get('name') + + def _create_host(self, host): + required_params = [ + 'password', + 'username', + 'hypervisor', + 'pod', + ] + self.module.fail_on_missing_params(required_params=required_params) + self.result['changed'] = True + args = { + 'hypervisor': self.module.params.get('hypervisor'), + 'url': self._get_url(), + 'username': self.module.params.get('username'), + 'password': self.module.params.get('password'), + 'podid': self.get_pod(key='id'), + 'zoneid': self.get_zone(key='id'), + 'clusterid': self.get_cluster(key='id'), + 'hosttags': self.get_host_tags(), + } + if not self.module.check_mode: + host = self.query_api('addHost', **args) + host = host['host'][0] + return host + + def _update_host(self, host, allocation_state=None): + args = { + 'id': host['id'], + 'hosttags': self.get_host_tags(), + 'allocationstate': allocation_state, + } + + if allocation_state is not None: + host = self._set_host_allocation_state(host) + + if self.has_changed(args, host): + self.result['changed'] = True + if not self.module.check_mode: + host = self.query_api('updateHost', **args) + host = host['host'] + + return host + + def absent_host(self): + host = self.get_host() + if host: + self.result['changed'] = True + args = { + 'id': host['id'], + } + if not self.module.check_mode: + res = self.enable_maintenance(host) + if res: + res = self.query_api('deleteHost', **args) + return host + + def enable_maintenance(self, host): + if host['resourcestate'] not in ['PrepareForMaintenance', 'Maintenance']: + self.result['changed'] = True + args = { + 'id': host['id'], + } + if not self.module.check_mode: + res = self.query_api('prepareHostForMaintenance', **args) + self.poll_job(res, 'host') + host = self._poll_for_maintenance() + return host + + def disable_maintenance(self, host): + if host['resourcestate'] in ['PrepareForMaintenance', 'Maintenance']: + self.result['changed'] = True + args = { + 'id': host['id'], + } + if not self.module.check_mode: + res = self.query_api('cancelHostMaintenance', **args) + host = self.poll_job(res, 'host') + return host + + def _poll_for_maintenance(self): + for i in range(0, 300): + time.sleep(2) + host = self.get_host(refresh=True) + if not host: + return None + elif host['resourcestate'] != 'PrepareForMaintenance': + return host + self.fail_json(msg="Polling for maintenance timed out") + + def get_result(self, host): + super(AnsibleCloudStackHost, self).get_result(host) + if host: + self.result['allocation_state'] = host['resourcestate'].lower() + self.result['host_tags'] = host['hosttags'].split(',') if host.get('hosttags') else [] + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True, aliases=['ip_address']), + url=dict(), + password=dict(no_log=True), + username=dict(), + hypervisor=dict(), + allocation_state=dict(choices=['enabled', 'disabled', 'maintenance']), + pod=dict(), + cluster=dict(), + host_tags=dict(type='list', elements='str', aliases=['host_tag']), + zone=dict(), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_host = AnsibleCloudStackHost(module) + + state = module.params.get('state') + if state == 'absent': + host = acs_host.absent_host() + else: + host = acs_host.present_host() + + result = acs_host.get_result(host) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py new file mode 100644 index 00000000..b97d6e26 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_image_store.py @@ -0,0 +1,246 @@ +#!/usr/bin/python + +# Copyright: (c) 2019, Patryk Cichy @PatTheSilent +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_image_store + +short_description: Manages CloudStack Image Stores. + + +description: + - Deploy, remove, recreate CloudStack Image Stores. + +version_added: 0.1.0 +options: + url: + description: + - The URL for the Image Store. + - Required when I(state=present). + type: str + name: + description: + - The ID of the Image Store. Required when deleting a Image Store. + required: true + type: str + zone: + description: + - The Zone name for the Image Store. + required: true + type: str + state: + description: + - Stage of the Image Store + choices: [present, absent] + default: present + type: str + provider: + description: + - The image store provider name. Required when creating a new Image Store + type: str + force_recreate: + description: + - Set to C(yes) if you're changing an existing Image Store. + - This will force the recreation of the Image Store. + - Recreation might fail if there are snapshots present on the Image Store. Delete them before running the recreation. + type: bool + default: no + +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack + + +author: + - Patryk Cichy (@PatTheSilent) +''' + +EXAMPLES = ''' +- name: Add a Image Store (NFS) + ngine_io.cloudstack.cs_image_store: + zone: zone-01 + name: nfs-01 + provider: NFS + url: nfs://192.168.21.16/exports/secondary + + +# Change the NFS share URL and force a Image Store recreation +- name: Change the NFS url + ngine_io.cloudstack.cs_image_store: + zone: zone-01 + name: nfs-01 + provider: NFS + force_recreate: yes + url: nfs://192.168.21.10/shares/secondary + +- name: delete the image store + ngine_io.cloudstack.cs_image_store: + name: nfs-01 + zone: zone-01 + state: absent + +''' + +RETURN = ''' +id: + description: the ID of the image store + type: str + returned: success + sample: feb11a84-a093-45eb-b84d-7f680313c40b +name: + description: the name of the image store + type: str + returned: success + sample: nfs-01 +protocol: + description: the protocol of the image store + type: str + returned: success + sample: nfs +provider_name: + description: the provider name of the image store + type: str + returned: success + sample: NFS +scope: + description: the scope of the image store + type: str + returned: success + sample: ZONE +url: + description: the url of the image store + type: str + sample: nfs://192.168.21.16/exports/secondary + returned: success +zone: + description: the Zone name of the image store + type: str + returned: success + sample: zone-01 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together + + +class AnsibleCloudstackImageStore(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudstackImageStore, self).__init__(module) + self.returns = { + 'protocol': 'protocol', + 'providername': 'provider_name', + 'scope': 'scope', + 'url': 'url' + } + self.image_store = None + + def get_storage_providers(self, storage_type="image"): + args = { + 'type': storage_type + } + storage_provides = self.query_api('listStorageProviders', **args) + return [provider.get('name') for provider in storage_provides.get('dataStoreProvider')] + + def get_image_store(self): + if self.image_store: + return self.image_store + image_store = self.module.params.get('name') + args = { + 'name': self.module.params.get('name'), + 'zoneid': self.get_zone(key='id') + } + + image_stores = self.query_api('listImageStores', **args) + if image_stores: + for img_s in image_stores.get('imagestore'): + if image_store.lower() in [img_s['name'].lower(), img_s['id']]: + self.image_store = img_s + break + + return self.image_store + + def present_image_store(self): + provider_list = self.get_storage_providers() + image_store = self.get_image_store() + + if self.module.params.get('provider') not in provider_list: + self.module.fail_json( + msg='Provider %s is not in the provider list (%s). Please specify a correct provider' % ( + self.module.params.get('provider'), provider_list)) + args = { + 'name': self.module.params.get('name'), + 'url': self.module.params.get('url'), + 'zoneid': self.get_zone(key='id'), + 'provider': self.module.params.get('provider') + } + if not image_store: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('addImageStore', **args) + self.image_store = res.get('imagestore') + else: + # Cloudstack API expects 'provider' but returns 'providername' + args['providername'] = args.pop('provider') + if self.has_changed(args, image_store): + if self.module.params.get('force_recreate'): + self.absent_image_store() + self.image_store = None + self.image_store = self.present_image_store() + else: + self.module.warn("Changes to the Image Store won't be applied" + "Use force_recreate=yes to allow the store to be recreated") + + return self.image_store + + def absent_image_store(self): + image_store = self.get_image_store() + if image_store: + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'id': image_store.get('id') + } + self.query_api('deleteImageStore', **args) + return image_store + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + url=dict(), + name=dict(required=True), + zone=dict(required=True), + provider=dict(), + force_recreate=dict(type='bool', default=False), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + required_if=[ + ('state', 'present', ['url', 'provider']), + ], + supports_check_mode=True + ) + + acis_do = AnsibleCloudstackImageStore(module) + + state = module.params.get('state') + if state == "absent": + image_store = acis_do.absent_image_store() + else: + image_store = acis_do.present_image_store() + + result = acis_do.get_result(image_store) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py new file mode 100644 index 00000000..97a0ef93 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance.py @@ -0,0 +1,1101 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instance +short_description: Manages instances and virtual machines on Apache CloudStack based clouds. +description: + - Deploy, start, update, scale, restart, restore, stop and destroy instances. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Host name of the instance. C(name) can only contain ASCII letters. + - Name will be generated (UUID) by CloudStack if not specified and can not be changed afterwards. + - Either C(name) or C(display_name) is required. + type: str + display_name: + description: + - Custom display name of the instances. + - Display name will be set to I(name) if not specified. + - Either I(name) or I(display_name) is required. + type: str + group: + description: + - Group in where the new instance should be in. + type: str + state: + description: + - State of the instance. + type: str + default: present + choices: [ deployed, started, stopped, restarted, restored, destroyed, expunged, present, absent ] + service_offering: + description: + - Name or id of the service offering of the new instance. + - If not set, first found service offering is used. + type: str + cpu: + description: + - The number of CPUs to allocate to the instance, used with custom service offerings + type: int + cpu_speed: + description: + - The clock speed/shares allocated to the instance, used with custom service offerings + type: int + memory: + description: + - The memory allocated to the instance, used with custom service offerings + type: int + template: + description: + - Name, display text or id of the template to be used for creating the new instance. + - Required when using I(state=present). + - Mutually exclusive with I(iso) option. + type: str + iso: + description: + - Name or id of the ISO to be used for creating the new instance. + - Required when using I(state=present). + - Mutually exclusive with I(template) option. + type: str + template_filter: + description: + - Name of the filter used to search for the template or iso. + - Used for params I(iso) or I(template) on I(state=present). + - The filter C(all) was added in 2.6. + type: str + default: executable + choices: [ all, featured, self, selfexecutable, sharedexecutable, executable, community ] + aliases: [ iso_filter ] + hypervisor: + description: + - Name the hypervisor to be used for creating the new instance. + - Relevant when using I(state=present), but only considered if not set on ISO/template. + - If not set or found on ISO/template, first found hypervisor will be used. + - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator). + type: str + keyboard: + description: + - Keyboard device type for the instance. + type: str + choices: [ 'de', 'de-ch', 'es', 'fi', 'fr', 'fr-be', 'fr-ch', 'is', 'it', 'jp', 'nl-be', 'no', 'pt', 'uk', 'us' ] + networks: + description: + - List of networks to use for the new instance. + type: list + elements: str + aliases: [ network ] + ip_address: + description: + - IPv4 address for default instance's network during creation. + type: str + ip6_address: + description: + - IPv6 address for default instance's network. + type: str + ip_to_networks: + description: + - "List of mappings in the form I({'network': NetworkName, 'ip': 1.2.3.4})" + - Mutually exclusive with I(networks) option. + type: list + elements: dict + aliases: [ ip_to_network ] + disk_offering: + description: + - Name of the disk offering to be used. + type: str + disk_size: + description: + - Disk size in GByte required if deploying instance from ISO. + type: int + root_disk_size: + description: + - Root disk size in GByte required if deploying instance with KVM hypervisor and want resize the root disk size at startup + (need CloudStack >= 4.4, cloud-initramfs-growroot installed and enabled in the template) + type: int + security_groups: + description: + - List of security groups the instance to be applied to. + type: list + elements: str + aliases: [ security_group ] + host: + description: + - Host on which an instance should be deployed or started on. + - Only considered when I(state=started) or instance is running. + - Requires root admin privileges. + type: str + domain: + description: + - Domain the instance is related to. + type: str + account: + description: + - Account the instance is related to. + type: str + project: + description: + - Name of the project the instance to be deployed in. + type: str + zone: + description: + - Name of the zone in which the instance should be deployed. + - If not set, default zone is used. + type: str + ssh_key: + description: + - Name of the SSH key to be deployed on the new instance. + type: str + affinity_groups: + description: + - Affinity groups names to be applied to the new instance. + type: list + elements: str + aliases: [ affinity_group ] + user_data: + description: + - Optional data (ASCII) that can be sent to the instance upon a successful deployment. + - The data will be automatically base64 encoded. + - Consider switching to HTTP_POST by using I(CLOUDSTACK_METHOD=post) to increase the HTTP_GET size limit of 2KB to 32 KB. + type: str + force: + description: + - Force stop/start the instance if required to apply changes, otherwise a running instance will not be changed. + type: bool + default: no + allow_root_disk_shrink: + description: + - Enables a volume shrinkage when the new size is smaller than the old one. + type: bool + default: no + tags: + description: + - List of tags. Tags are a list of dictionaries having keys C(key) and C(value). + - "If you want to delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes + details: + description: + - Map to specify custom parameters. + type: dict +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +# NOTE: Names of offerings and ISOs depending on the CloudStack configuration. +- name: create a instance from an ISO + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + iso: Linux Debian 7 64-bit + hypervisor: VMware + project: Integration + zone: ch-zrh-ix-01 + service_offering: 1cpu_1gb + disk_offering: PerfPlus Storage + disk_size: 20 + networks: + - Server Integration + - Sync Integration + - Storage Integration + +- name: for changing a running instance, use the 'force' parameter + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + display_name: web-vm-01.example.com + iso: Linux Debian 7 64-bit + service_offering: 2cpu_2gb + force: yes + +# NOTE: user_data can be used to kickstart the instance using cloud-init yaml config. +- name: create or update a instance on Exoscale's public cloud using display_name. + ngine_io.cloudstack.cs_instance: + display_name: web-vm-1 + template: Linux Debian 7 64-bit + service_offering: Tiny + ssh_key: john@example.com + tags: + - key: admin + value: john + - key: foo + value: bar + user_data: | + #cloud-config + packages: + - nginx + +- name: create an instance with multiple interfaces specifying the IP addresses + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + template: Linux Debian 7 64-bit + service_offering: Tiny + ip_to_networks: + - network: NetworkA + ip: 10.1.1.1 + - network: NetworkB + ip: 192.0.2.1 + +- name: ensure an instance is stopped + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + state: stopped + +- name: ensure an instance is running + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + state: started + +- name: remove an instance + ngine_io.cloudstack.cs_instance: + name: web-vm-1 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the instance. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the instance. + returned: success + type: str + sample: web-01 +display_name: + description: Display name of the instance. + returned: success + type: str + sample: web-01 +group: + description: Group name of the instance is related. + returned: success + type: str + sample: web +created: + description: Date of the instance was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +password_enabled: + description: True if password setting is enabled. + returned: success + type: bool + sample: true +password: + description: The password of the instance if exists. + returned: if available + type: str + sample: Ge2oe7Do +ssh_key: + description: Name of SSH key deployed to instance. + returned: if available + type: str + sample: key@work +domain: + description: Domain the instance is related to. + returned: success + type: str + sample: example domain +account: + description: Account the instance is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the instance is related to. + returned: success + type: str + sample: Production +default_ip: + description: Default IP address of the instance. + returned: success + type: str + sample: 10.23.37.42 +default_ip6: + description: Default IPv6 address of the instance. + returned: if available + type: str + sample: 2a04:c43:c00:a07:4b4:beff:fe00:74 +public_ip: + description: Public IP address with instance via static NAT rule. + returned: if available + type: str + sample: 1.2.3.4 +iso: + description: Name of ISO the instance was deployed with. + returned: if available + type: str + sample: Debian-8-64bit +template: + description: Name of template the instance was deployed with. + returned: success + type: str + sample: Linux Debian 9 64-bit +template_display_text: + description: Display text of template the instance was deployed with. + returned: success + type: str + sample: Linux Debian 9 64-bit 200G Disk (2017-10-08-622866) +service_offering: + description: Name of the service offering the instance has. + returned: success + type: str + sample: 2cpu_2gb +zone: + description: Name of zone the instance is in. + returned: success + type: str + sample: ch-gva-2 +state: + description: State of the instance. + returned: success + type: str + sample: Running +security_groups: + description: Security groups the instance is in. + returned: success + type: list + sample: '[ "default" ]' +affinity_groups: + description: Affinity groups the instance is in. + returned: success + type: list + sample: '[ "webservers" ]' +tags: + description: List of resource tags associated with the instance. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +hypervisor: + description: Hypervisor related to this instance. + returned: success + type: str + sample: KVM +host: + description: Hostname of hypervisor an instance is running on. + returned: success and instance is running + type: str + sample: host-01.example.com +instance_name: + description: Internal name of the instance (ROOT admin only). + returned: success + type: str + sample: i-44-3992-VM +user-data: + description: Optional data sent to the instance. + returned: success + type: str + sample: VXNlciBkYXRhIGV4YW1wbGUK +''' + +import base64 +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_bytes, to_text +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackInstance(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackInstance, self).__init__(module) + self.returns = { + 'group': 'group', + 'hypervisor': 'hypervisor', + 'instancename': 'instance_name', + 'publicip': 'public_ip', + 'passwordenabled': 'password_enabled', + 'password': 'password', + 'serviceofferingname': 'service_offering', + 'isoname': 'iso', + 'templatename': 'template', + 'templatedisplaytext': 'template_display_text', + 'keypair': 'ssh_key', + 'hostname': 'host', + } + self.instance = None + self.template = None + self.iso = None + + def get_service_offering_id(self): + service_offering = self.module.params.get('service_offering') + + service_offerings = self.query_api('listServiceOfferings') + if service_offerings: + if not service_offering: + return service_offerings['serviceoffering'][0]['id'] + + for s in service_offerings['serviceoffering']: + if service_offering in [s['name'], s['id']]: + return s['id'] + self.fail_json(msg="Service offering '%s' not found" % service_offering) + + def get_host_id(self): + host_name = self.module.params.get('host') + if not host_name: + return None + + args = { + 'type': 'routing', + 'zoneid': self.get_zone(key='id'), + } + hosts = self.query_api('listHosts', **args) + if hosts: + for h in hosts['host']: + if h['name'] == host_name: + return h['id'] + + self.fail_json(msg="Host '%s' not found" % host_name) + + def get_template_or_iso(self, key=None): + template = self.module.params.get('template') + iso = self.module.params.get('iso') + + if not template and not iso: + return None + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'isrecursive': True, + 'fetch_list': True, + } + + if template: + if self.template: + return self._get_by_key(key, self.template) + + rootdisksize = self.module.params.get('root_disk_size') + args['templatefilter'] = self.module.params.get('template_filter') + args['fetch_list'] = True + templates = self.query_api('listTemplates', **args) + if templates: + for t in templates: + if template in [t.get('displaytext', None), t['name'], t['id']]: + if rootdisksize and t['size'] > rootdisksize * 1024 ** 3: + continue + self.template = t + return self._get_by_key(key, self.template) + + if rootdisksize: + more_info = " (with size <= %s)" % rootdisksize + else: + more_info = "" + + self.module.fail_json(msg="Template '%s' not found%s" % (template, more_info)) + + elif iso: + if self.iso: + return self._get_by_key(key, self.iso) + + args['isofilter'] = self.module.params.get('template_filter') + args['fetch_list'] = True + isos = self.query_api('listIsos', **args) + if isos: + for i in isos: + if iso in [i['displaytext'], i['name'], i['id']]: + self.iso = i + return self._get_by_key(key, self.iso) + + self.module.fail_json(msg="ISO '%s' not found" % iso) + + def get_instance(self): + instance = self.instance + if not instance: + instance_name = self.get_or_fallback('name', 'display_name') + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'fetch_list': True, + } + # Do not pass zoneid, as the instance name must be unique across zones. + instances = self.query_api('listVirtualMachines', **args) + if instances: + for v in instances: + if instance_name.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]: + self.instance = v + break + return self.instance + + def _get_instance_user_data(self, instance): + # Query the user data if we need to + if 'userdata' in instance: + return instance['userdata'] + + user_data = "" + if self.get_user_data() is not None and instance.get('id'): + res = self.query_api('getVirtualMachineUserData', virtualmachineid=instance['id']) + user_data = res['virtualmachineuserdata'].get('userdata', "") + return user_data + + def get_iptonetwork_mappings(self): + network_mappings = self.module.params.get('ip_to_networks') + if network_mappings is None: + return + + if network_mappings and self.module.params.get('networks'): + self.module.fail_json(msg="networks and ip_to_networks are mutually exclusive.") + + network_names = [n['network'] for n in network_mappings] + ids = self.get_network_ids(network_names) + res = [] + for i, data in enumerate(network_mappings): + res.append({'networkid': ids[i], 'ip': data['ip']}) + return res + + def get_ssh_keypair(self, key=None, name=None, fail_on_missing=True): + ssh_key_name = name or self.module.params.get('ssh_key') + if ssh_key_name is None: + return + + args = { + 'domainid': self.get_domain('id'), + 'account': self.get_account('name'), + 'projectid': self.get_project('id'), + 'name': ssh_key_name, + } + ssh_key_pairs = self.query_api('listSSHKeyPairs', **args) + if 'sshkeypair' in ssh_key_pairs: + return self._get_by_key(key=key, my_dict=ssh_key_pairs['sshkeypair'][0]) + + elif fail_on_missing: + self.module.fail_json(msg="SSH key not found: %s" % ssh_key_name) + + def ssh_key_has_changed(self): + ssh_key_name = self.module.params.get('ssh_key') + if ssh_key_name is None: + return False + + # Fails if keypair for param is inexistent + param_ssh_key_fp = self.get_ssh_keypair(key='fingerprint') + + # CloudStack 4.5 does return keypair on instance for a non existent key. + instance_ssh_key_name = self.instance.get('keypair') + if instance_ssh_key_name is None: + return True + + # Get fingerprint for keypair of instance but do not fail if inexistent. + instance_ssh_key_fp = self.get_ssh_keypair(key='fingerprint', name=instance_ssh_key_name, fail_on_missing=False) + if not instance_ssh_key_fp: + return True + + # Compare fingerprints to ensure the keypair changed + if instance_ssh_key_fp != param_ssh_key_fp: + return True + return False + + def security_groups_has_changed(self): + security_groups = self.module.params.get('security_groups') + if security_groups is None: + return False + + security_groups = [s.lower() for s in security_groups] + instance_security_groups = self.instance.get('securitygroup') or [] + + instance_security_group_names = [] + for instance_security_group in instance_security_groups: + if instance_security_group['name'].lower() not in security_groups: + return True + else: + instance_security_group_names.append(instance_security_group['name'].lower()) + + for security_group in security_groups: + if security_group not in instance_security_group_names: + return True + return False + + def get_network_ids(self, network_names=None): + if network_names is None: + network_names = self.module.params.get('networks') + + if not network_names: + return None + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'fetch_list': True, + } + networks = self.query_api('listNetworks', **args) + if not networks: + self.module.fail_json(msg="No networks available") + + network_ids = [] + network_displaytexts = [] + for network_name in network_names: + for n in networks: + if network_name in [n['displaytext'], n['name'], n['id']]: + network_ids.append(n['id']) + network_displaytexts.append(n['name']) + break + + if len(network_ids) != len(network_names): + self.module.fail_json(msg="Could not find all networks, networks list found: %s" % network_displaytexts) + + return network_ids + + def present_instance(self, start_vm=True): + instance = self.get_instance() + + if not instance: + instance = self.deploy_instance(start_vm=start_vm) + else: + instance = self.recover_instance(instance=instance) + instance = self.update_instance(instance=instance, start_vm=start_vm) + + # In check mode, we do not necessarily have an instance + if instance: + instance = self.ensure_tags(resource=instance, resource_type='UserVm') + # refresh instance data + self.instance = instance + + return instance + + def get_user_data(self): + user_data = self.module.params.get('user_data') + if user_data is not None: + user_data = to_text(base64.b64encode(to_bytes(user_data))) + return user_data + + def get_details(self): + details = self.module.params.get('details') + cpu = self.module.params.get('cpu') + cpu_speed = self.module.params.get('cpu_speed') + memory = self.module.params.get('memory') + if all([cpu, cpu_speed, memory]): + details.extends({ + 'cpuNumber': cpu, + 'cpuSpeed': cpu_speed, + 'memory': memory, + }) + + return details + + def deploy_instance(self, start_vm=True): + self.result['changed'] = True + networkids = self.get_network_ids() + if networkids is not None: + networkids = ','.join(networkids) + + args = {} + args['templateid'] = self.get_template_or_iso(key='id') + if not args['templateid']: + self.module.fail_json(msg="Template or ISO is required.") + + args['zoneid'] = self.get_zone(key='id') + args['serviceofferingid'] = self.get_service_offering_id() + args['account'] = self.get_account(key='name') + args['domainid'] = self.get_domain(key='id') + args['projectid'] = self.get_project(key='id') + args['diskofferingid'] = self.get_disk_offering(key='id') + args['networkids'] = networkids + args['iptonetworklist'] = self.get_iptonetwork_mappings() + args['userdata'] = self.get_user_data() + args['keyboard'] = self.module.params.get('keyboard') + args['ipaddress'] = self.module.params.get('ip_address') + args['ip6address'] = self.module.params.get('ip6_address') + args['name'] = self.module.params.get('name') + args['displayname'] = self.get_or_fallback('display_name', 'name') + args['group'] = self.module.params.get('group') + args['keypair'] = self.get_ssh_keypair(key='name') + args['size'] = self.module.params.get('disk_size') + args['startvm'] = start_vm + args['rootdisksize'] = self.module.params.get('root_disk_size') + args['affinitygroupnames'] = self.module.params.get('affinity_groups') + args['details'] = self.get_details() + args['securitygroupnames'] = self.module.params.get('security_groups') + args['hostid'] = self.get_host_id() + + template_iso = self.get_template_or_iso() + if 'hypervisor' not in template_iso: + args['hypervisor'] = self.get_hypervisor() + + instance = None + if not self.module.check_mode: + instance = self.query_api('deployVirtualMachine', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(instance, 'virtualmachine') + return instance + + def update_instance(self, instance, start_vm=True): + # Service offering data + args_service_offering = { + 'id': instance['id'], + } + if self.module.params.get('service_offering'): + args_service_offering['serviceofferingid'] = self.get_service_offering_id() + service_offering_changed = self.has_changed(args_service_offering, instance) + + # Instance data + args_instance_update = { + 'id': instance['id'], + 'userdata': self.get_user_data(), + } + instance['userdata'] = self._get_instance_user_data(instance) + args_instance_update['ostypeid'] = self.get_os_type(key='id') + if self.module.params.get('group'): + args_instance_update['group'] = self.module.params.get('group') + if self.module.params.get('display_name'): + args_instance_update['displayname'] = self.module.params.get('display_name') + instance_changed = self.has_changed(args_instance_update, instance) + + ssh_key_changed = self.ssh_key_has_changed() + + security_groups_changed = self.security_groups_has_changed() + + # Volume data + args_volume_update = {} + root_disk_size = self.module.params.get('root_disk_size') + root_disk_size_changed = False + + if root_disk_size is not None: + res = self.query_api('listVolumes', type='ROOT', virtualmachineid=instance['id']) + [volume] = res['volume'] + + size = volume['size'] >> 30 + + args_volume_update['id'] = volume['id'] + args_volume_update['size'] = root_disk_size + + shrinkok = self.module.params.get('allow_root_disk_shrink') + if shrinkok: + args_volume_update['shrinkok'] = shrinkok + + root_disk_size_changed = root_disk_size != size + + changed = [ + service_offering_changed, + instance_changed, + security_groups_changed, + ssh_key_changed, + root_disk_size_changed, + ] + + if any(changed): + force = self.module.params.get('force') + instance_state = instance['state'].lower() + if instance_state == 'stopped' or force: + self.result['changed'] = True + if not self.module.check_mode: + + # Ensure VM has stopped + instance = self.stop_instance() + instance = self.poll_job(instance, 'virtualmachine') + self.instance = instance + + # Change service offering + if service_offering_changed: + res = self.query_api('changeServiceForVirtualMachine', **args_service_offering) + instance = res['virtualmachine'] + self.instance = instance + + # Update VM + if instance_changed or security_groups_changed: + if security_groups_changed: + args_instance_update['securitygroupnames'] = ','.join(self.module.params.get('security_groups')) + res = self.query_api('updateVirtualMachine', **args_instance_update) + instance = res['virtualmachine'] + self.instance = instance + + # Reset SSH key + if ssh_key_changed: + # SSH key data + args_ssh_key = {} + args_ssh_key['id'] = instance['id'] + args_ssh_key['projectid'] = self.get_project(key='id') + args_ssh_key['keypair'] = self.module.params.get('ssh_key') + instance = self.query_api('resetSSHKeyForVirtualMachine', **args_ssh_key) + instance = self.poll_job(instance, 'virtualmachine') + self.instance = instance + + # Root disk size + if root_disk_size_changed: + async_result = self.query_api('resizeVolume', **args_volume_update) + self.poll_job(async_result, 'volume') + + # Start VM again if it was running before + if instance_state == 'running' and start_vm: + instance = self.start_instance() + else: + self.module.warn("Changes won't be applied to running instances. " + "Use force=true to allow the instance %s to be stopped/started." % instance['name']) + + # migrate to other host + host_changed = all([ + instance['state'].lower() in ['starting', 'running'], + instance.get('hostname') is not None, + self.module.params.get('host') is not None, + self.module.params.get('host') != instance.get('hostname') + ]) + if host_changed: + self.result['changed'] = True + args_host = { + 'virtualmachineid': instance['id'], + 'hostid': self.get_host_id(), + } + if not self.module.check_mode: + res = self.query_api('migrateVirtualMachine', **args_host) + instance = self.poll_job(res, 'virtualmachine') + + return instance + + def recover_instance(self, instance): + if instance['state'].lower() in ['destroying', 'destroyed']: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('recoverVirtualMachine', id=instance['id']) + instance = res['virtualmachine'] + return instance + + def absent_instance(self): + instance = self.get_instance() + if instance: + if instance['state'].lower() not in ['expunging', 'destroying', 'destroyed']: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('destroyVirtualMachine', id=instance['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(res, 'virtualmachine') + return instance + + def expunge_instance(self): + instance = self.get_instance() + if instance: + res = {} + if instance['state'].lower() in ['destroying', 'destroyed']: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('destroyVirtualMachine', id=instance['id'], expunge=True) + + elif instance['state'].lower() not in ['expunging']: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('destroyVirtualMachine', id=instance['id'], expunge=True) + + poll_async = self.module.params.get('poll_async') + if poll_async: + res = self.poll_job(res, 'virtualmachine') + return instance + + def stop_instance(self): + instance = self.get_instance() + # in check mode instance may not be instantiated + if instance: + if instance['state'].lower() in ['stopping', 'stopped']: + return instance + + if instance['state'].lower() in ['starting', 'running']: + self.result['changed'] = True + if not self.module.check_mode: + instance = self.query_api('stopVirtualMachine', id=instance['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(instance, 'virtualmachine') + return instance + + def start_instance(self): + instance = self.get_instance() + # in check mode instance may not be instantiated + if instance: + if instance['state'].lower() in ['starting', 'running']: + return instance + + if instance['state'].lower() in ['stopped', 'stopping']: + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'id': instance['id'], + 'hostid': self.get_host_id(), + } + instance = self.query_api('startVirtualMachine', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(instance, 'virtualmachine') + return instance + + def restart_instance(self): + instance = self.get_instance() + # in check mode instance may not be instantiated + if instance: + if instance['state'].lower() in ['running', 'starting']: + self.result['changed'] = True + if not self.module.check_mode: + instance = self.query_api('rebootVirtualMachine', id=instance['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(instance, 'virtualmachine') + + elif instance['state'].lower() in ['stopping', 'stopped']: + instance = self.start_instance() + return instance + + def restore_instance(self): + instance = self.get_instance() + self.result['changed'] = True + # in check mode instance may not be instantiated + if instance: + args = {} + args['templateid'] = self.get_template_or_iso(key='id') + args['virtualmachineid'] = instance['id'] + res = self.query_api('restoreVirtualMachine', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + instance = self.poll_job(res, 'virtualmachine') + return instance + + def get_result(self, instance): + super(AnsibleCloudStackInstance, self).get_result(instance) + if instance: + self.result['user_data'] = self._get_instance_user_data(instance) + if 'securitygroup' in instance: + security_groups = [] + for securitygroup in instance['securitygroup']: + security_groups.append(securitygroup['name']) + self.result['security_groups'] = security_groups + if 'affinitygroup' in instance: + affinity_groups = [] + for affinitygroup in instance['affinitygroup']: + affinity_groups.append(affinitygroup['name']) + self.result['affinity_groups'] = affinity_groups + if 'nic' in instance: + for nic in instance['nic']: + if nic['isdefault']: + if 'ipaddress' in nic: + self.result['default_ip'] = nic['ipaddress'] + if 'ip6address' in nic: + self.result['default_ip6'] = nic['ip6address'] + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(), + display_name=dict(), + group=dict(), + state=dict(choices=['present', 'deployed', 'started', 'stopped', 'restarted', 'restored', 'absent', 'destroyed', 'expunged'], default='present'), + service_offering=dict(), + cpu=dict(type='int'), + cpu_speed=dict(type='int'), + memory=dict(type='int'), + template=dict(), + iso=dict(), + template_filter=dict( + default="executable", + aliases=['iso_filter'], + choices=['all', 'featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community'] + ), + networks=dict(type='list', elements='str', aliases=['network']), + ip_to_networks=dict(type='list', elements='dict', aliases=['ip_to_network']), + ip_address=dict(), + ip6_address=dict(), + disk_offering=dict(), + disk_size=dict(type='int'), + root_disk_size=dict(type='int'), + keyboard=dict(type='str', choices=['de', 'de-ch', 'es', 'fi', 'fr', 'fr-be', 'fr-ch', 'is', 'it', 'jp', 'nl-be', 'no', 'pt', 'uk', 'us']), + hypervisor=dict(), + host=dict(), + security_groups=dict(type='list', elements='str', aliases=['security_group']), + affinity_groups=dict(type='list', elements='str', aliases=['affinity_group']), + domain=dict(), + account=dict(), + project=dict(), + user_data=dict(), + zone=dict(), + ssh_key=dict(), + force=dict(type='bool', default=False), + tags=dict(type='list', elements='dict', aliases=['tag']), + details=dict(type='dict'), + poll_async=dict(type='bool', default=True), + allow_root_disk_shrink=dict(type='bool', default=False), + )) + + required_together = cs_required_together() + required_together.extend([ + ['cpu', 'cpu_speed', 'memory'], + ]) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=required_together, + required_one_of=( + ['display_name', 'name'], + ), + mutually_exclusive=( + ['template', 'iso'], + ), + supports_check_mode=True + ) + + acs_instance = AnsibleCloudStackInstance(module) + + state = module.params.get('state') + + if state in ['absent', 'destroyed']: + instance = acs_instance.absent_instance() + + elif state in ['expunged']: + instance = acs_instance.expunge_instance() + + elif state in ['restored']: + acs_instance.present_instance() + instance = acs_instance.restore_instance() + + elif state in ['present', 'deployed']: + instance = acs_instance.present_instance() + + elif state in ['stopped']: + acs_instance.present_instance(start_vm=False) + instance = acs_instance.stop_instance() + + elif state in ['started']: + acs_instance.present_instance() + instance = acs_instance.start_instance() + + elif state in ['restarted']: + acs_instance.present_instance() + instance = acs_instance.restart_instance() + + if instance and 'state' in instance and instance['state'].lower() == 'error': + module.fail_json(msg="Instance named '%s' in error state." % module.params.get('name')) + + result = acs_instance.get_result(instance) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py new file mode 100644 index 00000000..5b111bec --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_info.py @@ -0,0 +1,370 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instance_info +short_description: Gathering information from the API of instances from Apache CloudStack based clouds. +description: + - Gathering information from the API of an instance. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name or display name of the instance. + - If not specified, all instances are returned + type: str + required: false + domain: + description: + - Domain the instance is related to. + type: str + account: + description: + - Account the instance is related to. + type: str + project: + description: + - Project the instance is related to. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Gather instance information + ngine_io.cloudstack.cs_instance_info: + name: web-vm-1 + register: vm + +- name: Show the returned results of the registered variable + debug: + msg: "{{ vm }}" + +- name: Gather information from all instances + ngine_io.cloudstack.cs_instance_info: + register: vms + +- name: Show information on all instances + debug: + msg: "{{ vms }}" +''' + +RETURN = ''' +--- +instances: + description: A list of matching instances. + type: list + returned: success + contains: + id: + description: UUID of the instance. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 + name: + description: Name of the instance. + returned: success + type: str + sample: web-01 + display_name: + description: Display name of the instance. + returned: success + type: str + sample: web-01 + group: + description: Group name of the instance is related. + returned: success + type: str + sample: web + created: + description: Date of the instance was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 + password_enabled: + description: True if password setting is enabled. + returned: success + type: bool + sample: true + password: + description: The password of the instance if exists. + returned: success + type: str + sample: Ge2oe7Do + ssh_key: + description: Name of SSH key deployed to instance. + returned: success + type: str + sample: key@work + domain: + description: Domain the instance is related to. + returned: success + type: str + sample: example domain + account: + description: Account the instance is related to. + returned: success + type: str + sample: example account + project: + description: Name of project the instance is related to. + returned: success + type: str + sample: Production + default_ip: + description: Default IP address of the instance. + returned: success + type: str + sample: 10.23.37.42 + public_ip: + description: Public IP address with instance via static NAT rule. + returned: success + type: str + sample: 1.2.3.4 + iso: + description: Name of ISO the instance was deployed with. + returned: success + type: str + sample: Debian-8-64bit + template: + description: Name of template the instance was deployed with. + returned: success + type: str + sample: Debian-8-64bit + service_offering: + description: Name of the service offering the instance has. + returned: success + type: str + sample: 2cpu_2gb + zone: + description: Name of zone the instance is in. + returned: success + type: str + sample: ch-gva-2 + state: + description: State of the instance. + returned: success + type: str + sample: Running + security_groups: + description: Security groups the instance is in. + returned: success + type: list + sample: '[ "default" ]' + affinity_groups: + description: Affinity groups the instance is in. + returned: success + type: list + sample: '[ "webservers" ]' + tags: + description: List of resource tags associated with the instance. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' + hypervisor: + description: Hypervisor related to this instance. + returned: success + type: str + sample: KVM + host: + description: Host the instance is running on. + returned: success and instance is running + type: str + sample: host01.example.com + instance_name: + description: Internal name of the instance (ROOT admin only). + returned: success + type: str + sample: i-44-3992-VM + volumes: + description: List of dictionaries of the volumes attached to the instance. + returned: success + type: list + sample: '[ { name: "ROOT-1369", type: "ROOT", size: 10737418240 }, { name: "data01, type: "DATADISK", size: 10737418240 } ]' + nic: + description: List of dictionaries of the instance nics. + returned: success + type: complex + contains: + broadcasturi: + description: The broadcast uri of the nic. + returned: success + type: str + sample: vlan://2250 + gateway: + description: The gateway of the nic. + returned: success + type: str + sample: 10.1.2.1 + id: + description: The ID of the nic. + returned: success + type: str + sample: 5dc74fa3-2ec3-48a0-9e0d-6f43365336a9 + ipaddress: + description: The ip address of the nic. + returned: success + type: str + sample: 10.1.2.3 + isdefault: + description: True if nic is default, false otherwise. + returned: success + type: bool + sample: true + isolationuri: + description: The isolation uri of the nic. + returned: success + type: str + sample: vlan://2250 + macaddress: + description: The mac address of the nic. + returned: success + type: str + sample: 06:a2:03:00:08:12 + netmask: + description: The netmask of the nic. + returned: success + type: str + sample: 255.255.255.0 + networkid: + description: The ID of the corresponding network. + returned: success + type: str + sample: 432ce27b-c2bb-4e12-a88c-a919cd3a3017 + networkname: + description: The name of the corresponding network. + returned: success + type: str + sample: network1 + traffictype: + description: The traffic type of the nic. + returned: success + type: str + sample: Guest + type: + description: The type of the network. + returned: success + type: str + sample: Shared +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec + + +class AnsibleCloudStackInstanceInfo(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackInstanceInfo, self).__init__(module) + self.returns = { + 'group': 'group', + 'hypervisor': 'hypervisor', + 'instancename': 'instance_name', + 'publicip': 'public_ip', + 'passwordenabled': 'password_enabled', + 'password': 'password', + 'serviceofferingname': 'service_offering', + 'isoname': 'iso', + 'templatename': 'template', + 'keypair': 'ssh_key', + 'hostname': 'host', + } + + def get_instances(self): + instance_name = self.module.params.get('name') + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'fetch_list': True, + } + # Do not pass zoneid, as the instance name must be unique across zones. + instances = self.query_api('listVirtualMachines', **args) + if not instance_name: + return instances or [] + if instances: + for v in instances: + if instance_name.lower() in [v['name'].lower(), v['displayname'].lower(), v['id']]: + return [v] + return [] + + def get_volumes(self, instance): + volume_details = [] + if instance: + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'virtualmachineid': instance['id'], + 'fetch_list': True, + } + + volumes = self.query_api('listVolumes', **args) + if volumes: + for vol in volumes: + volume_details.append({'size': vol['size'], 'type': vol['type'], 'name': vol['name']}) + return volume_details + + def run(self): + instances = self.get_instances() + if self.module.params.get('name') and not instances: + self.module.fail_json(msg="Instance not found: %s" % self.module.params.get('name')) + return { + 'instances': [self.update_result(resource) for resource in instances] + } + + def update_result(self, instance, result=None): + result = super(AnsibleCloudStackInstanceInfo, self).update_result(instance, result) + if instance: + if 'securitygroup' in instance: + security_groups = [] + for securitygroup in instance['securitygroup']: + security_groups.append(securitygroup['name']) + result['security_groups'] = security_groups + if 'affinitygroup' in instance: + affinity_groups = [] + for affinitygroup in instance['affinitygroup']: + affinity_groups.append(affinitygroup['name']) + result['affinity_groups'] = affinity_groups + if 'nic' in instance: + for nic in instance['nic']: + if nic['isdefault'] and 'ipaddress' in nic: + result['default_ip'] = nic['ipaddress'] + result['nic'] = instance['nic'] + volumes = self.get_volumes(instance) + if volumes: + result['volumes'] = volumes + return result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(), + domain=dict(), + account=dict(), + project=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + acs_instance_info = AnsibleCloudStackInstanceInfo(module=module) + cs_instance_info = acs_instance_info.run() + module.exit_json(**cs_instance_info) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py new file mode 100644 index 00000000..11ea45fc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic.py @@ -0,0 +1,285 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, Marc-Aurèle Brothier @marcaurele +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instance_nic +short_description: Manages NICs of an instance on Apache CloudStack based clouds. +description: + - Add and remove nic to and from network +author: + - Marc-Aurèle Brothier (@marcaurele) + - René Moser (@resmo) +version_added: 0.1.0 +options: + vm: + description: + - Name of instance. + required: true + type: str + aliases: [ name ] + network: + description: + - Name of the network. + type: str + required: true + ip_address: + description: + - IP address to be used for the nic. + type: str + vpc: + description: + - Name of the VPC the I(vm) is related to. + type: str + domain: + description: + - Domain the instance is related to. + type: str + account: + description: + - Account the instance is related to. + type: str + project: + description: + - Name of the project the instance is deployed in. + type: str + zone: + description: + - Name of the zone in which the instance is deployed in. + - If not set, default zone is used. + type: str + state: + description: + - State of the nic. + type: str + default: present + choices: [ present, absent ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Add a nic on another network + ngine_io.cloudstack.cs_instance_nic: + vm: privnet + network: privNetForBasicZone + +- name: Ensure IP address on a nic + ngine_io.cloudstack.cs_instance_nic: + vm: privnet + ip_address: 10.10.11.32 + network: privNetForBasicZone + +- name: Remove a secondary nic + ngine_io.cloudstack.cs_instance_nic: + vm: privnet + state: absent + network: privNetForBasicZone +''' + +RETURN = ''' +--- +id: + description: UUID of the nic. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +vm: + description: Name of the VM. + returned: success + type: str + sample: web-01 +ip_address: + description: Primary IP of the NIC. + returned: success + type: str + sample: 10.10.10.10 +netmask: + description: Netmask of the NIC. + returned: success + type: str + sample: 255.255.255.0 +mac_address: + description: MAC address of the NIC. + returned: success + type: str + sample: 02:00:33:31:00:e4 +network: + description: Name of the network if not default. + returned: success + type: str + sample: sync network +domain: + description: Domain the VM is related to. + returned: success + type: str + sample: example domain +account: + description: Account the VM is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the VM is related to. + returned: success + type: str + sample: Production +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackInstanceNic(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackInstanceNic, self).__init__(module) + self.nic = None + self.returns = { + 'ipaddress': 'ip_address', + 'macaddress': 'mac_address', + 'netmask': 'netmask', + } + + def get_nic(self): + if self.nic: + return self.nic + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'networkid': self.get_network(key='id'), + } + nics = self.query_api('listNics', **args) + if nics: + self.nic = nics['nic'][0] + return self.nic + return None + + def get_nic_from_result(self, result): + for nic in result.get('nic') or []: + if nic['networkid'] == self.get_network(key='id'): + return nic + + def add_nic(self): + self.result['changed'] = True + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'networkid': self.get_network(key='id'), + 'ipaddress': self.module.params.get('ip_address'), + } + if not self.module.check_mode: + res = self.query_api('addNicToVirtualMachine', **args) + + if self.module.params.get('poll_async'): + vm = self.poll_job(res, 'virtualmachine') + self.nic = self.get_nic_from_result(result=vm) + return self.nic + + def update_nic(self, nic): + # Do not try to update if no IP address is given + ip_address = self.module.params.get('ip_address') + if not ip_address: + return nic + + args = { + 'nicid': nic['id'], + 'ipaddress': ip_address, + } + if self.has_changed(args, nic, ['ipaddress']): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateVmNicIp', **args) + + if self.module.params.get('poll_async'): + vm = self.poll_job(res, 'virtualmachine') + self.nic = self.get_nic_from_result(result=vm) + return self.nic + + def remove_nic(self, nic): + self.result['changed'] = True + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'nicid': nic['id'], + } + if not self.module.check_mode: + res = self.query_api('removeNicFromVirtualMachine', **args) + + if self.module.params.get('poll_async'): + self.poll_job(res, 'virtualmachine') + return nic + + def present_nic(self): + nic = self.get_nic() + if not nic: + nic = self.add_nic() + else: + nic = self.update_nic(nic) + return nic + + def absent_nic(self): + nic = self.get_nic() + if nic: + return self.remove_nic(nic) + return nic + + def get_result(self, nic): + super(AnsibleCloudStackInstanceNic, self).get_result(nic) + if nic and not self.module.params.get('network'): + self.module.params['network'] = nic.get('networkid') + self.result['network'] = self.get_network(key='name') + self.result['vm'] = self.get_vm(key='name') + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + vm=dict(required=True, aliases=['name']), + network=dict(required=True), + vpc=dict(), + ip_address=dict(), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True, + ) + + acs_nic = AnsibleCloudStackInstanceNic(module) + + state = module.params.get('state') + if state == 'absent': + nic = acs_nic.absent_nic() + else: + nic = acs_nic.present_nic() + + result = acs_nic.get_result(nic) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py new file mode 100644 index 00000000..7dabe7d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_nic_secondaryip.py @@ -0,0 +1,267 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instance_nic_secondaryip +short_description: Manages secondary IPs of an instance on Apache CloudStack based clouds. +description: + - Add and remove secondary IPs to and from a NIC of an instance. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + vm: + description: + - Name of instance. + type: str + required: true + aliases: [ name ] + network: + description: + - Name of the network. + - Required to find the NIC if instance has multiple networks assigned. + type: str + vm_guest_ip: + description: + - Secondary IP address to be added to the instance nic. + - If not set, the API always returns a new IP address and idempotency is not given. + type: str + aliases: [ secondary_ip ] + vpc: + description: + - Name of the VPC the I(vm) is related to. + type: str + domain: + description: + - Domain the instance is related to. + type: str + account: + description: + - Account the instance is related to. + type: str + project: + description: + - Name of the project the instance is deployed in. + type: str + zone: + description: + - Name of the zone in which the instance is deployed in. + - If not set, default zone is used. + type: str + state: + description: + - State of the ipaddress. + type: str + default: present + choices: [ present, absent ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack + +''' + +EXAMPLES = ''' +- name: Assign a specific IP to the default NIC of the VM + ngine_io.cloudstack.cs_instance_nic_secondaryip: + vm: customer_xy + vm_guest_ip: 10.10.10.10 + +# Note: If vm_guest_ip is not set, you will get a new IP address on every run. +- name: Assign an IP to the default NIC of the VM + ngine_io.cloudstack.cs_instance_nic_secondaryip: + vm: customer_xy + +- name: Remove a specific IP from the default NIC + ngine_io.cloudstack.cs_instance_nic_secondaryip: + vm: customer_xy + vm_guest_ip: 10.10.10.10 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the NIC. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +vm: + description: Name of the VM. + returned: success + type: str + sample: web-01 +ip_address: + description: Primary IP of the NIC. + returned: success + type: str + sample: 10.10.10.10 +netmask: + description: Netmask of the NIC. + returned: success + type: str + sample: 255.255.255.0 +mac_address: + description: MAC address of the NIC. + returned: success + type: str + sample: 02:00:33:31:00:e4 +vm_guest_ip: + description: Secondary IP of the NIC. + returned: success + type: str + sample: 10.10.10.10 +network: + description: Name of the network if not default. + returned: success + type: str + sample: sync network +domain: + description: Domain the VM is related to. + returned: success + type: str + sample: example domain +account: + description: Account the VM is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the VM is related to. + returned: success + type: str + sample: Production +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackInstanceNicSecondaryIp(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackInstanceNicSecondaryIp, self).__init__(module) + self.vm_guest_ip = self.module.params.get('vm_guest_ip') + self.nic = None + self.returns = { + 'ipaddress': 'ip_address', + 'macaddress': 'mac_address', + 'netmask': 'netmask', + } + + def get_nic(self): + if self.nic: + return self.nic + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'networkid': self.get_network(key='id'), + } + nics = self.query_api('listNics', **args) + if nics: + self.nic = nics['nic'][0] + return self.nic + self.fail_json(msg="NIC for VM %s in network %s not found" % (self.get_vm(key='name'), self.get_network(key='name'))) + + def get_secondary_ip(self): + nic = self.get_nic() + if self.vm_guest_ip: + secondary_ips = nic.get('secondaryip') or [] + for secondary_ip in secondary_ips: + if secondary_ip['ipaddress'] == self.vm_guest_ip: + return secondary_ip + return None + + def present_nic_ip(self): + nic = self.get_nic() + if not self.get_secondary_ip(): + self.result['changed'] = True + args = { + 'nicid': nic['id'], + 'ipaddress': self.vm_guest_ip, + } + + if not self.module.check_mode: + res = self.query_api('addIpToNic', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + nic = self.poll_job(res, 'nicsecondaryip') + # Save result for RETURNS + self.vm_guest_ip = nic['ipaddress'] + return nic + + def absent_nic_ip(self): + nic = self.get_nic() + secondary_ip = self.get_secondary_ip() + if secondary_ip: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('removeIpFromNic', id=secondary_ip['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'nicsecondaryip') + return nic + + def get_result(self, nic): + super(AnsibleCloudStackInstanceNicSecondaryIp, self).get_result(nic) + if nic and not self.module.params.get('network'): + self.module.params['network'] = nic.get('networkid') + self.result['network'] = self.get_network(key='name') + self.result['vm'] = self.get_vm(key='name') + self.result['vm_guest_ip'] = self.vm_guest_ip + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + vm=dict(required=True, aliases=['name']), + vm_guest_ip=dict(aliases=['secondary_ip']), + network=dict(), + vpc=dict(), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True, + required_if=([ + ('state', 'absent', ['vm_guest_ip']) + ]) + ) + + acs_instance_nic_secondaryip = AnsibleCloudStackInstanceNicSecondaryIp(module) + state = module.params.get('state') + + if state == 'absent': + nic = acs_instance_nic_secondaryip.absent_nic_ip() + else: + nic = acs_instance_nic_secondaryip.present_nic_ip() + + result = acs_instance_nic_secondaryip.get_result(nic) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py new file mode 100644 index 00000000..58b9b741 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instance_password_reset.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Gregor Riepl <onitake@gmail.com> +# based on cs_sshkeypair (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instance_password_reset +short_description: Allows resetting VM the default passwords on Apache CloudStack based clouds. +description: + - Resets the default user account's password on an instance. + - Requires cloud-init to be installed in the virtual machine. + - The passwordenabled flag must be set on the template associated with the VM. +author: Gregor Riepl (@onitake) +version_added: 0.1.0 +options: + vm: + description: + - Name of the virtual machine to reset the password on. + type: str + required: true + domain: + description: + - Name of the domain the virtual machine belongs to. + type: str + account: + description: + - Account the virtual machine belongs to. + type: str + project: + description: + - Name of the project the virtual machine belongs to. + type: str + zone: + description: + - Name of the zone in which the instance is deployed. + - If not set, the default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: stop the virtual machine before resetting the password + ngine_io.cloudstack.cs_instance: + name: myvirtualmachine + state: stopped + +- name: reset and get new default password + ngine_io.cloudstack.cs_instance_password_reset: + vm: myvirtualmachine + register: root + +- debug: + msg: "new default password is {{ root.password }}" + +- name: boot the virtual machine to activate the new password + ngine_io.cloudstack.cs_instance: + name: myvirtualmachine + state: started + when: root is changed +''' + +RETURN = ''' +--- +id: + description: ID of the virtual machine. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +password: + description: The new default password. + returned: success + type: str + sample: ahQu5nuNge3keesh +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_required_together, + cs_argument_spec +) + + +class AnsibleCloudStackPasswordReset(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackPasswordReset, self).__init__(module) + self.returns = { + 'password': 'password', + } + self.password = None + + def reset_password(self): + args = { + 'id': self.get_vm(key='id'), + } + + res = None + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('resetPasswordForVirtualMachine', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + res = self.poll_job(res, 'virtualmachine') + + if res and 'password' in res: + self.password = res['password'] + + return self.password + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + vm=dict(required=True), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_password = AnsibleCloudStackPasswordReset(module) + password = acs_password.reset_password() + result = acs_password.get_result({'password': password}) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py new file mode 100644 index 00000000..56783b2a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_instancegroup.py @@ -0,0 +1,181 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_instancegroup +short_description: Manages instance groups on Apache CloudStack based clouds. +description: + - Create and remove instance groups. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the instance group. + type: str + required: true + domain: + description: + - Domain the instance group is related to. + type: str + account: + description: + - Account the instance group is related to. + type: str + project: + description: + - Project the instance group is related to. + type: str + state: + description: + - State of the instance group. + type: str + default: present + choices: [ present, absent ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create an instance group + ngine_io.cloudstack.cs_instancegroup: + name: loadbalancers + +- name: Remove an instance group + ngine_io.cloudstack.cs_instancegroup: + name: loadbalancers + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the instance group. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the instance group. + returned: success + type: str + sample: webservers +created: + description: Date when the instance group was created. + returned: success + type: str + sample: 2015-05-03T15:05:51+0200 +domain: + description: Domain the instance group is related to. + returned: success + type: str + sample: example domain +account: + description: Account the instance group is related to. + returned: success + type: str + sample: example account +project: + description: Project the instance group is related to. + returned: success + type: str + sample: example project +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackInstanceGroup(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackInstanceGroup, self).__init__(module) + self.instance_group = None + + def get_instance_group(self): + if self.instance_group: + return self.instance_group + + name = self.module.params.get('name') + + args = { + 'account': self.get_account('name'), + 'domainid': self.get_domain('id'), + 'projectid': self.get_project('id'), + 'fetch_list': True, + } + instance_groups = self.query_api('listInstanceGroups', **args) + if instance_groups: + for g in instance_groups: + if name in [g['name'], g['id']]: + self.instance_group = g + break + return self.instance_group + + def present_instance_group(self): + instance_group = self.get_instance_group() + if not instance_group: + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'account': self.get_account('name'), + 'domainid': self.get_domain('id'), + 'projectid': self.get_project('id'), + } + if not self.module.check_mode: + res = self.query_api('createInstanceGroup', **args) + instance_group = res['instancegroup'] + return instance_group + + def absent_instance_group(self): + instance_group = self.get_instance_group() + if instance_group: + self.result['changed'] = True + if not self.module.check_mode: + self.query_api('deleteInstanceGroup', id=instance_group['id']) + return instance_group + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + state=dict(default='present', choices=['present', 'absent']), + domain=dict(), + account=dict(), + project=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_ig = AnsibleCloudStackInstanceGroup(module) + + state = module.params.get('state') + if state in ['absent']: + instance_group = acs_ig.absent_instance_group() + else: + instance_group = acs_ig.present_instance_group() + + result = acs_ig.get_result(instance_group) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py new file mode 100644 index 00000000..04236d3d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_ip_address.py @@ -0,0 +1,279 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk> +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_ip_address +short_description: Manages public IP address associations on Apache CloudStack based clouds. +description: + - Acquires and associates a public IP to an account or project. + - Due to API limitations this is not an idempotent call, so be sure to only + conditionally call this when I(state=present). + - Tagging the IP address can also make the call idempotent. +author: + - Darren Worrall (@dazworrall) + - René Moser (@resmo) +version_added: 0.1.0 +options: + ip_address: + description: + - Public IP address. + - Required if I(state=absent) and I(tags) is not set. + type: str + domain: + description: + - Domain the IP address is related to. + type: str + network: + description: + - Network the IP address is related to. + - Mutually exclusive with I(vpc). + type: str + vpc: + description: + - VPC the IP address is related to. + - Mutually exclusive with I(network). + type: str + account: + description: + - Account the IP address is related to. + type: str + project: + description: + - Name of the project the IP address is related to. + type: str + zone: + description: + - Name of the zone in which the IP address is in. + - If not set, default zone is used. + type: str + state: + description: + - State of the IP address. + type: str + default: present + choices: [ present, absent ] + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - Tags can be used as an unique identifier for the IP Addresses. + - In this case, at least one of them must be unique to ensure idempotency. + type: list + elements: dict + aliases: [ tag ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Associate an IP address conditionally + ngine_io.cloudstack.cs_ip_address: + network: My Network + register: ip_address + when: instance.public_ip is undefined + +- name: Disassociate an IP address + ngine_io.cloudstack.cs_ip_address: + ip_address: 1.2.3.4 + state: absent + +- name: Associate an IP address with tags + ngine_io.cloudstack.cs_ip_address: + network: My Network + tags: + - key: myCustomID + value: 5510c31a-416e-11e8-9013-02000a6b00bf + register: ip_address + +- name: Disassociate an IP address with tags + ngine_io.cloudstack.cs_ip_address: + state: absent + tags: + - key: myCustomID + value: 5510c31a-416e-11e8-9013-02000a6b00bf +''' + +RETURN = ''' +--- +id: + description: UUID of the Public IP address. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +ip_address: + description: Public IP address. + returned: success + type: str + sample: 1.2.3.4 +zone: + description: Name of zone the IP address is related to. + returned: success + type: str + sample: ch-gva-2 +project: + description: Name of project the IP address is related to. + returned: success + type: str + sample: Production +account: + description: Account the IP address is related to. + returned: success + type: str + sample: example account +domain: + description: Domain the IP address is related to. + returned: success + type: str + sample: example domain +tags: + description: List of resource tags associated with the IP address. + returned: success + type: dict + sample: '[ { "key": "myCustomID", "value": "5510c31a-416e-11e8-9013-02000a6b00bf" } ]' +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackIPAddress(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackIPAddress, self).__init__(module) + self.returns = { + 'ipaddress': 'ip_address', + } + + def get_ip_address(self, key=None): + if self.ip_address: + return self._get_by_key(key, self.ip_address) + args = { + 'ipaddress': self.module.params.get('ip_address'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'vpcid': self.get_vpc(key='id'), + } + ip_addresses = self.query_api('listPublicIpAddresses', **args) + + if ip_addresses: + tags = self.module.params.get('tags') + for ip_addr in ip_addresses['publicipaddress']: + if ip_addr['ipaddress'] == args['ipaddress'] != '': + self.ip_address = ip_addresses['publicipaddress'][0] + elif tags: + if sorted([tag for tag in tags if tag in ip_addr['tags']]) == sorted(tags): + self.ip_address = ip_addr + return self._get_by_key(key, self.ip_address) + + def present_ip_address(self): + ip_address = self.get_ip_address() + + if not ip_address: + ip_address = self.associate_ip_address(ip_address) + + if ip_address: + ip_address = self.ensure_tags(resource=ip_address, resource_type='publicipaddress') + + return ip_address + + def associate_ip_address(self, ip_address): + self.result['changed'] = True + args = { + # ipaddress only works with CloudStack >=v4.13 + 'ipaddress': self.module.params.get('ip_address'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + # For the VPC case networkid is irrelevant, special case and we have to ignore it here. + 'networkid': self.get_network(key='id') if not self.module.params.get('vpc') else None, + 'zoneid': self.get_zone(key='id'), + 'vpcid': self.get_vpc(key='id'), + } + ip_address = None + if not self.module.check_mode: + res = self.query_api('associateIpAddress', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + ip_address = self.poll_job(res, 'ipaddress') + return ip_address + + def disassociate_ip_address(self): + ip_address = self.get_ip_address() + if not ip_address: + return None + if ip_address['isstaticnat']: + self.module.fail_json(msg="IP address is allocated via static nat") + + self.result['changed'] = True + if not self.module.check_mode: + self.module.params['tags'] = [] + ip_address = self.ensure_tags(resource=ip_address, resource_type='publicipaddress') + + res = self.query_api('disassociateIpAddress', id=ip_address['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'ipaddress') + return ip_address + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + ip_address=dict(required=False), + state=dict(choices=['present', 'absent'], default='present'), + vpc=dict(), + network=dict(), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + tags=dict(type='list', elements='dict', aliases=['tag']), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + required_if=[ + ('state', 'absent', ['ip_address', 'tags'], True), + ], + mutually_exclusive=( + ['vpc', 'network'], + ), + supports_check_mode=True + ) + + acs_ip_address = AnsibleCloudStackIPAddress(module) + + state = module.params.get('state') + if state in ['absent']: + ip_address = acs_ip_address.disassociate_ip_address() + else: + ip_address = acs_ip_address.present_ip_address() + + result = acs_ip_address.get_result(ip_address) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py new file mode 100644 index 00000000..cecca5eb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_iso.py @@ -0,0 +1,436 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_iso +short_description: Manages ISO images on Apache CloudStack based clouds. +description: + - Register and remove ISO images. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the ISO. + type: str + required: true + display_text: + description: + - Display text of the ISO. + - If not specified, I(name) will be used. + type: str + url: + description: + - URL where the ISO can be downloaded from. Required if I(state) is present. + type: str + os_type: + description: + - Name of the OS that best represents the OS of this ISO. If the iso is bootable this parameter needs to be passed. Required if I(state) is present. + type: str + is_ready: + description: + - This flag is used for searching existing ISOs. If set to C(yes), it will only list ISO ready for deployment e.g. + successfully downloaded and installed. Recommended to set it to C(no). + type: bool + default: no + is_public: + description: + - Register the ISO to be publicly available to all users. Only used if I(state) is present. + type: bool + is_featured: + description: + - Register the ISO to be featured. Only used if I(state) is present. + type: bool + is_dynamically_scalable: + description: + - Register the ISO having XS/VMware tools installed inorder to support dynamic scaling of VM cpu/memory. Only used if I(state) is present. + type: bool + checksum: + description: + - The MD5 checksum value of this ISO. If set, we search by checksum instead of name. + type: str + bootable: + description: + - Register the ISO to be bootable. Only used if I(state) is present. + type: bool + domain: + description: + - Domain the ISO is related to. + type: str + account: + description: + - Account the ISO is related to. + type: str + project: + description: + - Name of the project the ISO to be registered in. + type: str + zone: + description: + - Name of the zone you wish the ISO to be registered or deleted from. + - If not specified, first zone found will be used. + type: str + cross_zones: + description: + - Whether the ISO should be synced or removed across zones. + - Mutually exclusive with I(zone). + type: bool + default: no + iso_filter: + description: + - Name of the filter used to search for the ISO. + type: str + default: self + choices: [ featured, self, selfexecutable,sharedexecutable,executable, community ] + state: + description: + - State of the ISO. + type: str + default: present + choices: [ present, absent ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Register an ISO if ISO name does not already exist + ngine_io.cloudstack.cs_iso: + name: Debian 7 64-bit + url: http://mirror.switch.ch/ftp/mirror/debian-cd/current/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso + os_type: Debian GNU/Linux 7(64-bit) + +- name: Register an ISO with given name if ISO md5 checksum does not already exist + ngine_io.cloudstack.cs_iso: + name: Debian 7 64-bit + url: http://mirror.switch.ch/ftp/mirror/debian-cd/current/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso + os_type: Debian GNU/Linux 7(64-bit) + checksum: 0b31bccccb048d20b551f70830bb7ad0 + +- name: Remove an ISO by name + ngine_io.cloudstack.cs_iso: + name: Debian 7 64-bit + state: absent + +- name: Remove an ISO by checksum + ngine_io.cloudstack.cs_iso: + name: Debian 7 64-bit + checksum: 0b31bccccb048d20b551f70830bb7ad0 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the ISO. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: Name of the ISO. + returned: success + type: str + sample: Debian 7 64-bit +display_text: + description: Text to be displayed of the ISO. + returned: success + type: str + sample: Debian 7.7 64-bit minimal 2015-03-19 +zone: + description: Name of zone the ISO is registered in. + returned: success + type: str + sample: zuerich +status: + description: Status of the ISO. + returned: success + type: str + sample: Successfully Installed +is_ready: + description: True if the ISO is ready to be deployed from. + returned: success + type: bool + sample: true +is_public: + description: True if the ISO is public. + returned: success + type: bool + sample: true +bootable: + description: True if the ISO is bootable. + returned: success + type: bool + sample: true +is_featured: + description: True if the ISO is featured. + returned: success + type: bool + sample: true +format: + description: Format of the ISO. + returned: success + type: str + sample: ISO +os_type: + description: Typo of the OS. + returned: success + type: str + sample: CentOS 6.5 (64-bit) +checksum: + description: MD5 checksum of the ISO. + returned: success + type: str + sample: 0b31bccccb048d20b551f70830bb7ad0 +created: + description: Date of registering. + returned: success + type: str + sample: 2015-03-29T14:57:06+0200 +cross_zones: + description: true if the ISO is managed across all zones, false otherwise. + returned: success + type: bool + sample: false +domain: + description: Domain the ISO is related to. + returned: success + type: str + sample: example domain +account: + description: Account the ISO is related to. + returned: success + type: str + sample: example account +project: + description: Project the ISO is related to. + returned: success + type: str + sample: example project +tags: + description: List of resource tags associated with the ISO. + returned: success + type: dict + sample: '[ { "key": "foo", "value": "bar" } ]' +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackIso(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackIso, self).__init__(module) + self.returns = { + 'checksum': 'checksum', + 'status': 'status', + 'isready': 'is_ready', + 'crossZones': 'cross_zones', + 'format': 'format', + 'ostypename': 'os_type', + 'isfeatured': 'is_featured', + 'bootable': 'bootable', + 'ispublic': 'is_public', + + } + self.iso = None + + def _get_common_args(self): + return { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'), + 'ostypeid': self.get_os_type('id'), + 'bootable': self.module.params.get('bootable'), + } + + def register_iso(self): + args = self._get_common_args() + args.update({ + 'domainid': self.get_domain('id'), + 'account': self.get_account('name'), + 'projectid': self.get_project('id'), + 'checksum': self.module.params.get('checksum'), + 'isfeatured': self.module.params.get('is_featured'), + 'ispublic': self.module.params.get('is_public'), + }) + + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + else: + args['zoneid'] = -1 + + if args['bootable'] and not args['ostypeid']: + self.module.fail_json(msg="OS type 'os_type' is required if 'bootable=true'.") + + args['url'] = self.module.params.get('url') + if not args['url']: + self.module.fail_json(msg="URL is required.") + + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('registerIso', **args) + self.iso = res['iso'][0] + return self.iso + + def present_iso(self): + iso = self.get_iso() + if not iso: + iso = self.register_iso() + else: + iso = self.update_iso(iso) + + if iso: + iso = self.ensure_tags(resource=iso, resource_type='ISO') + self.iso = iso + return iso + + def update_iso(self, iso): + args = self._get_common_args() + args.update({ + 'id': iso['id'], + }) + if self.has_changed(args, iso): + self.result['changed'] = True + + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + else: + # Workaround API does not return cross_zones=true + self.result['cross_zones'] = True + args['zoneid'] = -1 + + if not self.module.check_mode: + res = self.query_api('updateIso', **args) + self.iso = res['iso'] + return self.iso + + def get_iso(self): + if not self.iso: + args = { + 'isready': self.module.params.get('is_ready'), + 'isofilter': self.module.params.get('iso_filter'), + 'domainid': self.get_domain('id'), + 'account': self.get_account('name'), + 'projectid': self.get_project('id'), + } + + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + + # if checksum is set, we only look on that. + checksum = self.module.params.get('checksum') + if not checksum: + args['name'] = self.module.params.get('name') + + isos = self.query_api('listIsos', **args) + if isos: + if not checksum: + self.iso = isos['iso'][0] + else: + for i in isos['iso']: + if i['checksum'] == checksum: + self.iso = i + break + return self.iso + + def absent_iso(self): + iso = self.get_iso() + if iso: + self.result['changed'] = True + + args = { + 'id': iso['id'], + 'projectid': self.get_project('id'), + } + + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + + if not self.module.check_mode: + res = self.query_api('deleteIso', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'iso') + return iso + + def get_result(self, iso): + super(AnsibleCloudStackIso, self).get_result(iso) + # Workaround API does not return cross_zones=true + if self.module.params.get('cross_zones'): + self.result['cross_zones'] = True + if 'zone' in self.result: + del self.result['zone'] + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + url=dict(), + os_type=dict(), + zone=dict(), + cross_zones=dict(type='bool', default=False), + iso_filter=dict(default='self', choices=['featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community']), + domain=dict(), + account=dict(), + project=dict(), + checksum=dict(), + is_ready=dict(type='bool', default=False), + bootable=dict(type='bool'), + is_featured=dict(type='bool'), + is_public=dict(type='bool'), + is_dynamically_scalable=dict(type='bool'), + state=dict(choices=['present', 'absent'], default='present'), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['zone', 'cross_zones'], + ), + supports_check_mode=True + ) + + acs_iso = AnsibleCloudStackIso(module) + + state = module.params.get('state') + if state in ['absent']: + iso = acs_iso.absent_iso() + else: + iso = acs_iso.present_iso() + + result = acs_iso.get_result(iso) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py new file mode 100644 index 00000000..12a7d13a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule.py @@ -0,0 +1,371 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk> +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_loadbalancer_rule +short_description: Manages load balancer rules on Apache CloudStack based clouds. +description: + - Add, update and remove load balancer rules. +author: + - Darren Worrall (@dazworrall) + - René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - The name of the load balancer rule. + type: str + required: true + description: + description: + - The description of the load balancer rule. + type: str + algorithm: + description: + - Load balancer algorithm + - Required when using I(state=present). + type: str + choices: [ source, roundrobin, leastconn ] + default: source + private_port: + description: + - The private port of the private ip address/virtual machine where the network traffic will be load balanced to. + - Required when using I(state=present). + - Can not be changed once the rule exists due API limitation. + type: int + public_port: + description: + - The public port from where the network traffic will be load balanced from. + - Required when using I(state=present). + - Can not be changed once the rule exists due API limitation. + type: int + ip_address: + description: + - Public IP address from where the network traffic will be load balanced from. + type: str + required: true + aliases: [ public_ip ] + open_firewall: + description: + - Whether the firewall rule for public port should be created, while creating the new rule. + - Use M(cs_firewall) for managing firewall rules. + type: bool + default: no + cidr: + description: + - CIDR (full notation) to be used for firewall rule if required. + type: str + protocol: + description: + - The protocol to be used on the load balancer + type: str + project: + description: + - Name of the project the load balancer IP address is related to. + type: str + state: + description: + - State of the rule. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the rule is related to. + type: str + account: + description: + - Account the rule is related to. + type: str + zone: + description: + - Name of the zone in which the rule should be created. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + network: + description: + - Name of the network. + type: str + vpc: + description: + - Name of the VPC. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a load balancer rule + ngine_io.cloudstack.cs_loadbalancer_rule: + name: balance_http + public_ip: 1.2.3.4 + algorithm: leastconn + public_port: 80 + private_port: 8080 + +- name: Update algorithm of an existing load balancer rule + ngine_io.cloudstack.cs_loadbalancer_rule: + name: balance_http + public_ip: 1.2.3.4 + algorithm: roundrobin + public_port: 80 + private_port: 8080 + +- name: Delete a load balancer rule + ngine_io.cloudstack.cs_loadbalancer_rule: + name: balance_http + public_ip: 1.2.3.4 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the rule. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +zone: + description: Name of zone the rule is related to. + returned: success + type: str + sample: ch-gva-2 +project: + description: Name of project the rule is related to. + returned: success + type: str + sample: Production +account: + description: Account the rule is related to. + returned: success + type: str + sample: example account +domain: + description: Domain the rule is related to. + returned: success + type: str + sample: example domain +algorithm: + description: Load balancer algorithm used. + returned: success + type: str + sample: source +cidr: + description: CIDR to forward traffic from. + returned: success + type: str + sample: 0.0.0.0/0 +name: + description: Name of the rule. + returned: success + type: str + sample: http-lb +description: + description: Description of the rule. + returned: success + type: str + sample: http load balancer rule +protocol: + description: Protocol of the rule. + returned: success + type: str + sample: tcp +public_port: + description: Public port. + returned: success + type: int + sample: 80 +private_port: + description: Private IP address. + returned: success + type: int + sample: 80 +public_ip: + description: Public IP address. + returned: success + type: str + sample: 1.2.3.4 +tags: + description: List of resource tags associated with the rule. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +state: + description: State of the rule. + returned: success + type: str + sample: Add +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackLBRule(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackLBRule, self).__init__(module) + self.returns = { + 'publicip': 'public_ip', + 'algorithm': 'algorithm', + 'cidrlist': 'cidr', + 'protocol': 'protocol', + } + # these values will be casted to int + self.returns_to_int = { + 'publicport': 'public_port', + 'privateport': 'private_port', + } + + def get_rule(self, **kwargs): + rules = self.query_api('listLoadBalancerRules', **kwargs) + if rules: + return rules['loadbalancerrule'][0] + + def _get_common_args(self): + return { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id') if self.module.params.get('zone') else None, + 'publicipid': self.get_ip_address(key='id'), + 'name': self.module.params.get('name'), + } + + def present_lb_rule(self): + required_params = [ + 'algorithm', + 'private_port', + 'public_port', + ] + self.module.fail_on_missing_params(required_params=required_params) + + args = self._get_common_args() + rule = self.get_rule(**args) + if rule: + rule = self._update_lb_rule(rule) + else: + rule = self._create_lb_rule(rule) + + if rule: + rule = self.ensure_tags(resource=rule, resource_type='LoadBalancer') + return rule + + def _create_lb_rule(self, rule): + self.result['changed'] = True + if not self.module.check_mode: + args = self._get_common_args() + args.update({ + 'algorithm': self.module.params.get('algorithm'), + 'privateport': self.module.params.get('private_port'), + 'publicport': self.module.params.get('public_port'), + 'cidrlist': self.module.params.get('cidr'), + 'description': self.module.params.get('description'), + 'protocol': self.module.params.get('protocol'), + 'networkid': self.get_network(key='id'), + }) + res = self.query_api('createLoadBalancerRule', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + rule = self.poll_job(res, 'loadbalancer') + return rule + + def _update_lb_rule(self, rule): + args = { + 'id': rule['id'], + 'algorithm': self.module.params.get('algorithm'), + 'description': self.module.params.get('description'), + } + if self.has_changed(args, rule): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateLoadBalancerRule', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + rule = self.poll_job(res, 'loadbalancer') + return rule + + def absent_lb_rule(self): + args = self._get_common_args() + rule = self.get_rule(**args) + if rule: + self.result['changed'] = True + if rule and not self.module.check_mode: + res = self.query_api('deleteLoadBalancerRule', id=rule['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'loadbalancer') + return rule + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + description=dict(), + algorithm=dict(choices=['source', 'roundrobin', 'leastconn'], default='source'), + private_port=dict(type='int'), + public_port=dict(type='int'), + protocol=dict(), + state=dict(choices=['present', 'absent'], default='present'), + ip_address=dict(required=True, aliases=['public_ip']), + cidr=dict(), + project=dict(), + open_firewall=dict(type='bool', default=False), + tags=dict(type='list', elements='dict', aliases=['tag']), + zone=dict(), + domain=dict(), + account=dict(), + vpc=dict(), + network=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_lb_rule = AnsibleCloudStackLBRule(module) + + state = module.params.get('state') + if state in ['absent']: + rule = acs_lb_rule.absent_lb_rule() + else: + rule = acs_lb_rule.present_lb_rule() + + result = acs_lb_rule.get_result(rule) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py new file mode 100644 index 00000000..6922bb83 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_loadbalancer_rule_member.py @@ -0,0 +1,345 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, Darren Worrall <darren@iweb.co.uk> +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_loadbalancer_rule_member +short_description: Manages load balancer rule members on Apache CloudStack based clouds. +description: + - Add and remove load balancer rule members. +author: + - Darren Worrall (@dazworrall) + - René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - The name of the load balancer rule. + type: str + required: true + ip_address: + description: + - Public IP address from where the network traffic will be load balanced from. + - Only needed to find the rule if I(name) is not unique. + type: str + aliases: [ public_ip ] + vms: + description: + - List of VMs to assign to or remove from the rule. + type: list + elements: str + required: true + aliases: [ vm ] + state: + description: + - Should the VMs be present or absent from the rule. + type: str + default: present + choices: [ present, absent ] + project: + description: + - Name of the project the firewall rule is related to. + type: str + domain: + description: + - Domain the rule is related to. + type: str + account: + description: + - Account the rule is related to. + type: str + zone: + description: + - Name of the zone in which the rule should be located. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Add VMs to an existing load balancer + ngine_io.cloudstack.cs_loadbalancer_rule_member: + name: balance_http + vms: + - web01 + - web02 + +- name: Remove a VM from an existing load balancer + ngine_io.cloudstack.cs_loadbalancer_rule_member: + name: balance_http + vms: + - web01 + - web02 + state: absent + + +# Rolling upgrade of hosts +- hosts: webservers + serial: 1 + pre_tasks: + - name: Remove from load balancer + ngine_io.cloudstack.cs_loadbalancer_rule_member: + name: balance_http + vm: "{{ ansible_hostname }}" + state: absent + tasks: + # Perform update + post_tasks: + - name: Add to load balancer + ngine_io.cloudstack.cs_loadbalancer_rule_member: + name: balance_http + vm: "{{ ansible_hostname }}" + state: present + +''' + +RETURN = ''' +--- +id: + description: UUID of the rule. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +zone: + description: Name of zone the rule is related to. + returned: success + type: str + sample: ch-gva-2 +project: + description: Name of project the rule is related to. + returned: success + type: str + sample: Production +account: + description: Account the rule is related to. + returned: success + type: str + sample: example account +domain: + description: Domain the rule is related to. + returned: success + type: str + sample: example domain +algorithm: + description: Load balancer algorithm used. + returned: success + type: str + sample: source +cidr: + description: CIDR to forward traffic from. + returned: success + type: str + sample: 0.0.0.0/0 +name: + description: Name of the rule. + returned: success + type: str + sample: http-lb +description: + description: Description of the rule. + returned: success + type: str + sample: http load balancer rule +protocol: + description: Protocol of the rule. + returned: success + type: str + sample: tcp +public_port: + description: Public port. + returned: success + type: int + sample: 80 +private_port: + description: Private IP address. + returned: success + type: int + sample: 80 +public_ip: + description: Public IP address. + returned: success + type: str + sample: 1.2.3.4 +vms: + description: Rule members. + returned: success + type: list + sample: '[ "web01", "web02" ]' +tags: + description: List of resource tags associated with the rule. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +state: + description: State of the rule. + returned: success + type: str + sample: Add +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackLBRuleMember(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackLBRuleMember, self).__init__(module) + self.returns = { + 'publicip': 'public_ip', + 'algorithm': 'algorithm', + 'cidrlist': 'cidr', + 'protocol': 'protocol', + } + # these values will be casted to int + self.returns_to_int = { + 'publicport': 'public_port', + 'privateport': 'private_port', + } + + def get_rule(self): + args = self._get_common_args() + args.update({ + 'name': self.module.params.get('name'), + 'zoneid': self.get_zone(key='id') if self.module.params.get('zone') else None, + }) + if self.module.params.get('ip_address'): + args['publicipid'] = self.get_ip_address(key='id') + + rules = self.query_api('listLoadBalancerRules', **args) + if rules: + if len(rules['loadbalancerrule']) > 1: + self.module.fail_json(msg="More than one rule having name %s. Please pass 'ip_address' as well." % args['name']) + return rules['loadbalancerrule'][0] + return None + + def _get_common_args(self): + return { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + } + + def _get_members_of_rule(self, rule): + res = self.query_api('listLoadBalancerRuleInstances', id=rule['id']) + return res.get('loadbalancerruleinstance', []) + + def _ensure_members(self, operation): + if operation not in ['add', 'remove']: + self.module.fail_json(msg="Bad operation: %s" % operation) + + rule = self.get_rule() + if not rule: + self.module.fail_json(msg="Unknown rule: %s" % self.module.params.get('name')) + + existing = {} + for vm in self._get_members_of_rule(rule=rule): + existing[vm['name']] = vm['id'] + + wanted_names = self.module.params.get('vms') + + if operation == 'add': + cs_func = 'assignToLoadBalancerRule' + to_change = set(wanted_names) - set(existing.keys()) + else: + cs_func = 'removeFromLoadBalancerRule' + to_change = set(wanted_names) & set(existing.keys()) + + if not to_change: + return rule + + args = self._get_common_args() + args['fetch_list'] = True + vms = self.query_api('listVirtualMachines', **args) + to_change_ids = [] + for name in to_change: + for vm in vms: + if vm['name'] == name: + to_change_ids.append(vm['id']) + break + else: + self.module.fail_json(msg="Unknown VM: %s" % name) + + if to_change_ids: + self.result['changed'] = True + + if to_change_ids and not self.module.check_mode: + res = self.query_api( + cs_func, + id=rule['id'], + virtualmachineids=to_change_ids, + ) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res) + rule = self.get_rule() + return rule + + def add_members(self): + return self._ensure_members('add') + + def remove_members(self): + return self._ensure_members('remove') + + def get_result(self, rule): + super(AnsibleCloudStackLBRuleMember, self).get_result(rule) + if rule: + self.result['vms'] = [] + for vm in self._get_members_of_rule(rule=rule): + self.result['vms'].append(vm['name']) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + ip_address=dict(aliases=['public_ip']), + vms=dict(required=True, aliases=['vm'], type='list', elements='str'), + state=dict(choices=['present', 'absent'], default='present'), + zone=dict(), + domain=dict(), + project=dict(), + account=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_lb_rule_member = AnsibleCloudStackLBRuleMember(module) + + state = module.params.get('state') + if state in ['absent']: + rule = acs_lb_rule_member.remove_members() + else: + rule = acs_lb_rule_member.add_members() + + result = acs_lb_rule_member.get_result(rule) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py new file mode 100644 index 00000000..3dc37999 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network.py @@ -0,0 +1,633 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_network +short_description: Manages networks on Apache CloudStack based clouds. +description: + - Create, update, restart and delete networks. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name (case sensitive) of the network. + type: str + required: true + display_text: + description: + - Display text of the network. + - If not specified, I(name) will be used as I(display_text). + type: str + network_offering: + description: + - Name of the offering for the network. + - Required if I(state=present). + type: str + start_ip: + description: + - The beginning IPv4 address of the network belongs to. + - Only considered on create. + type: str + end_ip: + description: + - The ending IPv4 address of the network belongs to. + - If not specified, value of I(start_ip) is used. + - Only considered on create. + type: str + gateway: + description: + - The gateway of the network. + - Required for shared networks and isolated networks when it belongs to a VPC. + - Only considered on create. + type: str + netmask: + description: + - The netmask of the network. + - Required for shared networks and isolated networks when it belongs to a VPC. + - Only considered on create. + type: str + start_ipv6: + description: + - The beginning IPv6 address of the network belongs to. + - Only considered on create. + type: str + end_ipv6: + description: + - The ending IPv6 address of the network belongs to. + - If not specified, value of I(start_ipv6) is used. + - Only considered on create. + type: str + cidr_ipv6: + description: + - CIDR of IPv6 network, must be at least /64. + - Only considered on create. + type: str + gateway_ipv6: + description: + - The gateway of the IPv6 network. + - Required for shared networks. + - Only considered on create. + type: str + vlan: + description: + - The ID or VID of the network. + type: str + vpc: + description: + - Name of the VPC of the network. + type: str + isolated_pvlan: + description: + - The isolated private VLAN for this network. + type: str + clean_up: + description: + - Cleanup old network elements. + - Only considered on I(state=restarted). + default: no + type: bool + acl_type: + description: + - Access control type for the network. + - If not specified, Cloudstack will default to C(account) for isolated networks + - and C(domain) for shared networks. + - Only considered on create. + type: str + choices: [ account, domain ] + acl: + description: + - The name of the access control list for the VPC network tier. + type: str + subdomain_access: + description: + - Defines whether to allow subdomains to use networks dedicated to their parent domain(s). + - Should be used with I(acl_type=domain). + - Only considered on create. + type: bool + network_domain: + description: + - The network domain. + type: str + state: + description: + - State of the network. + type: str + default: present + choices: [ present, absent, restarted ] + zone: + description: + - Name of the zone in which the network should be deployed. + - If not set, default zone is used. + type: str + project: + description: + - Name of the project the network to be deployed in. + type: str + domain: + description: + - Domain the network is related to. + type: str + account: + description: + - Account the network is related to. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a network + ngine_io.cloudstack.cs_network: + name: my network + zone: gva-01 + network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService + network_domain: example.com + +- name: Create a network with start and end IP + ngine_io.cloudstack.cs_network: + name: Private Network + network_offering: PrivNet + start_ip: 10.12.9.10 + end_ip: 10.12.9.100 + netmask: 255.255.255.0 + zone: gva-01 + +- name: Create a VPC tier + ngine_io.cloudstack.cs_network: + name: my VPC tier 1 + zone: gva-01 + vpc: my VPC + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + acl: my web acl + +- name: Update a network + ngine_io.cloudstack.cs_network: + name: my network + display_text: network of domain example.local + network_domain: example.local + +- name: Restart a network with clean up + ngine_io.cloudstack.cs_network: + name: my network + clean_up: yes + state: restarted + +- name: Remove a network + ngine_io.cloudstack.cs_network: + name: my network + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the network. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the network. + returned: success + type: str + sample: web project +display_text: + description: Display text of the network. + returned: success + type: str + sample: web project +dns1: + description: IP address of the 1st nameserver. + returned: success + type: str + sample: 1.2.3.4 +dns2: + description: IP address of the 2nd nameserver. + returned: success + type: str + sample: 1.2.3.4 +cidr: + description: IPv4 network CIDR. + returned: success + type: str + sample: 10.101.64.0/24 +gateway: + description: IPv4 gateway. + returned: success + type: str + sample: 10.101.64.1 +netmask: + description: IPv4 netmask. + returned: success + type: str + sample: 255.255.255.0 +cidr_ipv6: + description: IPv6 network CIDR. + returned: if available + type: str + sample: 2001:db8::/64 +gateway_ipv6: + description: IPv6 gateway. + returned: if available + type: str + sample: 2001:db8::1 +zone: + description: Name of zone. + returned: success + type: str + sample: ch-gva-2 +domain: + description: Domain the network is related to. + returned: success + type: str + sample: ROOT +account: + description: Account the network is related to. + returned: success + type: str + sample: example account +project: + description: Name of project. + returned: success + type: str + sample: Production +tags: + description: List of resource tags associated with the network. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +acl_type: + description: Access type of the network (Domain, Account). + returned: success + type: str + sample: Account +acl: + description: Name of the access control list for the VPC network tier. + returned: success + type: str + sample: My ACL +acl_id: + description: ID of the access control list for the VPC network tier. + returned: success + type: str + sample: dfafcd55-0510-4b8c-b6c5-b8cedb4cfd88 +broadcast_domain_type: + description: Broadcast domain type of the network. + returned: success + type: str + sample: Vlan +type: + description: Type of the network. + returned: success + type: str + sample: Isolated +traffic_type: + description: Traffic type of the network. + returned: success + type: str + sample: Guest +state: + description: State of the network (Allocated, Implemented, Setup). + returned: success + type: str + sample: Allocated +is_persistent: + description: Whether the network is persistent or not. + returned: success + type: bool + sample: false +network_domain: + description: The network domain + returned: success + type: str + sample: example.local +network_offering: + description: The network offering name. + returned: success + type: str + sample: DefaultIsolatedNetworkOfferingWithSourceNatService +network_offering_display_text: + description: The network offering display text. + returned: success + type: str + sample: Offering for Isolated Vpc networks with Source Nat service enabled +network_offering_conserve_mode: + description: Whether the network offering has IP conserve mode enabled or not. + returned: success + type: bool + sample: false +network_offering_availability: + description: The availability of the network offering the network is created from + returned: success + type: str + sample: Optional +is_system: + description: Whether the network is system related or not. + returned: success + type: bool + sample: false +vpc: + description: Name of the VPC. + returned: if available + type: str + sample: My VPC +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackNetwork(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackNetwork, self).__init__(module) + self.returns = { + 'networkdomain': 'network_domain', + 'networkofferingname': 'network_offering', + 'networkofferingdisplaytext': 'network_offering_display_text', + 'networkofferingconservemode': 'network_offering_conserve_mode', + 'networkofferingavailability': 'network_offering_availability', + 'aclid': 'acl_id', + 'issystem': 'is_system', + 'ispersistent': 'is_persistent', + 'acltype': 'acl_type', + 'type': 'type', + 'traffictype': 'traffic_type', + 'ip6gateway': 'gateway_ipv6', + 'ip6cidr': 'cidr_ipv6', + 'gateway': 'gateway', + 'cidr': 'cidr', + 'netmask': 'netmask', + 'broadcastdomaintype': 'broadcast_domain_type', + 'dns1': 'dns1', + 'dns2': 'dns2', + } + self.network = None + + def get_network_acl(self, key=None, acl_id=None): + if acl_id is not None: + args = { + 'id': acl_id, + 'vpcid': self.get_vpc(key='id'), + } + else: + acl_name = self.module.params.get('acl') + if not acl_name: + return + + args = { + 'name': acl_name, + 'vpcid': self.get_vpc(key='id'), + } + network_acls = self.query_api('listNetworkACLLists', **args) + if network_acls: + acl = network_acls['networkacllist'][0] + return self._get_by_key(key, acl) + + def get_network_offering(self, key=None): + network_offering = self.module.params.get('network_offering') + if not network_offering: + self.module.fail_json(msg="missing required arguments: network_offering") + + args = { + 'zoneid': self.get_zone(key='id'), + 'fetch_list': True, + } + + network_offerings = self.query_api('listNetworkOfferings', **args) + if network_offerings: + for no in network_offerings: + if network_offering in [no['name'], no['displaytext'], no['id']]: + return self._get_by_key(key, no) + self.module.fail_json(msg="Network offering '%s' not found" % network_offering) + + def _get_args(self): + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'networkdomain': self.module.params.get('network_domain'), + 'networkofferingid': self.get_network_offering(key='id') + } + return args + + def get_network(self, refresh=False): + if not self.network or refresh: + network = self.module.params.get('name') + args = { + 'zoneid': self.get_zone(key='id'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'vpcid': self.get_vpc(key='id'), + 'fetch_list': True, + } + networks = self.query_api('listNetworks', **args) + if networks: + for n in networks: + if network in [n['name'], n['displaytext'], n['id']]: + self.network = n + self.network['acl'] = self.get_network_acl(key='name', acl_id=n.get('aclid')) + break + return self.network + + def present_network(self): + if self.module.params.get('acl') is not None and self.module.params.get('vpc') is None: + self.module.fail_json(msg="Missing required params: vpc") + + network = self.get_network() + if not network: + network = self.create_network(network) + else: + network = self.update_network(network) + + if network: + network = self.ensure_tags(resource=network, resource_type='Network') + + return network + + def update_network(self, network): + args = self._get_args() + args['id'] = network['id'] + + if self.has_changed(args, network): + self.result['changed'] = True + if not self.module.check_mode: + network = self.query_api('updateNetwork', **args) + + poll_async = self.module.params.get('poll_async') + if network and poll_async: + network = self.poll_job(network, 'network') + + # Skip ACL check if the network is not a VPC tier + if network.get('aclid') != self.get_network_acl(key='id'): + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'aclid': self.get_network_acl(key='id'), + 'networkid': network['id'], + } + network = self.query_api('replaceNetworkACLList', **args) + if self.module.params.get('poll_async'): + self.poll_job(network, 'networkacllist') + network = self.get_network(refresh=True) + return network + + def create_network(self, network): + self.result['changed'] = True + + args = self._get_args() + args.update({ + 'acltype': self.module.params.get('acl_type'), + 'aclid': self.get_network_acl(key='id'), + 'zoneid': self.get_zone(key='id'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'startip': self.module.params.get('start_ip'), + 'endip': self.get_or_fallback('end_ip', 'start_ip'), + 'netmask': self.module.params.get('netmask'), + 'gateway': self.module.params.get('gateway'), + 'startipv6': self.module.params.get('start_ipv6'), + 'endipv6': self.get_or_fallback('end_ipv6', 'start_ipv6'), + 'ip6cidr': self.module.params.get('cidr_ipv6'), + 'ip6gateway': self.module.params.get('gateway_ipv6'), + 'vlan': self.module.params.get('vlan'), + 'isolatedpvlan': self.module.params.get('isolated_pvlan'), + 'subdomainaccess': self.module.params.get('subdomain_access'), + 'vpcid': self.get_vpc(key='id') + }) + + if not self.module.check_mode: + res = self.query_api('createNetwork', **args) + + network = res['network'] + return network + + def restart_network(self): + network = self.get_network() + + if not network: + self.module.fail_json(msg="No network named '%s' found." % self.module.params('name')) + + # Restarting only available for these states + if network['state'].lower() in ['implemented', 'setup']: + self.result['changed'] = True + + args = { + 'id': network['id'], + 'cleanup': self.module.params.get('clean_up') + } + + if not self.module.check_mode: + network = self.query_api('restartNetwork', **args) + + poll_async = self.module.params.get('poll_async') + if network and poll_async: + network = self.poll_job(network, 'network') + return network + + def absent_network(self): + network = self.get_network() + if network: + self.result['changed'] = True + + args = { + 'id': network['id'] + } + + if not self.module.check_mode: + res = self.query_api('deleteNetwork', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + self.poll_job(res, 'network') + return network + + def get_result(self, network): + super(AnsibleCloudStackNetwork, self).get_result(network) + if network: + self.result['acl'] = self.get_network_acl(key='name', acl_id=network.get('aclid')) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + network_offering=dict(), + zone=dict(), + start_ip=dict(), + end_ip=dict(), + gateway=dict(), + netmask=dict(), + start_ipv6=dict(), + end_ipv6=dict(), + cidr_ipv6=dict(), + gateway_ipv6=dict(), + vlan=dict(), + vpc=dict(), + isolated_pvlan=dict(), + clean_up=dict(type='bool', default=False), + network_domain=dict(), + subdomain_access=dict(type='bool'), + state=dict(choices=['present', 'absent', 'restarted'], default='present'), + acl=dict(), + acl_type=dict(choices=['account', 'domain']), + project=dict(), + domain=dict(), + account=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_network = AnsibleCloudStackNetwork(module) + + state = module.params.get('state') + if state == 'absent': + network = acs_network.absent_network() + + elif state == 'restarted': + network = acs_network.restart_network() + + else: + network = acs_network.present_network() + + result = acs_network.get_result(network) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py new file mode 100644 index 00000000..b6cd0e18 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl.py @@ -0,0 +1,197 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_network_acl +short_description: Manages network access control lists (ACL) on Apache CloudStack based clouds. +description: + - Create and remove network ACLs. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the network ACL. + type: str + required: true + description: + description: + - Description of the network ACL. + - If not set, identical to I(name). + type: str + vpc: + description: + - VPC the network ACL is related to. + type: str + required: true + state: + description: + - State of the network ACL. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the network ACL rule is related to. + type: str + account: + description: + - Account the network ACL rule is related to. + type: str + project: + description: + - Name of the project the network ACL is related to. + type: str + zone: + description: + - Name of the zone the VPC is related to. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a network ACL + ngine_io.cloudstack.cs_network_acl: + name: Webserver ACL + description: a more detailed description of the ACL + vpc: customers + +- name: remove a network ACL + ngine_io.cloudstack.cs_network_acl: + name: Webserver ACL + vpc: customers + state: absent +''' + +RETURN = ''' +--- +name: + description: Name of the network ACL. + returned: success + type: str + sample: customer acl +description: + description: Description of the network ACL. + returned: success + type: str + sample: Example description of a network ACL +vpc: + description: VPC of the network ACL. + returned: success + type: str + sample: customer vpc +zone: + description: Zone the VPC is related to. + returned: success + type: str + sample: ch-gva-2 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackNetworkAcl(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackNetworkAcl, self).__init__(module) + + def get_network_acl(self): + args = { + 'name': self.module.params.get('name'), + 'vpcid': self.get_vpc(key='id'), + } + network_acls = self.query_api('listNetworkACLLists', **args) + if network_acls: + return network_acls['networkacllist'][0] + return None + + def present_network_acl(self): + network_acl = self.get_network_acl() + if not network_acl: + self.result['changed'] = True + args = { + 'name': self.module.params.get('name'), + 'description': self.get_or_fallback('description', 'name'), + 'vpcid': self.get_vpc(key='id') + } + if not self.module.check_mode: + res = self.query_api('createNetworkACLList', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + network_acl = self.poll_job(res, 'networkacllist') + + return network_acl + + def absent_network_acl(self): + network_acl = self.get_network_acl() + if network_acl: + self.result['changed'] = True + args = { + 'id': network_acl['id'], + } + if not self.module.check_mode: + res = self.query_api('deleteNetworkACLList', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'networkacllist') + + return network_acl + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + description=dict(), + vpc=dict(required=True), + state=dict(choices=['present', 'absent'], default='present'), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_network_acl = AnsibleCloudStackNetworkAcl(module) + + state = module.params.get('state') + if state == 'absent': + network_acl = acs_network_acl.absent_network_acl() + else: + network_acl = acs_network_acl.present_network_acl() + + result = acs_network_acl.get_result(network_acl) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py new file mode 100644 index 00000000..acce9e2c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_acl_rule.py @@ -0,0 +1,457 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_network_acl_rule +short_description: Manages network access control list (ACL) rules on Apache CloudStack based clouds. +description: + - Add, update and remove network ACL rules. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + network_acl: + description: + - Name of the network ACL. + type: str + required: true + aliases: [ acl ] + cidrs: + description: + - CIDRs of the rule. + type: list + elements: str + default: [ 0.0.0.0/0 ] + aliases: [ cidr ] + rule_position: + description: + - The position of the network ACL rule. + type: int + required: true + aliases: [ number ] + protocol: + description: + - Protocol of the rule + choices: [ tcp, udp, icmp, all, by_number ] + type: str + default: tcp + protocol_number: + description: + - Protocol number from 1 to 256 required if I(protocol=by_number). + type: int + start_port: + description: + - Start port for this rule. + - Considered if I(protocol=tcp) or I(protocol=udp). + type: int + aliases: [ port ] + end_port: + description: + - End port for this rule. + - Considered if I(protocol=tcp) or I(protocol=udp). + - If not specified, equal I(start_port). + type: int + icmp_type: + description: + - Type of the icmp message being sent. + - Considered if I(protocol=icmp). + type: int + icmp_code: + description: + - Error code for this icmp message. + - Considered if I(protocol=icmp). + type: int + vpc: + description: + - VPC the network ACL is related to. + type: str + required: true + traffic_type: + description: + - Traffic type of the rule. + type: str + choices: [ ingress, egress ] + default: ingress + aliases: [ type ] + action_policy: + description: + - Action policy of the rule. + type: str + choices: [ allow, deny ] + default: allow + aliases: [ action ] + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "If you want to delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + domain: + description: + - Domain the VPC is related to. + type: str + account: + description: + - Account the VPC is related to. + type: str + project: + description: + - Name of the project the VPC is related to. + type: str + zone: + description: + - Name of the zone the VPC related to. + - If not set, default zone is used. + type: str + state: + description: + - State of the network ACL rule. + type: str + default: present + choices: [ present, absent ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a network ACL rule, allow port 80 ingress + ngine_io.cloudstack.cs_network_acl_rule: + network_acl: web + rule_position: 1 + vpc: my vpc + traffic_type: ingress + action_policy: allow + port: 80 + cidr: 0.0.0.0/0 + +- name: create a network ACL rule, deny port range 8000-9000 ingress for 10.20.0.0/16 and 10.22.0.0/16 + ngine_io.cloudstack.cs_network_acl_rule: + network_acl: web + rule_position: 1 + vpc: my vpc + traffic_type: ingress + action_policy: deny + start_port: 8000 + end_port: 9000 + cidrs: + - 10.20.0.0/16 + - 10.22.0.0/16 + +- name: remove a network ACL rule + ngine_io.cloudstack.cs_network_acl_rule: + network_acl: web + rule_position: 1 + vpc: my vpc + state: absent +''' + +RETURN = ''' +--- +network_acl: + description: Name of the network ACL. + returned: success + type: str + sample: customer acl +cidr: + description: CIDR of the network ACL rule. + returned: success + type: str + sample: 0.0.0.0/0 +cidrs: + description: CIDRs of the network ACL rule. + returned: success + type: list + sample: [ 0.0.0.0/0 ] +rule_position: + description: Position of the network ACL rule. + returned: success + type: int + sample: 1 +action_policy: + description: Action policy of the network ACL rule. + returned: success + type: str + sample: deny +traffic_type: + description: Traffic type of the network ACL rule. + returned: success + type: str + sample: ingress +protocol: + description: Protocol of the network ACL rule. + returned: success + type: str + sample: tcp +protocol_number: + description: Protocol number in case protocol is by number. + returned: success + type: int + sample: 8 +start_port: + description: Start port of the network ACL rule. + returned: success + type: int + sample: 80 +end_port: + description: End port of the network ACL rule. + returned: success + type: int + sample: 80 +icmp_code: + description: ICMP code of the network ACL rule. + returned: success + type: int + sample: 8 +icmp_type: + description: ICMP type of the network ACL rule. + returned: success + type: int + sample: 0 +state: + description: State of the network ACL rule. + returned: success + type: str + sample: Active +vpc: + description: VPC of the network ACL. + returned: success + type: str + sample: customer vpc +tags: + description: List of resource tags associated with the network ACL rule. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +domain: + description: Domain the network ACL rule is related to. + returned: success + type: str + sample: example domain +account: + description: Account the network ACL rule is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the network ACL rule is related to. + returned: success + type: str + sample: Production +zone: + description: Zone the VPC is related to. + returned: success + type: str + sample: ch-gva-2 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackNetworkAclRule(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackNetworkAclRule, self).__init__(module) + self.returns = { + 'cidrlist': 'cidr', + 'action': 'action_policy', + 'protocol': 'protocol', + 'icmpcode': 'icmp_code', + 'icmptype': 'icmp_type', + 'number': 'rule_position', + 'traffictype': 'traffic_type', + } + # these values will be casted to int + self.returns_to_int = { + 'startport': 'start_port', + 'endport': 'end_port', + } + + def get_network_acl_rule(self): + args = { + 'aclid': self.get_network_acl(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + } + network_acl_rules = self.query_api('listNetworkACLs', **args) + for acl_rule in network_acl_rules.get('networkacl', []): + if acl_rule['number'] == self.module.params.get('rule_position'): + return acl_rule + return None + + def present_network_acl_rule(self): + network_acl_rule = self.get_network_acl_rule() + + protocol = self.module.params.get('protocol') + start_port = self.module.params.get('start_port') + end_port = self.get_or_fallback('end_port', 'start_port') + icmp_type = self.module.params.get('icmp_type') + icmp_code = self.module.params.get('icmp_code') + + if protocol in ['tcp', 'udp'] and (start_port is None or end_port is None): + self.module.fail_json(msg="protocol is %s but the following are missing: start_port, end_port" % protocol) + + elif protocol == 'icmp' and (icmp_type is None or icmp_code is None): + self.module.fail_json(msg="protocol is icmp but the following are missing: icmp_type, icmp_code") + + elif protocol == 'by_number' and self.module.params.get('protocol_number') is None: + self.module.fail_json(msg="protocol is by_number but the following are missing: protocol_number") + + if not network_acl_rule: + network_acl_rule = self._create_network_acl_rule(network_acl_rule) + else: + network_acl_rule = self._update_network_acl_rule(network_acl_rule) + + if network_acl_rule: + network_acl_rule = self.ensure_tags(resource=network_acl_rule, resource_type='NetworkACL') + return network_acl_rule + + def absent_network_acl_rule(self): + network_acl_rule = self.get_network_acl_rule() + if network_acl_rule: + self.result['changed'] = True + args = { + 'id': network_acl_rule['id'], + } + if not self.module.check_mode: + res = self.query_api('deleteNetworkACL', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'networkacl') + + return network_acl_rule + + def _create_network_acl_rule(self, network_acl_rule): + self.result['changed'] = True + protocol = self.module.params.get('protocol') + args = { + 'aclid': self.get_network_acl(key='id'), + 'action': self.module.params.get('action_policy'), + 'protocol': protocol if protocol != 'by_number' else self.module.params.get('protocol_number'), + 'startport': self.module.params.get('start_port'), + 'endport': self.get_or_fallback('end_port', 'start_port'), + 'number': self.module.params.get('rule_position'), + 'icmpcode': self.module.params.get('icmp_code'), + 'icmptype': self.module.params.get('icmp_type'), + 'traffictype': self.module.params.get('traffic_type'), + 'cidrlist': self.module.params.get('cidrs'), + } + if not self.module.check_mode: + res = self.query_api('createNetworkACL', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + network_acl_rule = self.poll_job(res, 'networkacl') + + return network_acl_rule + + def _update_network_acl_rule(self, network_acl_rule): + protocol = self.module.params.get('protocol') + args = { + 'id': network_acl_rule['id'], + 'action': self.module.params.get('action_policy'), + 'protocol': protocol if protocol != 'by_number' else str(self.module.params.get('protocol_number')), + 'startport': self.module.params.get('start_port'), + 'endport': self.get_or_fallback('end_port', 'start_port'), + 'icmpcode': self.module.params.get('icmp_code'), + 'icmptype': self.module.params.get('icmp_type'), + 'traffictype': self.module.params.get('traffic_type'), + 'cidrlist': ",".join(self.module.params.get('cidrs')), + } + if self.has_changed(args, network_acl_rule): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateNetworkACLItem', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + network_acl_rule = self.poll_job(res, 'networkacl') + + return network_acl_rule + + def get_result(self, network_acl_rule): + super(AnsibleCloudStackNetworkAclRule, self).get_result(network_acl_rule) + if network_acl_rule: + if 'cidrlist' in network_acl_rule: + self.result['cidrs'] = network_acl_rule['cidrlist'].split(',') or [network_acl_rule['cidrlist']] + if network_acl_rule['protocol'] not in ['tcp', 'udp', 'icmp', 'all']: + self.result['protocol_number'] = int(network_acl_rule['protocol']) + self.result['protocol'] = 'by_number' + self.result['action_policy'] = self.result['action_policy'].lower() + self.result['traffic_type'] = self.result['traffic_type'].lower() + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + network_acl=dict(required=True, aliases=['acl']), + rule_position=dict(required=True, type='int', aliases=['number']), + vpc=dict(required=True), + cidrs=dict(type='list', elements='str', default=['0.0.0.0/0'], aliases=['cidr']), + protocol=dict(choices=['tcp', 'udp', 'icmp', 'all', 'by_number'], default='tcp'), + protocol_number=dict(type='int'), + traffic_type=dict(choices=['ingress', 'egress'], aliases=['type'], default='ingress'), + action_policy=dict(choices=['allow', 'deny'], aliases=['action'], default='allow'), + icmp_type=dict(type='int'), + icmp_code=dict(type='int'), + start_port=dict(type='int', aliases=['port']), + end_port=dict(type='int'), + state=dict(choices=['present', 'absent'], default='present'), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + tags=dict(type='list', elements='dict', aliases=['tag']), + poll_async=dict(type='bool', default=True), + )) + + required_together = cs_required_together() + required_together.extend([ + ['icmp_type', 'icmp_code'], + ]) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['icmp_type', 'start_port'], + ['icmp_type', 'end_port'], + ), + supports_check_mode=True + ) + + acs_network_acl_rule = AnsibleCloudStackNetworkAclRule(module) + + state = module.params.get('state') + if state == 'absent': + network_acl_rule = acs_network_acl_rule.absent_network_acl_rule() + else: + network_acl_rule = acs_network_acl_rule.present_network_acl_rule() + + result = acs_network_acl_rule.get_result(network_acl_rule) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py new file mode 100644 index 00000000..a5c5cb93 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_network_offering.py @@ -0,0 +1,422 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, David Passante (@dpassante) +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_network_offering +short_description: Manages network offerings on Apache CloudStack based clouds. +description: + - Create, update, enable, disable and remove network offerings. +author: David Passante (@dpassante) +version_added: 0.1.0 +options: + state: + description: + - State of the network offering. + type: str + choices: [ enabled, present, disabled, absent] + default: present + display_text: + description: + - Display text of the network offerings. + type: str + guest_ip_type: + description: + - Guest type of the network offering. + type: str + choices: [ Shared, Isolated ] + name: + description: + - The name of the network offering. + type: str + required: true + supported_services: + description: + - Services supported by the network offering. + - A list of one or more items from the choice list. + type: list + elements: str + choices: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + aliases: [ supported_service ] + traffic_type: + description: + - The traffic type for the network offering. + type: str + default: Guest + availability: + description: + - The availability of network offering. Default value is Optional + type: str + conserve_mode: + description: + - Whether the network offering has IP conserve mode enabled. + type: bool + details: + description: + - Network offering details in key/value pairs. + - with service provider as a value + type: list + elements: dict + egress_default_policy: + description: + - Whether the default egress policy is allow or to deny. + type: str + choices: [ allow, deny ] + persistent: + description: + - True if network offering supports persistent networks + - defaulted to false if not specified + type: bool + keepalive_enabled: + description: + - If true keepalive will be turned on in the loadbalancer. + - At the time of writing this has only an effect on haproxy. + - the mode http and httpclose options are unset in the haproxy conf file. + type: bool + max_connections: + description: + - Maximum number of concurrent connections supported by the network offering. + type: int + network_rate: + description: + - Data transfer rate in megabits per second allowed. + type: int + service_capabilities: + description: + - Desired service capabilities as part of network offering. + type: list + elements: str + aliases: [ service_capability ] + service_offering: + description: + - The service offering name or ID used by virtual router provider. + type: str + service_providers: + description: + - Provider to service mapping. + - If not specified, the provider for the service will be mapped to the default provider on the physical network. + type: list + elements: dict + aliases: [ service_provider ] + specify_ip_ranges: + description: + - Whether the network offering supports specifying IP ranges. + - Defaulted to C(no) by the API if not specified. + type: bool + specify_vlan: + description: + - Whether the network offering supports vlans or not. + type: bool + for_vpc: + description: + - Whether the offering is meant to be used for VPC or not. + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a network offering and enable it + ngine_io.cloudstack.cs_network_offering: + name: my_network_offering + display_text: network offering description + state: enabled + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + +- name: Remove a network offering + ngine_io.cloudstack.cs_network_offering: + name: my_network_offering + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the network offering. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: The name of the network offering. + returned: success + type: str + sample: MyCustomNetworkOffering +display_text: + description: The display text of the network offering. + returned: success + type: str + sample: My network offering +state: + description: The state of the network offering. + returned: success + type: str + sample: Enabled +guest_ip_type: + description: Guest type of the network offering. + returned: success + type: str + sample: Isolated +availability: + description: The availability of network offering. + returned: success + type: str + sample: Optional +service_offering_id: + description: The service offering ID. + returned: success + type: str + sample: c5f7a5fc-43f8-11e5-a151-feff819cdc9f +max_connections: + description: The maximum number of concurrent connections to be handled by LB. + returned: success + type: int + sample: 300 +network_rate: + description: The network traffic transfer ate in Mbit/s. + returned: success + type: int + sample: 200 +traffic_type: + description: The traffic type. + returned: success + type: str + sample: Guest +egress_default_policy: + description: Default egress policy. + returned: success + type: str + sample: allow +is_persistent: + description: Whether persistent networks are supported or not. + returned: success + type: bool + sample: false +is_default: + description: Whether network offering is the default offering or not. + returned: success + type: bool + sample: false +for_vpc: + description: Whether the offering is meant to be used for VPC or not. + returned: success + type: bool + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackNetworkOffering(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackNetworkOffering, self).__init__(module) + self.returns = { + 'guestiptype': 'guest_ip_type', + 'availability': 'availability', + 'serviceofferingid': 'service_offering_id', + 'networkrate': 'network_rate', + 'maxconnections': 'max_connections', + 'traffictype': 'traffic_type', + 'isdefault': 'is_default', + 'ispersistent': 'is_persistent', + 'forvpc': 'for_vpc' + } + self.network_offering = None + + def get_service_offering_id(self): + service_offering = self.module.params.get('service_offering') + if not service_offering: + return None + + args = { + 'issystem': True + } + + service_offerings = self.query_api('listServiceOfferings', **args) + if service_offerings: + for s in service_offerings['serviceoffering']: + if service_offering in [s['name'], s['id']]: + return s['id'] + self.fail_json(msg="Service offering '%s' not found" % service_offering) + + def get_network_offering(self): + if self.network_offering: + return self.network_offering + + args = { + 'name': self.module.params.get('name'), + 'guestiptype': self.module.params.get('guest_type'), + } + no = self.query_api('listNetworkOfferings', **args) + if no: + self.network_offering = no['networkoffering'][0] + + return self.network_offering + + def create_or_update(self): + network_offering = self.get_network_offering() + + if not network_offering: + network_offering = self.create_network_offering() + + return self.update_network_offering(network_offering=network_offering) + + def create_network_offering(self): + network_offering = None + self.result['changed'] = True + + args = { + 'state': self.module.params.get('state'), + 'displaytext': self.module.params.get('display_text'), + 'guestiptype': self.module.params.get('guest_ip_type'), + 'name': self.module.params.get('name'), + 'supportedservices': self.module.params.get('supported_services'), + 'traffictype': self.module.params.get('traffic_type'), + 'availability': self.module.params.get('availability'), + 'conservemode': self.module.params.get('conserve_mode'), + 'details': self.module.params.get('details'), + 'egressdefaultpolicy': self.module.params.get('egress_default_policy') == 'allow', + 'ispersistent': self.module.params.get('persistent'), + 'keepaliveenabled': self.module.params.get('keepalive_enabled'), + 'maxconnections': self.module.params.get('max_connections'), + 'networkrate': self.module.params.get('network_rate'), + 'servicecapabilitylist': self.module.params.get('service_capabilities'), + 'serviceofferingid': self.get_service_offering_id(), + 'serviceproviderlist': self.module.params.get('service_providers'), + 'specifyipranges': self.module.params.get('specify_ip_ranges'), + 'specifyvlan': self.module.params.get('specify_vlan'), + 'forvpc': self.module.params.get('for_vpc'), + } + + required_params = [ + 'display_text', + 'guest_ip_type', + 'supported_services', + 'service_providers', + ] + + self.module.fail_on_missing_params(required_params=required_params) + + if not self.module.check_mode: + res = self.query_api('createNetworkOffering', **args) + network_offering = res['networkoffering'] + + return network_offering + + def delete_network_offering(self): + network_offering = self.get_network_offering() + + if network_offering: + self.result['changed'] = True + if not self.module.check_mode: + self.query_api('deleteNetworkOffering', id=network_offering['id']) + + return network_offering + + def update_network_offering(self, network_offering): + if not network_offering: + return network_offering + + args = { + 'id': network_offering['id'], + 'state': self.module.params.get('state'), + 'displaytext': self.module.params.get('display_text'), + 'name': self.module.params.get('name'), + 'availability': self.module.params.get('availability'), + 'maxconnections': self.module.params.get('max_connections'), + } + + if args['state'] in ['enabled', 'disabled']: + args['state'] = args['state'].title() + else: + del args['state'] + + if self.has_changed(args, network_offering): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateNetworkOffering', **args) + network_offering = res['networkoffering'] + + return network_offering + + def get_result(self, network_offering): + super(AnsibleCloudStackNetworkOffering, self).get_result(network_offering) + if network_offering: + self.result['egress_default_policy'] = 'allow' if network_offering.get('egressdefaultpolicy') else 'deny' + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + state=dict(choices=['enabled', 'present', 'disabled', 'absent'], default='present'), + display_text=dict(), + guest_ip_type=dict(choices=['Shared', 'Isolated']), + name=dict(required=True), + supported_services=dict(type='list', elements='str', aliases=['supported_service'], choices=[ + 'Dns', + 'PortForwarding', + 'Dhcp', + 'SourceNat', + 'UserData', + 'Firewall', + 'StaticNat', + 'Vpn', + 'Lb', + ]), + traffic_type=dict(default='Guest'), + availability=dict(), + conserve_mode=dict(type='bool'), + details=dict(type='list', elements='dict'), + egress_default_policy=dict(choices=['allow', 'deny']), + persistent=dict(type='bool'), + keepalive_enabled=dict(type='bool'), + max_connections=dict(type='int'), + network_rate=dict(type='int'), + service_capabilities=dict(type='list', elements='str', aliases=['service_capability']), + service_offering=dict(), + service_providers=dict(type='list', elements='dict', aliases=['service_provider']), + specify_ip_ranges=dict(type='bool'), + specify_vlan=dict(type='bool'), + for_vpc=dict(type='bool'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_network_offering = AnsibleCloudStackNetworkOffering(module) + + state = module.params.get('state') + if state in ['absent']: + network_offering = acs_network_offering.delete_network_offering() + else: + network_offering = acs_network_offering.create_or_update() + + result = acs_network_offering.get_result(network_offering) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py new file mode 100644 index 00000000..2148afc2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_physical_network.py @@ -0,0 +1,473 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, Netservers Ltd. <support@netservers.co.uk> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_physical_network +short_description: Manages physical networks on Apache CloudStack based clouds. +description: + - Create, update and remove networks. + - Enabled and disabled Network Service Providers + - Enables Internal LoadBalancer and VPC/VirtualRouter elements as required +author: + - Netservers Ltd. (@netservers) + - Patryk Cichy (@PatTheSilent) +version_added: 0.1.0 +options: + name: + description: + - Name of the physical network. + required: true + aliases: + - physical_network + type: str + zone: + description: + - Name of the zone in which the network belongs. + - If not set, default zone is used. + type: str + broadcast_domain_range: + description: + - broadcast domain range for the physical network[Pod or Zone]. + choices: [ POD, ZONE ] + type: str + domain: + description: + - Domain the network is owned by. + type: str + isolation_method: + description: + - Isolation method for the physical network. + choices: [ VLAN, GRE, L3 ] + type: str + network_speed: + description: + - The speed for the physical network. + choices: [1G, 10G] + type: str + tags: + description: + - A tag to identify this network. + - Physical networks support only one tag. + - To remove an existing tag pass an empty string. + aliases: + - tag + type: str + vlan: + description: + - The VLAN/VNI Ranges of the physical network. + type: str + nsps_enabled: + description: + - List of Network Service Providers to enable. + type: list + elements: str + nsps_disabled: + description: + - List of Network Service Providers to disable. + type: list + elements: str + state: + description: + - State of the physical network. + default: present + type: str + choices: [ present, absent, disabled, enabled ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a network is present + ngine_io.cloudstack.cs_physical_network: + name: net01 + zone: zone01 + isolation_method: VLAN + broadcast_domain_range: ZONE + +- name: Set a tag on a network + ngine_io.cloudstack.cs_physical_network: + name: net01 + tag: overlay + +- name: Remove tag on a network + ngine_io.cloudstack.cs_physical_network: + name: net01 + tag: "" + +- name: Ensure a network is enabled with specific nsps enabled + ngine_io.cloudstack.cs_physical_network: + name: net01 + zone: zone01 + isolation_method: VLAN + vlan: 100-200,300-400 + broadcast_domain_range: ZONE + state: enabled + nsps_enabled: + - virtualrouter + - internallbvm + - vpcvirtualrouter + +- name: Ensure a network is disabled + ngine_io.cloudstack.cs_physical_network: + name: net01 + zone: zone01 + state: disabled + +- name: Ensure a network is enabled + ngine_io.cloudstack.cs_physical_network: + name: net01 + zone: zone01 + state: enabled + +- name: Ensure a network is absent + ngine_io.cloudstack.cs_physical_network: + name: net01 + zone: zone01 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the network. + returned: success + type: str + sample: 3f8f25cd-c498-443f-9058-438cfbcbff50 +name: + description: Name of the network. + returned: success + type: str + sample: net01 +state: + description: State of the network [Enabled/Disabled]. + returned: success + type: str + sample: Enabled +broadcast_domain_range: + description: broadcastdomainrange of the network [POD / ZONE]. + returned: success + type: str + sample: ZONE +isolation_method: + description: isolationmethod of the network [VLAN/GRE/L3]. + returned: success + type: str + sample: VLAN +network_speed: + description: networkspeed of the network [1G/10G]. + returned: success + type: str + sample: 1G +zone: + description: Name of zone the physical network is in. + returned: success + type: str + sample: ch-gva-2 +domain: + description: Name of domain the network is in. + returned: success + type: str + sample: domain1 +nsps: + description: list of enabled or disabled Network Service Providers + type: complex + returned: on enabling/disabling of Network Service Providers + contains: + enabled: + description: list of Network Service Providers that were enabled + returned: on Network Service Provider enabling + type: list + sample: + - virtualrouter + disabled: + description: list of Network Service Providers that were disabled + returned: on Network Service Provider disabling + type: list + sample: + - internallbvm +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackPhysicalNetwork(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackPhysicalNetwork, self).__init__(module) + self.returns = { + 'isolationmethods': 'isolation_method', + 'broadcastdomainrange': 'broadcast_domain_range', + 'networkspeed': 'network_speed', + 'vlan': 'vlan', + 'tags': 'tags', + } + self.nsps = [] + self.vrouters = None + self.loadbalancers = None + + def _get_common_args(self): + args = { + 'name': self.module.params.get('name'), + 'isolationmethods': self.module.params.get('isolation_method'), + 'broadcastdomainrange': self.module.params.get('broadcast_domain_range'), + 'networkspeed': self.module.params.get('network_speed'), + 'tags': self.module.params.get('tags'), + 'vlan': self.module.params.get('vlan'), + } + + state = self.module.params.get('state') + if state in ['enabled', 'disabled']: + args['state'] = state.capitalize() + return args + + def get_physical_network(self, key=None): + physical_network = self.module.params.get('name') + if self.physical_network: + return self._get_by_key(key, self.physical_network) + + args = { + 'zoneid': self.get_zone(key='id') + } + physical_networks = self.query_api('listPhysicalNetworks', **args) + if physical_networks: + for net in physical_networks['physicalnetwork']: + if physical_network.lower() in [net['name'].lower(), net['id']]: + self.physical_network = net + self.result['physical_network'] = net['name'] + break + + return self._get_by_key(key, self.physical_network) + + def get_nsp(self, name=None): + if not self.nsps: + args = { + 'physicalnetworkid': self.get_physical_network(key='id') + } + res = self.query_api('listNetworkServiceProviders', **args) + + self.nsps = res['networkserviceprovider'] + + names = [] + for nsp in self.nsps: + names.append(nsp['name']) + if nsp['name'].lower() == name.lower(): + return nsp + + self.module.fail_json(msg="Failed: '{0}' not in network service providers list '[{1}]'".format(name, names)) + + def update_nsp(self, name=None, state=None, service_list=None): + nsp = self.get_nsp(name) + if not service_list and nsp['state'] == state: + return nsp + + args = { + 'id': nsp['id'], + 'servicelist': service_list, + 'state': state + } + if not self.module.check_mode: + res = self.query_api('updateNetworkServiceProvider', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + nsp = self.poll_job(res, 'networkserviceprovider') + + self.result['changed'] = True + return nsp + + def get_vrouter_element(self, nsp_name='virtualrouter'): + nsp = self.get_nsp(nsp_name) + nspid = nsp['id'] + if self.vrouters is None: + self.vrouters = dict() + res = self.query_api('listVirtualRouterElements', ) + for vrouter in res['virtualrouterelement']: + self.vrouters[vrouter['nspid']] = vrouter + + if nspid not in self.vrouters: + self.module.fail_json(msg="Failed: No VirtualRouterElement found for nsp '%s'" % nsp_name) + + return self.vrouters[nspid] + + def get_loadbalancer_element(self, nsp_name='internallbvm'): + nsp = self.get_nsp(nsp_name) + nspid = nsp['id'] + if self.loadbalancers is None: + self.loadbalancers = dict() + res = self.query_api('listInternalLoadBalancerElements', ) + for loadbalancer in res['internalloadbalancerelement']: + self.loadbalancers[loadbalancer['nspid']] = loadbalancer + + if nspid not in self.loadbalancers: + self.module.fail_json(msg="Failed: No Loadbalancer found for nsp '%s'" % nsp_name) + + return self.loadbalancers[nspid] + + def set_vrouter_element_state(self, enabled, nsp_name='virtualrouter'): + vrouter = self.get_vrouter_element(nsp_name) + if vrouter['enabled'] == enabled: + return vrouter + + args = { + 'id': vrouter['id'], + 'enabled': enabled + } + if not self.module.check_mode: + res = self.query_api('configureVirtualRouterElement', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vrouter = self.poll_job(res, 'virtualrouterelement') + + self.result['changed'] = True + return vrouter + + def set_loadbalancer_element_state(self, enabled, nsp_name='internallbvm'): + loadbalancer = self.get_loadbalancer_element(nsp_name=nsp_name) + if loadbalancer['enabled'] == enabled: + return loadbalancer + + args = { + 'id': loadbalancer['id'], + 'enabled': enabled + } + if not self.module.check_mode: + res = self.query_api('configureInternalLoadBalancerElement', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + loadbalancer = self.poll_job(res, 'internalloadbalancerelement') + + self.result['changed'] = True + return loadbalancer + + def present_network(self): + network = self.get_physical_network() + if network: + network = self._update_network() + else: + network = self._create_network() + return network + + def _create_network(self): + self.result['changed'] = True + args = dict(zoneid=self.get_zone(key='id')) + args.update(self._get_common_args()) + if self.get_domain(key='id'): + args['domainid'] = self.get_domain(key='id') + + if not self.module.check_mode: + resource = self.query_api('createPhysicalNetwork', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.network = self.poll_job(resource, 'physicalnetwork') + + return self.network + + def _update_network(self): + network = self.get_physical_network() + + args = dict(id=network['id']) + args.update(self._get_common_args()) + + if self.has_changed(args, network): + self.result['changed'] = True + + if not self.module.check_mode: + resource = self.query_api('updatePhysicalNetwork', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.physical_network = self.poll_job(resource, 'physicalnetwork') + return self.physical_network + + def absent_network(self): + physical_network = self.get_physical_network() + if physical_network: + self.result['changed'] = True + args = { + 'id': physical_network['id'], + } + if not self.module.check_mode: + resource = self.query_api('deletePhysicalNetwork', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(resource, 'success') + + return physical_network + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True, aliases=['physical_network']), + zone=dict(), + domain=dict(), + vlan=dict(), + nsps_disabled=dict(type='list', elements='str'), + nsps_enabled=dict(type='list', elements='str'), + network_speed=dict(choices=['1G', '10G']), + broadcast_domain_range=dict(choices=['POD', 'ZONE']), + isolation_method=dict(choices=['VLAN', 'GRE', 'L3']), + state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'), + tags=dict(aliases=['tag']), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_network = AnsibleCloudStackPhysicalNetwork(module) + state = module.params.get('state') + nsps_disabled = module.params.get('nsps_disabled', []) + nsps_enabled = module.params.get('nsps_enabled', []) + + if state in ['absent']: + network = acs_network.absent_network() + else: + network = acs_network.present_network() + if nsps_disabled is not None: + for name in nsps_disabled: + acs_network.update_nsp(name=name, state='Disabled') + + if nsps_enabled is not None: + for nsp_name in nsps_enabled: + if nsp_name.lower() in ['virtualrouter', 'vpcvirtualrouter']: + acs_network.set_vrouter_element_state(enabled=True, nsp_name=nsp_name) + elif nsp_name.lower() == 'internallbvm': + acs_network.set_loadbalancer_element_state(enabled=True, nsp_name=nsp_name) + + acs_network.update_nsp(name=nsp_name, state='Enabled') + + result = acs_network.get_result(network) + + if nsps_enabled: + result['nsps_enabled'] = nsps_enabled + if nsps_disabled: + result['nsps_disabled'] = nsps_disabled + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py new file mode 100644 index 00000000..90ab2ef5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_pod.py @@ -0,0 +1,289 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_pod +short_description: Manages pods on Apache CloudStack based clouds. +description: + - Create, update, delete pods. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the pod. + type: str + required: true + id: + description: + - uuid of the existing pod. + type: str + start_ip: + description: + - Starting IP address for the Pod. + - Required on I(state=present) + type: str + end_ip: + description: + - Ending IP address for the Pod. + type: str + netmask: + description: + - Netmask for the Pod. + - Required on I(state=present) + type: str + gateway: + description: + - Gateway for the Pod. + - Required on I(state=present) + type: str + zone: + description: + - Name of the zone in which the pod belongs to. + - If not set, default zone is used. + type: str + state: + description: + - State of the pod. + type: str + default: present + choices: [ present, enabled, disabled, absent ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a pod is present + ngine_io.cloudstack.cs_pod: + name: pod1 + zone: ch-zrh-ix-01 + start_ip: 10.100.10.101 + gateway: 10.100.10.1 + netmask: 255.255.255.0 + +- name: Ensure a pod is disabled + ngine_io.cloudstack.cs_pod: + name: pod1 + zone: ch-zrh-ix-01 + state: disabled + +- name: Ensure a pod is enabled + ngine_io.cloudstack.cs_pod: + name: pod1 + zone: ch-zrh-ix-01 + state: enabled + +- name: Ensure a pod is absent + ngine_io.cloudstack.cs_pod: + name: pod1 + zone: ch-zrh-ix-01 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the pod. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the pod. + returned: success + type: str + sample: pod01 +start_ip: + description: Starting IP of the pod. + returned: success + type: str + sample: 10.100.1.101 +end_ip: + description: Ending IP of the pod. + returned: success + type: str + sample: 10.100.1.254 +netmask: + description: Netmask of the pod. + returned: success + type: str + sample: 255.255.255.0 +gateway: + description: Gateway of the pod. + returned: success + type: str + sample: 10.100.1.1 +allocation_state: + description: State of the pod. + returned: success + type: str + sample: Enabled +zone: + description: Name of zone the pod is in. + returned: success + type: str + sample: ch-gva-2 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackPod(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackPod, self).__init__(module) + self.returns = { + 'endip': 'end_ip', + 'startip': 'start_ip', + 'gateway': 'gateway', + 'netmask': 'netmask', + 'allocationstate': 'allocation_state', + } + self.pod = None + + def _get_common_pod_args(self): + args = { + 'name': self.module.params.get('name'), + 'zoneid': self.get_zone(key='id'), + 'startip': self.module.params.get('start_ip'), + 'endip': self.module.params.get('end_ip'), + 'netmask': self.module.params.get('netmask'), + 'gateway': self.module.params.get('gateway') + } + state = self.module.params.get('state') + if state in ['enabled', 'disabled']: + args['allocationstate'] = state.capitalize() + return args + + def get_pod(self): + if not self.pod: + args = { + 'zoneid': self.get_zone(key='id') + } + + uuid = self.module.params.get('id') + if uuid: + args['id'] = uuid + else: + args['name'] = self.module.params.get('name') + + pods = self.query_api('listPods', **args) + if pods: + for pod in pods['pod']: + if not args['name']: + self.pod = self._transform_ip_list(pod) + break + elif args['name'] == pod['name']: + self.pod = self._transform_ip_list(pod) + break + return self.pod + + def present_pod(self): + pod = self.get_pod() + if pod: + pod = self._update_pod() + else: + pod = self._create_pod() + return pod + + def _create_pod(self): + required_params = [ + 'start_ip', + 'netmask', + 'gateway', + ] + self.module.fail_on_missing_params(required_params=required_params) + + pod = None + self.result['changed'] = True + args = self._get_common_pod_args() + if not self.module.check_mode: + res = self.query_api('createPod', **args) + pod = res['pod'] + return pod + + def _update_pod(self): + pod = self.get_pod() + args = self._get_common_pod_args() + args['id'] = pod['id'] + + if self.has_changed(args, pod): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updatePod', **args) + pod = res['pod'] + return pod + + def absent_pod(self): + pod = self.get_pod() + if pod: + self.result['changed'] = True + + args = { + 'id': pod['id'] + } + if not self.module.check_mode: + self.query_api('deletePod', **args) + return pod + + def _transform_ip_list(self, resource): + """ Workaround for 4.11 return API break """ + keys = ['endip', 'startip'] + if resource: + for key in keys: + if key in resource and isinstance(resource[key], list): + resource[key] = resource[key][0] + return resource + + def get_result(self, pod): + pod = self._transform_ip_list(pod) + super(AnsibleCloudStackPod, self).get_result(pod) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + id=dict(), + name=dict(required=True), + gateway=dict(), + netmask=dict(), + start_ip=dict(), + end_ip=dict(), + zone=dict(), + state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_pod = AnsibleCloudStackPod(module) + state = module.params.get('state') + if state in ['absent']: + pod = acs_pod.absent_pod() + else: + pod = acs_pod.present_pod() + + result = acs_pod.get_result(pod) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py new file mode 100644 index 00000000..3c80ccbb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_portforward.py @@ -0,0 +1,398 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_portforward +short_description: Manages port forwarding rules on Apache CloudStack based clouds. +description: + - Create, update and remove port forwarding rules. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + ip_address: + description: + - Public IP address the rule is assigned to. + type: str + required: true + vm: + description: + - Name of virtual machine which we make the port forwarding rule for. + - Required if I(state=present). + type: str + state: + description: + - State of the port forwarding rule. + type: str + default: present + choices: [ present, absent ] + protocol: + description: + - Protocol of the port forwarding rule. + type: str + default: tcp + choices: [ tcp, udp ] + public_port: + description: + - Start public port for this rule. + type: int + required: true + public_end_port: + description: + - End public port for this rule. + - If not specified equal I(public_port). + type: int + private_port: + description: + - Start private port for this rule. + type: int + required: true + private_end_port: + description: + - End private port for this rule. + - If not specified equal I(private_port). + type: int + open_firewall: + description: + - Whether the firewall rule for public port should be created, while creating the new rule. + - Not supported when forwarding ports in a VPC. + - Use M(cs_firewall) for managing firewall rules. + default: no + type: bool + vm_guest_ip: + description: + - VM guest NIC secondary IP address for the port forwarding rule. + type: str + network: + description: + - Name of the network. Required when forwarding ports in a VPC. + type: str + vpc: + description: + - Name of the VPC. + type: str + domain: + description: + - Domain the I(vm) is related to. + type: str + account: + description: + - Account the I(vm) is related to. + type: str + project: + description: + - Name of the project the I(vm) is located in. + type: str + zone: + description: + - Name of the zone in which the virtual machine is in. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: 1.2.3.4:80 -> web01:8080 + ngine_io.cloudstack.cs_portforward: + ip_address: 1.2.3.4 + vm: web01 + public_port: 80 + private_port: 8080 + +- name: forward SSH and open firewall + ngine_io.cloudstack.cs_portforward: + ip_address: '{{ public_ip }}' + vm: '{{ inventory_hostname }}' + public_port: '{{ ansible_ssh_port }}' + private_port: 22 + open_firewall: true + +- name: forward DNS traffic, but do not open firewall + ngine_io.cloudstack.cs_portforward: + ip_address: 1.2.3.4 + vm: '{{ inventory_hostname }}' + public_port: 53 + private_port: 53 + protocol: udp + +- name: remove ssh port forwarding + ngine_io.cloudstack.cs_portforward: + ip_address: 1.2.3.4 + public_port: 22 + private_port: 22 + state: absent + +- name: forward SSH in backend tier of VPC + ngine_io.cloudstack.cs_portforward: + ip_address: '{{ public_ip }}' + vm: '{{ inventory_hostname }}' + public_port: '{{ ansible_ssh_port }}' + private_port: 22 + vpc: myVPC + network: backend +''' + +RETURN = ''' +--- +id: + description: UUID of the public IP address. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +ip_address: + description: Public IP address. + returned: success + type: str + sample: 1.2.3.4 +protocol: + description: Protocol. + returned: success + type: str + sample: tcp +private_port: + description: Start port on the virtual machine's IP address. + returned: success + type: int + sample: 80 +private_end_port: + description: End port on the virtual machine's IP address. + returned: success + type: int + sample: 80 +public_port: + description: Start port on the public IP address. + returned: success + type: int + sample: 80 +public_end_port: + description: End port on the public IP address. + returned: success + type: int + sample: 80 +tags: + description: Tags related to the port forwarding. + returned: success + type: list + sample: [] +vm_name: + description: Name of the virtual machine. + returned: success + type: str + sample: web-01 +vm_display_name: + description: Display name of the virtual machine. + returned: success + type: str + sample: web-01 +vm_guest_ip: + description: IP of the virtual machine. + returned: success + type: str + sample: 10.101.65.152 +vpc: + description: Name of the VPC. + returned: success + type: str + sample: my_vpc +network: + description: Name of the network. + returned: success + type: str + sample: dmz +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together + + +class AnsibleCloudStackPortforwarding(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackPortforwarding, self).__init__(module) + self.returns = { + 'virtualmachinedisplayname': 'vm_display_name', + 'virtualmachinename': 'vm_name', + 'ipaddress': 'ip_address', + 'vmguestip': 'vm_guest_ip', + 'publicip': 'public_ip', + 'protocol': 'protocol', + } + # these values will be casted to int + self.returns_to_int = { + 'publicport': 'public_port', + 'publicendport': 'public_end_port', + 'privateport': 'private_port', + 'privateendport': 'private_end_port', + } + self.portforwarding_rule = None + + def get_portforwarding_rule(self): + if not self.portforwarding_rule: + protocol = self.module.params.get('protocol') + public_port = self.module.params.get('public_port') + + args = { + 'ipaddressid': self.get_ip_address(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + } + portforwarding_rules = self.query_api('listPortForwardingRules', **args) + + if portforwarding_rules and 'portforwardingrule' in portforwarding_rules: + for rule in portforwarding_rules['portforwardingrule']: + if (protocol == rule['protocol'] and + public_port == int(rule['publicport'])): + self.portforwarding_rule = rule + break + return self.portforwarding_rule + + def present_portforwarding_rule(self): + portforwarding_rule = self.get_portforwarding_rule() + if portforwarding_rule: + portforwarding_rule = self.update_portforwarding_rule(portforwarding_rule) + else: + portforwarding_rule = self.create_portforwarding_rule() + + if portforwarding_rule: + portforwarding_rule = self.ensure_tags(resource=portforwarding_rule, resource_type='PortForwardingRule') + self.portforwarding_rule = portforwarding_rule + + return portforwarding_rule + + def create_portforwarding_rule(self): + args = { + 'protocol': self.module.params.get('protocol'), + 'publicport': self.module.params.get('public_port'), + 'publicendport': self.get_or_fallback('public_end_port', 'public_port'), + 'privateport': self.module.params.get('private_port'), + 'privateendport': self.get_or_fallback('private_end_port', 'private_port'), + 'openfirewall': self.module.params.get('open_firewall'), + 'vmguestip': self.get_vm_guest_ip(), + 'ipaddressid': self.get_ip_address(key='id'), + 'virtualmachineid': self.get_vm(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'networkid': self.get_network(key='id'), + } + + portforwarding_rule = None + self.result['changed'] = True + if not self.module.check_mode: + portforwarding_rule = self.query_api('createPortForwardingRule', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + portforwarding_rule = self.poll_job(portforwarding_rule, 'portforwardingrule') + return portforwarding_rule + + def update_portforwarding_rule(self, portforwarding_rule): + args = { + 'protocol': self.module.params.get('protocol'), + 'publicport': self.module.params.get('public_port'), + 'publicendport': self.get_or_fallback('public_end_port', 'public_port'), + 'privateport': self.module.params.get('private_port'), + 'privateendport': self.get_or_fallback('private_end_port', 'private_port'), + 'vmguestip': self.get_vm_guest_ip(), + 'ipaddressid': self.get_ip_address(key='id'), + 'virtualmachineid': self.get_vm(key='id'), + 'networkid': self.get_network(key='id'), + } + + if self.has_changed(args, portforwarding_rule): + self.result['changed'] = True + if not self.module.check_mode: + # API broken in 4.2.1?, workaround using remove/create instead of update + # portforwarding_rule = self.query_api('updatePortForwardingRule', **args) + self.absent_portforwarding_rule() + portforwarding_rule = self.query_api('createPortForwardingRule', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + portforwarding_rule = self.poll_job(portforwarding_rule, 'portforwardingrule') + return portforwarding_rule + + def absent_portforwarding_rule(self): + portforwarding_rule = self.get_portforwarding_rule() + + if portforwarding_rule: + self.result['changed'] = True + args = { + 'id': portforwarding_rule['id'], + } + if not self.module.check_mode: + res = self.query_api('deletePortForwardingRule', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'portforwardingrule') + return portforwarding_rule + + def get_result(self, portforwarding_rule): + super(AnsibleCloudStackPortforwarding, self).get_result(portforwarding_rule) + if portforwarding_rule: + for search_key, return_key in self.returns_to_int.items(): + if search_key in portforwarding_rule: + self.result[return_key] = int(portforwarding_rule[search_key]) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + ip_address=dict(required=True), + protocol=dict(choices=['tcp', 'udp'], default='tcp'), + public_port=dict(type='int', required=True), + public_end_port=dict(type='int'), + private_port=dict(type='int', required=True), + private_end_port=dict(type='int'), + state=dict(choices=['present', 'absent'], default='present'), + open_firewall=dict(type='bool', default=False), + vm_guest_ip=dict(), + vm=dict(), + vpc=dict(), + network=dict(), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_pf = AnsibleCloudStackPortforwarding(module) + state = module.params.get('state') + if state in ['absent']: + pf_rule = acs_pf.absent_portforwarding_rule() + else: + pf_rule = acs_pf.present_portforwarding_rule() + + result = acs_pf.get_result(pf_rule) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py new file mode 100644 index 00000000..c52444ed --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_project.py @@ -0,0 +1,271 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_project +short_description: Manages projects on Apache CloudStack based clouds. +description: + - Create, update, suspend, activate and remove projects. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the project. + type: str + required: true + display_text: + description: + - Display text of the project. + - If not specified, I(name) will be used as I(display_text). + type: str + state: + description: + - State of the project. + type: str + default: present + choices: [ present, absent, active, suspended ] + domain: + description: + - Domain the project is related to. + type: str + account: + description: + - Account the project is related to. + type: str + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "If you want to delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a project + ngine_io.cloudstack.cs_project: + name: web + tags: + - { key: admin, value: john } + - { key: foo, value: bar } + +- name: Rename a project + ngine_io.cloudstack.cs_project: + name: web + display_text: my web project + +- name: Suspend an existing project + ngine_io.cloudstack.cs_project: + name: web + state: suspended + +- name: Activate an existing project + ngine_io.cloudstack.cs_project: + name: web + state: active + +- name: Remove a project + ngine_io.cloudstack.cs_project: + name: web + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the project. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the project. + returned: success + type: str + sample: web project +display_text: + description: Display text of the project. + returned: success + type: str + sample: web project +state: + description: State of the project. + returned: success + type: str + sample: Active +domain: + description: Domain the project is related to. + returned: success + type: str + sample: example domain +account: + description: Account the project is related to. + returned: success + type: str + sample: example account +tags: + description: List of resource tags associated with the project. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackProject(AnsibleCloudStack): + + def get_project(self): + if not self.project: + project = self.module.params.get('name') + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'fetch_list': True, + } + projects = self.query_api('listProjects', **args) + if projects: + for p in projects: + if project.lower() in [p['name'].lower(), p['id']]: + self.project = p + break + return self.project + + def present_project(self): + project = self.get_project() + if not project: + project = self.create_project(project) + else: + project = self.update_project(project) + if project: + project = self.ensure_tags(resource=project, resource_type='project') + # refresh resource + self.project = project + return project + + def update_project(self, project): + args = { + 'id': project['id'], + 'displaytext': self.get_or_fallback('display_text', 'name') + } + if self.has_changed(args, project): + self.result['changed'] = True + if not self.module.check_mode: + project = self.query_api('updateProject', **args) + + poll_async = self.module.params.get('poll_async') + if project and poll_async: + project = self.poll_job(project, 'project') + return project + + def create_project(self, project): + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'account': self.get_account('name'), + 'domainid': self.get_domain('id') + } + if not self.module.check_mode: + project = self.query_api('createProject', **args) + + poll_async = self.module.params.get('poll_async') + if project and poll_async: + project = self.poll_job(project, 'project') + return project + + def state_project(self, state='active'): + project = self.present_project() + + if project['state'].lower() != state: + self.result['changed'] = True + + args = { + 'id': project['id'] + } + if not self.module.check_mode: + if state == 'suspended': + project = self.query_api('suspendProject', **args) + else: + project = self.query_api('activateProject', **args) + + poll_async = self.module.params.get('poll_async') + if project and poll_async: + project = self.poll_job(project, 'project') + return project + + def absent_project(self): + project = self.get_project() + if project: + self.result['changed'] = True + + args = { + 'id': project['id'] + } + if not self.module.check_mode: + res = self.query_api('deleteProject', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + res = self.poll_job(res, 'project') + return project + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + state=dict(choices=['present', 'absent', 'active', 'suspended'], default='present'), + domain=dict(), + account=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_project = AnsibleCloudStackProject(module) + + state = module.params.get('state') + if state in ['absent']: + project = acs_project.absent_project() + + elif state in ['active', 'suspended']: + project = acs_project.state_project(state=state) + + else: + project = acs_project.present_project() + + result = acs_project.get_result(project) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py new file mode 100644 index 00000000..327f7c1e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_region.py @@ -0,0 +1,187 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_region +short_description: Manages regions on Apache CloudStack based clouds. +description: + - Add, update and remove regions. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + id: + description: + - ID of the region. + - Must be an number (int). + type: int + required: true + name: + description: + - Name of the region. + - Required if I(state=present) + type: str + endpoint: + description: + - Endpoint URL of the region. + - Required if I(state=present) + type: str + state: + description: + - State of the region. + type: str + default: present + choices: [ present, absent ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a region + ngine_io.cloudstack.cs_region: + id: 2 + name: geneva + endpoint: https://cloud.gva.example.com + +- name: remove a region with ID 2 + ngine_io.cloudstack.cs_region: + id: 2 + state: absent +''' + +RETURN = ''' +--- +id: + description: ID of the region. + returned: success + type: int + sample: 1 +name: + description: Name of the region. + returned: success + type: str + sample: local +endpoint: + description: Endpoint of the region. + returned: success + type: str + sample: http://cloud.example.com +gslb_service_enabled: + description: Whether the GSLB service is enabled or not. + returned: success + type: bool + sample: true +portable_ip_service_enabled: + description: Whether the portable IP service is enabled or not. + returned: success + type: bool + sample: true +''' + + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackRegion(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackRegion, self).__init__(module) + self.returns = { + 'endpoint': 'endpoint', + 'gslbserviceenabled': 'gslb_service_enabled', + 'portableipserviceenabled': 'portable_ip_service_enabled', + } + + def get_region(self): + id = self.module.params.get('id') + regions = self.query_api('listRegions', id=id) + if regions: + return regions['region'][0] + return None + + def present_region(self): + region = self.get_region() + if not region: + region = self._create_region(region=region) + else: + region = self._update_region(region=region) + return region + + def _create_region(self, region): + self.result['changed'] = True + args = { + 'id': self.module.params.get('id'), + 'name': self.module.params.get('name'), + 'endpoint': self.module.params.get('endpoint') + } + if not self.module.check_mode: + res = self.query_api('addRegion', **args) + region = res['region'] + return region + + def _update_region(self, region): + args = { + 'id': self.module.params.get('id'), + 'name': self.module.params.get('name'), + 'endpoint': self.module.params.get('endpoint') + } + if self.has_changed(args, region): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateRegion', **args) + region = res['region'] + return region + + def absent_region(self): + region = self.get_region() + if region: + self.result['changed'] = True + if not self.module.check_mode: + self.query_api('removeRegion', id=region['id']) + return region + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + id=dict(required=True, type='int'), + name=dict(), + endpoint=dict(), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + required_if=[ + ('state', 'present', ['name', 'endpoint']), + ], + supports_check_mode=True + ) + + acs_region = AnsibleCloudStackRegion(module) + + state = module.params.get('state') + if state == 'absent': + region = acs_region.absent_region() + else: + region = acs_region.present_region() + + result = acs_region.get_result(region) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py new file mode 100644 index 00000000..fdca3bdd --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_resourcelimit.py @@ -0,0 +1,202 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_resourcelimit +short_description: Manages resource limits on Apache CloudStack based clouds. +description: + - Manage limits of resources for domains, accounts and projects. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + resource_type: + description: + - Type of the resource. + type: str + required: true + choices: + - instance + - ip_address + - volume + - snapshot + - template + - network + - vpc + - cpu + - memory + - primary_storage + - secondary_storage + aliases: [ type ] + limit: + description: + - Maximum number of the resource. + - Default is unlimited C(-1). + type: int + default: -1 + aliases: [ max ] + domain: + description: + - Domain the resource is related to. + type: str + account: + description: + - Account the resource is related to. + type: str + project: + description: + - Name of the project the resource is related to. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Update a resource limit for instances of a domain + ngine_io.cloudstack.cs_resourcelimit: + type: instance + limit: 10 + domain: customers + +- name: Update a resource limit for instances of an account + ngine_io.cloudstack.cs_resourcelimit: + type: instance + limit: 12 + account: moserre + domain: customers +''' + +RETURN = ''' +--- +recource_type: + description: Type of the resource + returned: success + type: str + sample: instance +limit: + description: Maximum number of the resource. + returned: success + type: int + sample: -1 +domain: + description: Domain the resource is related to. + returned: success + type: str + sample: example domain +account: + description: Account the resource is related to. + returned: success + type: str + sample: example account +project: + description: Project the resource is related to. + returned: success + type: str + sample: example project +''' + +# import cloudstack common +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_required_together, + cs_argument_spec +) + + +RESOURCE_TYPES = { + 'instance': 0, + 'ip_address': 1, + 'volume': 2, + 'snapshot': 3, + 'template': 4, + 'network': 6, + 'vpc': 7, + 'cpu': 8, + 'memory': 9, + 'primary_storage': 10, + 'secondary_storage': 11, +} + + +class AnsibleCloudStackResourceLimit(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackResourceLimit, self).__init__(module) + self.returns = { + 'max': 'limit', + } + + def get_resource_type(self): + resource_type = self.module.params.get('resource_type') + return RESOURCE_TYPES.get(resource_type) + + def get_resource_limit(self): + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'resourcetype': self.get_resource_type() + } + resource_limit = self.query_api('listResourceLimits', **args) + if resource_limit: + if 'limit' in resource_limit['resourcelimit'][0]: + resource_limit['resourcelimit'][0]['limit'] = int(resource_limit['resourcelimit'][0]) + return resource_limit['resourcelimit'][0] + self.module.fail_json(msg="Resource limit type '%s' not found." % self.module.params.get('resource_type')) + + def update_resource_limit(self): + resource_limit = self.get_resource_limit() + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'resourcetype': self.get_resource_type(), + 'max': self.module.params.get('limit', -1) + } + + if self.has_changed(args, resource_limit): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateResourceLimit', **args) + resource_limit = res['resourcelimit'] + return resource_limit + + def get_result(self, resource_limit): + self.result = super(AnsibleCloudStackResourceLimit, self).get_result(resource_limit) + self.result['resource_type'] = self.module.params.get('resource_type') + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + resource_type=dict(required=True, choices=list(RESOURCE_TYPES.keys()), aliases=['type']), + limit=dict(default=-1, aliases=['max'], type='int'), + domain=dict(), + account=dict(), + project=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_resource_limit = AnsibleCloudStackResourceLimit(module) + resource_limit = acs_resource_limit.update_resource_limit() + result = acs_resource_limit.get_result(resource_limit) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py new file mode 100644 index 00000000..01f23479 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role.py @@ -0,0 +1,205 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_role +short_description: Manages user roles on Apache CloudStack based clouds. +description: + - Create, update, delete user roles. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the role. + type: str + required: true + uuid: + description: + - ID of the role. + - If provided, I(uuid) is used as key. + type: str + aliases: [ id ] + role_type: + description: + - Type of the role. + - Only considered for creation. + type: str + default: User + choices: [ User, DomainAdmin, ResourceAdmin, Admin ] + description: + description: + - Description of the role. + type: str + state: + description: + - State of the role. + type: str + default: present + choices: [ present, absent ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure an user role is present + ngine_io.cloudstack.cs_role: + name: myrole_user + +- name: Ensure a role having particular ID is named as myrole_user + ngine_io.cloudstack.cs_role: + name: myrole_user + id: 04589590-ac63-4ffc-93f5-b698b8ac38b6 + +- name: Ensure a role is absent + ngine_io.cloudstack.cs_role: + name: myrole_user + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the role. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the role. + returned: success + type: str + sample: myrole +description: + description: Description of the role. + returned: success + type: str + sample: "This is my role description" +role_type: + description: Type of the role. + returned: success + type: str + sample: User +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackRole(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackRole, self).__init__(module) + self.returns = { + 'type': 'role_type', + } + + def get_role(self): + uuid = self.module.params.get('uuid') + if uuid: + args = { + 'id': uuid, + } + roles = self.query_api('listRoles', **args) + if roles: + return roles['role'][0] + else: + args = { + 'name': self.module.params.get('name'), + } + roles = self.query_api('listRoles', **args) + if roles: + return roles['role'][0] + return None + + def present_role(self): + role = self.get_role() + if role: + role = self._update_role(role) + else: + role = self._create_role(role) + return role + + def _create_role(self, role): + self.result['changed'] = True + args = { + 'name': self.module.params.get('name'), + 'type': self.module.params.get('role_type'), + 'description': self.module.params.get('description'), + } + if not self.module.check_mode: + res = self.query_api('createRole', **args) + role = res['role'] + return role + + def _update_role(self, role): + args = { + 'id': role['id'], + 'name': self.module.params.get('name'), + 'description': self.module.params.get('description'), + } + if self.has_changed(args, role): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateRole', **args) + + # The API as in 4.9 does not return an updated role yet + if 'role' not in res: + role = self.get_role() + else: + role = res['role'] + return role + + def absent_role(self): + role = self.get_role() + if role: + self.result['changed'] = True + args = { + 'id': role['id'], + } + if not self.module.check_mode: + self.query_api('deleteRole', **args) + return role + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + uuid=dict(aliases=['id']), + name=dict(required=True), + description=dict(), + role_type=dict(choices=['User', 'DomainAdmin', 'ResourceAdmin', 'Admin'], default='User'), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_role = AnsibleCloudStackRole(module) + state = module.params.get('state') + if state == 'absent': + role = acs_role.absent_role() + else: + role = acs_role.present_role() + + result = acs_role.get_result(role) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py new file mode 100644 index 00000000..8755f158 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_role_permission.py @@ -0,0 +1,345 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, David Passante (@dpassante) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_role_permission +short_description: Manages role permissions on Apache CloudStack based clouds. +description: + - Create, update and remove CloudStack role permissions. + - Managing role permissions only supported in CloudStack >= 4.9. +author: David Passante (@dpassante) +version_added: 0.1.0 +options: + name: + description: + - The API name of the permission. + type: str + required: true + role: + description: + - Name or ID of the role. + type: str + required: true + permission: + description: + - The rule permission, allow or deny. Defaulted to deny. + type: str + choices: [ allow, deny ] + default: deny + state: + description: + - State of the role permission. + type: str + choices: [ present, absent ] + default: present + description: + description: + - The description of the role permission. + type: str + parent: + description: + - The parent role permission uuid. use 0 to move this rule at the top of the list. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a role permission + ngine_io.cloudstack.cs_role_permission: + role: My_Custom_role + name: createVPC + permission: allow + description: My comments + +- name: Remove a role permission + ngine_io.cloudstack.cs_role_permission: + state: absent + role: My_Custom_role + name: createVPC + +- name: Update a system role permission + ngine_io.cloudstack.cs_role_permission: + role: Domain Admin + name: createVPC + permission: deny + +- name: Update rules order. Move the rule at the top of list + ngine_io.cloudstack.cs_role_permission: + role: Domain Admin + name: createVPC + parent: 0 +''' + +RETURN = ''' +--- +id: + description: The ID of the role permission. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: The API name of the permission. + returned: success + type: str + sample: createVPC +permission: + description: The permission type of the api name. + returned: success + type: str + sample: allow +role_id: + description: The ID of the role to which the role permission belongs. + returned: success + type: str + sample: c6f7a5fc-43f8-11e5-a151-feff819cdc7f +description: + description: The description of the role permission + returned: success + type: str + sample: Deny createVPC for users +''' + +from distutils.version import LooseVersion + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackRolePermission(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackRolePermission, self).__init__(module) + cloudstack_min_version = LooseVersion('4.9.2') + + self.returns = { + 'id': 'id', + 'roleid': 'role_id', + 'rule': 'name', + 'permission': 'permission', + 'description': 'description', + } + self.role_permission = None + + self.cloudstack_version = self._cloudstack_ver() + + if self.cloudstack_version < cloudstack_min_version: + self.fail_json(msg="This module requires CloudStack >= %s." % cloudstack_min_version) + + def _cloudstack_ver(self): + capabilities = self.get_capabilities() + return LooseVersion(capabilities['cloudstackversion']) + + def _get_role_id(self): + role = self.module.params.get('role') + if not role: + return None + + res = self.query_api('listRoles') + roles = res['role'] + if roles: + for r in roles: + if role in [r['name'], r['id']]: + return r['id'] + self.fail_json(msg="Role '%s' not found" % role) + + def _get_role_perm(self): + role_permission = self.role_permission + + args = { + 'roleid': self._get_role_id(), + } + + rp = self.query_api('listRolePermissions', **args) + + if rp: + role_permission = rp['rolepermission'] + + return role_permission + + def _get_rule(self, rule=None): + if not rule: + rule = self.module.params.get('name') + + if self._get_role_perm(): + for _rule in self._get_role_perm(): + if rule == _rule['rule'] or rule == _rule['id']: + return _rule + + return None + + def _get_rule_order(self): + perms = self._get_role_perm() + rules = [] + + if perms: + for i, rule in enumerate(perms): + rules.append(rule['id']) + + return rules + + def replace_rule(self): + old_rule = self._get_rule() + + if old_rule: + rules_order = self._get_rule_order() + old_pos = rules_order.index(old_rule['id']) + + self.remove_role_perm() + + new_rule = self.create_role_perm() + + if new_rule: + perm_order = self.order_permissions(int(old_pos - 1), new_rule['id']) + + return perm_order + + return None + + def order_permissions(self, parent, rule_id): + rules = self._get_rule_order() + + if isinstance(parent, int): + parent_pos = parent + elif parent == '0': + parent_pos = -1 + else: + parent_rule = self._get_rule(parent) + if not parent_rule: + self.fail_json(msg="Parent rule '%s' not found" % parent) + + parent_pos = rules.index(parent_rule['id']) + + r_id = rules.pop(rules.index(rule_id)) + + rules.insert((parent_pos + 1), r_id) + rules = ','.join(map(str, rules)) + + return rules + + def create_or_update_role_perm(self): + role_permission = self._get_rule() + + if not role_permission: + role_permission = self.create_role_perm() + else: + role_permission = self.update_role_perm(role_permission) + + return role_permission + + def create_role_perm(self): + role_permission = None + + self.result['changed'] = True + + args = { + 'rule': self.module.params.get('name'), + 'description': self.module.params.get('description'), + 'roleid': self._get_role_id(), + 'permission': self.module.params.get('permission'), + } + + if not self.module.check_mode: + res = self.query_api('createRolePermission', **args) + role_permission = res['rolepermission'] + + return role_permission + + def update_role_perm(self, role_perm): + perm_order = None + + if not self.module.params.get('parent'): + args = { + 'ruleid': role_perm['id'], + 'roleid': role_perm['roleid'], + 'permission': self.module.params.get('permission'), + } + + if self.has_changed(args, role_perm, only_keys=['permission']): + self.result['changed'] = True + + if not self.module.check_mode: + if self.cloudstack_version >= LooseVersion('4.11.0'): + self.query_api('updateRolePermission', **args) + role_perm = self._get_rule() + else: + perm_order = self.replace_rule() + else: + perm_order = self.order_permissions(self.module.params.get('parent'), role_perm['id']) + + if perm_order: + args = { + 'roleid': role_perm['roleid'], + 'ruleorder': perm_order, + } + + self.result['changed'] = True + + if not self.module.check_mode: + self.query_api('updateRolePermission', **args) + role_perm = self._get_rule() + + return role_perm + + def remove_role_perm(self): + role_permission = self._get_rule() + + if role_permission: + self.result['changed'] = True + + args = { + 'id': role_permission['id'], + } + + if not self.module.check_mode: + self.query_api('deleteRolePermission', **args) + + return role_permission + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + role=dict(required=True), + name=dict(required=True), + permission=dict(choices=['allow', 'deny'], default='deny'), + description=dict(), + state=dict(choices=['present', 'absent'], default='present'), + parent=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['permission', 'parent'], + ), + supports_check_mode=True + ) + + acs_role_perm = AnsibleCloudStackRolePermission(module) + + state = module.params.get('state') + if state in ['absent']: + role_permission = acs_role_perm.remove_role_perm() + else: + role_permission = acs_role_perm.create_or_update_role_perm() + + result = acs_role_perm.get_result(role_permission) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py new file mode 100644 index 00000000..e14a7609 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_router.py @@ -0,0 +1,368 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_router +short_description: Manages routers on Apache CloudStack based clouds. +description: + - Start, restart, stop and destroy routers. + - I(state=present) is not able to create routers, use M(cs_network) instead. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the router. + type: str + required: true + service_offering: + description: + - Name or id of the service offering of the router. + type: str + domain: + description: + - Domain the router is related to. + type: str + account: + description: + - Account the router is related to. + type: str + project: + description: + - Name of the project the router is related to. + type: str + zone: + description: + - Name of the zone the router is deployed in. + - If not set, all zones are used. + type: str + state: + description: + - State of the router. + type: str + default: present + choices: [ present, absent, started, stopped, restarted ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +# Ensure the router has the desired service offering, no matter if +# the router is running or not. +- name: Present router + ngine_io.cloudstack.cs_router: + name: r-40-VM + service_offering: System Offering for Software Router + +- name: Ensure started + ngine_io.cloudstack.cs_router: + name: r-40-VM + state: started + +# Ensure started with desired service offering. +# If the service offerings changes, router will be rebooted. +- name: Ensure started with desired service offering + ngine_io.cloudstack.cs_router: + name: r-40-VM + service_offering: System Offering for Software Router + state: started + +- name: Ensure stopped + ngine_io.cloudstack.cs_router: + name: r-40-VM + state: stopped + +- name: Remove a router + ngine_io.cloudstack.cs_router: + name: r-40-VM + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the router. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the router. + returned: success + type: str + sample: r-40-VM +created: + description: Date of the router was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +template_version: + description: Version of the system VM template. + returned: success + type: str + sample: 4.5.1 +requires_upgrade: + description: Whether the router needs to be upgraded to the new template. + returned: success + type: bool + sample: false +redundant_state: + description: Redundant state of the router. + returned: success + type: str + sample: UNKNOWN +role: + description: Role of the router. + returned: success + type: str + sample: VIRTUAL_ROUTER +zone: + description: Name of zone the router is in. + returned: success + type: str + sample: ch-gva-2 +service_offering: + description: Name of the service offering the router has. + returned: success + type: str + sample: System Offering For Software Router +state: + description: State of the router. + returned: success + type: str + sample: Active +domain: + description: Domain the router is related to. + returned: success + type: str + sample: ROOT +account: + description: Account the router is related to. + returned: success + type: str + sample: admin +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackRouter(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackRouter, self).__init__(module) + self.returns = { + 'serviceofferingname': 'service_offering', + 'version': 'template_version', + 'requiresupgrade': 'requires_upgrade', + 'redundantstate': 'redundant_state', + 'role': 'role' + } + self.router = None + + def get_service_offering_id(self): + service_offering = self.module.params.get('service_offering') + if not service_offering: + return None + + args = { + 'issystem': True + } + + service_offerings = self.query_api('listServiceOfferings', **args) + if service_offerings: + for s in service_offerings['serviceoffering']: + if service_offering in [s['name'], s['id']]: + return s['id'] + self.module.fail_json(msg="Service offering '%s' not found" % service_offering) + + def get_router(self): + if not self.router: + router = self.module.params.get('name') + + args = { + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'listall': True, + 'fetch_list': True, + } + + if self.module.params.get('zone'): + args['zoneid'] = self.get_zone(key='id') + + routers = self.query_api('listRouters', **args) + if routers: + for r in routers: + if router.lower() in [r['name'].lower(), r['id']]: + self.router = r + break + return self.router + + def start_router(self): + router = self.get_router() + if not router: + self.module.fail_json(msg="Router not found") + + if router['state'].lower() != "running": + self.result['changed'] = True + + args = { + 'id': router['id'], + } + + if not self.module.check_mode: + res = self.query_api('startRouter', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + router = self.poll_job(res, 'router') + return router + + def stop_router(self): + router = self.get_router() + if not router: + self.module.fail_json(msg="Router not found") + + if router['state'].lower() != "stopped": + self.result['changed'] = True + + args = { + 'id': router['id'], + } + + if not self.module.check_mode: + res = self.query_api('stopRouter', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + router = self.poll_job(res, 'router') + return router + + def reboot_router(self): + router = self.get_router() + if not router: + self.module.fail_json(msg="Router not found") + + self.result['changed'] = True + + args = { + 'id': router['id'], + } + + if not self.module.check_mode: + res = self.query_api('rebootRouter', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + router = self.poll_job(res, 'router') + return router + + def absent_router(self): + router = self.get_router() + if router: + self.result['changed'] = True + + args = { + 'id': router['id'], + } + + if not self.module.check_mode: + res = self.query_api('destroyRouter', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'router') + return router + + def present_router(self): + router = self.get_router() + if not router: + self.module.fail_json(msg="Router can not be created using the API, see cs_network.") + + args = { + 'id': router['id'], + 'serviceofferingid': self.get_service_offering_id(), + } + + state = self.module.params.get('state') + + if self.has_changed(args, router): + self.result['changed'] = True + + if not self.module.check_mode: + current_state = router['state'].lower() + + self.stop_router() + router = self.query_api('changeServiceForRouter', **args) + + if state in ['restarted', 'started']: + router = self.start_router() + + # if state=present we get to the state before the service + # offering change. + elif state == "present" and current_state == "running": + router = self.start_router() + + elif state == "started": + router = self.start_router() + + elif state == "stopped": + router = self.stop_router() + + elif state == "restarted": + router = self.reboot_router() + + return router + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + service_offering=dict(), + state=dict(choices=['present', 'started', 'stopped', 'restarted', 'absent'], default="present"), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_router = AnsibleCloudStackRouter(module) + + state = module.params.get('state') + if state in ['absent']: + router = acs_router.absent_router() + else: + router = acs_router.present_router() + + result = acs_router.get_result(router) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py new file mode 100644 index 00000000..5d8ba2b9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup.py @@ -0,0 +1,193 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_securitygroup +short_description: Manages security groups on Apache CloudStack based clouds. +description: + - Create and remove security groups. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the security group. + type: str + required: true + description: + description: + - Description of the security group. + type: str + state: + description: + - State of the security group. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the security group is related to. + type: str + account: + description: + - Account the security group is related to. + type: str + project: + description: + - Name of the project the security group to be created in. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a security group + ngine_io.cloudstack.cs_securitygroup: + name: default + description: default security group + +- name: remove a security group + ngine_io.cloudstack.cs_securitygroup: + name: default + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the security group. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: Name of security group. + returned: success + type: str + sample: app +description: + description: Description of security group. + returned: success + type: str + sample: application security group +tags: + description: List of resource tags associated with the security group. + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +project: + description: Name of project the security group is related to. + returned: success + type: str + sample: Production +domain: + description: Domain the security group is related to. + returned: success + type: str + sample: example domain +account: + description: Account the security group is related to. + returned: success + type: str + sample: example account +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together + + +class AnsibleCloudStackSecurityGroup(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackSecurityGroup, self).__init__(module) + self.security_group = None + + def get_security_group(self): + if not self.security_group: + + args = { + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'securitygroupname': self.module.params.get('name'), + } + sgs = self.query_api('listSecurityGroups', **args) + if sgs: + self.security_group = sgs['securitygroup'][0] + return self.security_group + + def create_security_group(self): + security_group = self.get_security_group() + if not security_group: + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'description': self.module.params.get('description'), + } + + if not self.module.check_mode: + res = self.query_api('createSecurityGroup', **args) + security_group = res['securitygroup'] + + return security_group + + def remove_security_group(self): + security_group = self.get_security_group() + if security_group: + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + } + + if not self.module.check_mode: + self.query_api('deleteSecurityGroup', **args) + + return security_group + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + description=dict(), + state=dict(choices=['present', 'absent'], default='present'), + project=dict(), + account=dict(), + domain=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_sg = AnsibleCloudStackSecurityGroup(module) + + state = module.params.get('state') + if state in ['absent']: + sg = acs_sg.remove_security_group() + else: + sg = acs_sg.create_security_group() + + result = acs_sg.get_result(sg) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py new file mode 100644 index 00000000..2bd269e8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_securitygroup_rule.py @@ -0,0 +1,379 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_securitygroup_rule +short_description: Manages security group rules on Apache CloudStack based clouds. +description: + - Add and remove security group rules. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + security_group: + description: + - Name of the security group the rule is related to. The security group must be existing. + type: str + required: true + state: + description: + - State of the security group rule. + type: str + default: present + choices: [ present, absent ] + protocol: + description: + - Protocol of the security group rule. + type: str + default: tcp + choices: [ tcp, udp, icmp, ah, esp, gre ] + type: + description: + - Ingress or egress security group rule. + type: str + default: ingress + choices: [ ingress, egress ] + cidr: + description: + - CIDR (full notation) to be used for security group rule. + type: str + default: 0.0.0.0/0 + user_security_group: + description: + - Security group this rule is based of. + type: str + start_port: + description: + - Start port for this rule. Required if I(protocol=tcp) or I(protocol=udp). + type: int + aliases: [ port ] + end_port: + description: + - End port for this rule. Required if I(protocol=tcp) or I(protocol=udp), but I(start_port) will be used if not set. + type: int + icmp_type: + description: + - Type of the icmp message being sent. Required if I(protocol=icmp). + type: int + icmp_code: + description: + - Error code for this icmp message. Required if I(protocol=icmp). + type: int + project: + description: + - Name of the project the security group to be created in. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +--- +- name: allow inbound port 80/tcp from 1.2.3.4 added to security group 'default' + ngine_io.cloudstack.cs_securitygroup_rule: + security_group: default + port: 80 + cidr: 1.2.3.4/32 + +- name: allow tcp/udp outbound added to security group 'default' + ngine_io.cloudstack.cs_securitygroup_rule: + security_group: default + type: egress + start_port: 1 + end_port: 65535 + protocol: '{{ item }}' + with_items: + - tcp + - udp + +- name: allow inbound icmp from 0.0.0.0/0 added to security group 'default' + ngine_io.cloudstack.cs_securitygroup_rule: + security_group: default + protocol: icmp + icmp_code: -1 + icmp_type: -1 + +- name: remove rule inbound port 80/tcp from 0.0.0.0/0 from security group 'default' + ngine_io.cloudstack.cs_securitygroup_rule: + security_group: default + port: 80 + state: absent + +- name: allow inbound port 80/tcp from security group web added to security group 'default' + ngine_io.cloudstack.cs_securitygroup_rule: + security_group: default + port: 80 + user_security_group: web +''' + +RETURN = ''' +--- +id: + description: UUID of the of the rule. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +security_group: + description: security group of the rule. + returned: success + type: str + sample: default +type: + description: type of the rule. + returned: success + type: str + sample: ingress +cidr: + description: CIDR of the rule. + returned: success and cidr is defined + type: str + sample: 0.0.0.0/0 +user_security_group: + description: user security group of the rule. + returned: success and user_security_group is defined + type: str + sample: default +protocol: + description: protocol of the rule. + returned: success + type: str + sample: tcp +start_port: + description: start port of the rule. + returned: success + type: int + sample: 80 +end_port: + description: end port of the rule. + returned: success + type: int + sample: 80 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together + + +class AnsibleCloudStackSecurityGroupRule(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackSecurityGroupRule, self).__init__(module) + self.returns = { + 'icmptype': 'icmp_type', + 'icmpcode': 'icmp_code', + 'endport': 'end_port', + 'startport': 'start_port', + 'protocol': 'protocol', + 'cidr': 'cidr', + 'securitygroupname': 'user_security_group', + } + + def _tcp_udp_match(self, rule, protocol, start_port, end_port): + return (protocol in ['tcp', 'udp'] and + protocol == rule['protocol'] and + start_port == int(rule['startport']) and + end_port == int(rule['endport'])) + + def _icmp_match(self, rule, protocol, icmp_code, icmp_type): + return (protocol == 'icmp' and + protocol == rule['protocol'] and + icmp_code == int(rule['icmpcode']) and + icmp_type == int(rule['icmptype'])) + + def _ah_esp_gre_match(self, rule, protocol): + return (protocol in ['ah', 'esp', 'gre'] and + protocol == rule['protocol']) + + def _type_security_group_match(self, rule, security_group_name): + return (security_group_name and + 'securitygroupname' in rule and + security_group_name == rule['securitygroupname']) + + def _type_cidr_match(self, rule, cidr): + return ('cidr' in rule and + cidr == rule['cidr']) + + def _get_rule(self, rules): + user_security_group_name = self.module.params.get('user_security_group') + cidr = self.module.params.get('cidr') + protocol = self.module.params.get('protocol') + start_port = self.module.params.get('start_port') + end_port = self.get_or_fallback('end_port', 'start_port') + icmp_code = self.module.params.get('icmp_code') + icmp_type = self.module.params.get('icmp_type') + + if protocol in ['tcp', 'udp'] and (start_port is None or end_port is None): + self.module.fail_json(msg="no start_port or end_port set for protocol '%s'" % protocol) + + if protocol == 'icmp' and (icmp_type is None or icmp_code is None): + self.module.fail_json(msg="no icmp_type or icmp_code set for protocol '%s'" % protocol) + + for rule in rules: + if user_security_group_name: + type_match = self._type_security_group_match(rule, user_security_group_name) + else: + type_match = self._type_cidr_match(rule, cidr) + + protocol_match = (self._tcp_udp_match(rule, protocol, start_port, end_port) or + self._icmp_match(rule, protocol, icmp_code, icmp_type) or + self._ah_esp_gre_match(rule, protocol)) + + if type_match and protocol_match: + return rule + return None + + def get_security_group(self, security_group_name=None): + if not security_group_name: + security_group_name = self.module.params.get('security_group') + args = { + 'securitygroupname': security_group_name, + 'projectid': self.get_project('id'), + } + sgs = self.query_api('listSecurityGroups', **args) + if not sgs or 'securitygroup' not in sgs: + self.module.fail_json(msg="security group '%s' not found" % security_group_name) + return sgs['securitygroup'][0] + + def add_rule(self): + security_group = self.get_security_group() + + args = {} + user_security_group_name = self.module.params.get('user_security_group') + + # the user_security_group and cidr are mutually_exclusive, but cidr is defaulted to 0.0.0.0/0. + # that is why we ignore if we have a user_security_group. + if user_security_group_name: + args['usersecuritygrouplist'] = [] + user_security_group = self.get_security_group(user_security_group_name) + args['usersecuritygrouplist'].append({ + 'group': user_security_group['name'], + 'account': user_security_group['account'], + }) + else: + args['cidrlist'] = self.module.params.get('cidr') + + args['protocol'] = self.module.params.get('protocol') + args['startport'] = self.module.params.get('start_port') + args['endport'] = self.get_or_fallback('end_port', 'start_port') + args['icmptype'] = self.module.params.get('icmp_type') + args['icmpcode'] = self.module.params.get('icmp_code') + args['projectid'] = self.get_project('id') + args['securitygroupid'] = security_group['id'] + + rule = None + res = None + sg_type = self.module.params.get('type') + if sg_type == 'ingress': + if 'ingressrule' in security_group: + rule = self._get_rule(security_group['ingressrule']) + if not rule: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('authorizeSecurityGroupIngress', **args) + + elif sg_type == 'egress': + if 'egressrule' in security_group: + rule = self._get_rule(security_group['egressrule']) + if not rule: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('authorizeSecurityGroupEgress', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + security_group = self.poll_job(res, 'securitygroup') + key = sg_type + "rule" # ingressrule / egressrule + if key in security_group: + rule = security_group[key][0] + return rule + + def remove_rule(self): + security_group = self.get_security_group() + rule = None + res = None + sg_type = self.module.params.get('type') + if sg_type == 'ingress': + rule = self._get_rule(security_group['ingressrule']) + if rule: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('revokeSecurityGroupIngress', id=rule['ruleid']) + + elif sg_type == 'egress': + rule = self._get_rule(security_group['egressrule']) + if rule: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('revokeSecurityGroupEgress', id=rule['ruleid']) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + res = self.poll_job(res, 'securitygroup') + return rule + + def get_result(self, security_group_rule): + super(AnsibleCloudStackSecurityGroupRule, self).get_result(security_group_rule) + self.result['type'] = self.module.params.get('type') + self.result['security_group'] = self.module.params.get('security_group') + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + security_group=dict(required=True), + type=dict(choices=['ingress', 'egress'], default='ingress'), + cidr=dict(default='0.0.0.0/0'), + user_security_group=dict(), + protocol=dict(choices=['tcp', 'udp', 'icmp', 'ah', 'esp', 'gre'], default='tcp'), + icmp_type=dict(type='int'), + icmp_code=dict(type='int'), + start_port=dict(type='int', aliases=['port']), + end_port=dict(type='int'), + state=dict(choices=['present', 'absent'], default='present'), + project=dict(), + poll_async=dict(type='bool', default=True), + )) + required_together = cs_required_together() + required_together.extend([ + ['icmp_type', 'icmp_code'], + ]) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=required_together, + mutually_exclusive=( + ['icmp_type', 'start_port'], + ['icmp_type', 'end_port'], + ['icmp_code', 'start_port'], + ['icmp_code', 'end_port'], + ), + supports_check_mode=True + ) + + acs_sg_rule = AnsibleCloudStackSecurityGroupRule(module) + + state = module.params.get('state') + if state in ['absent']: + sg_rule = acs_sg_rule.remove_rule() + else: + sg_rule = acs_sg_rule.add_rule() + + result = acs_sg_rule.get_result(sg_rule) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py new file mode 100644 index 00000000..8d17d521 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_service_offering.py @@ -0,0 +1,574 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_service_offering +description: + - Create and delete service offerings for guest and system VMs. + - Update display_text of existing service offering. +short_description: Manages service offerings on Apache CloudStack based clouds. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + disk_bytes_read_rate: + description: + - Bytes read rate of the disk offering. + type: int + aliases: [ bytes_read_rate ] + disk_bytes_write_rate: + description: + - Bytes write rate of the disk offering. + type: int + aliases: [ bytes_write_rate ] + cpu_number: + description: + - The number of CPUs of the service offering. + type: int + cpu_speed: + description: + - The CPU speed of the service offering in MHz. + type: int + limit_cpu_usage: + description: + - Restrict the CPU usage to committed service offering. + type: bool + deployment_planner: + description: + - The deployment planner heuristics used to deploy a VM of this offering. + - If not set, the value of global config I(vm.deployment.planner) is used. + type: str + display_text: + description: + - Display text of the service offering. + - If not set, I(name) will be used as I(display_text) while creating. + type: str + domain: + description: + - Domain the service offering is related to. + - Public for all domains and subdomains if not set. + type: str + host_tags: + description: + - The host tags for this service offering. + type: list + elements: str + aliases: + - host_tag + hypervisor_snapshot_reserve: + description: + - Hypervisor snapshot reserve space as a percent of a volume. + - Only for managed storage using Xen or VMware. + type: int + is_iops_customized: + description: + - Whether compute offering iops is custom or not. + type: bool + aliases: [ disk_iops_customized ] + disk_iops_read_rate: + description: + - IO requests read rate of the disk offering. + type: int + disk_iops_write_rate: + description: + - IO requests write rate of the disk offering. + type: int + disk_iops_max: + description: + - Max. iops of the compute offering. + type: int + disk_iops_min: + description: + - Min. iops of the compute offering. + type: int + is_system: + description: + - Whether it is a system VM offering or not. + type: bool + default: no + is_volatile: + description: + - Whether the virtual machine needs to be volatile or not. + - Every reboot of VM the root disk is detached then destroyed and a fresh root disk is created and attached to VM. + type: bool + memory: + description: + - The total memory of the service offering in MB. + type: int + name: + description: + - Name of the service offering. + type: str + required: true + network_rate: + description: + - Data transfer rate in Mb/s allowed. + - Supported only for non-system offering and system offerings having I(system_vm_type=domainrouter). + type: int + offer_ha: + description: + - Whether HA is set for the service offering. + type: bool + provisioning_type: + description: + - Provisioning type used to create volumes. + type: str + choices: + - thin + - sparse + - fat + service_offering_details: + description: + - Details for planner, used to store specific parameters. + - A list of dictionaries having keys C(key) and C(value). + type: list + elements: dict + state: + description: + - State of the service offering. + type: str + choices: + - present + - absent + default: present + storage_type: + description: + - The storage type of the service offering. + type: str + choices: + - local + - shared + system_vm_type: + description: + - The system VM type. + - Required if I(is_system=yes). + type: str + choices: + - domainrouter + - consoleproxy + - secondarystoragevm + storage_tags: + description: + - The storage tags for this service offering. + type: list + elements: str + aliases: + - storage_tag + is_customized: + description: + - Whether the offering is customizable or not. + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a non-volatile compute service offering with local storage + ngine_io.cloudstack.cs_service_offering: + name: Micro + display_text: Micro 512mb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 512 + host_tags: eco + storage_type: local + +- name: Create a volatile compute service offering with shared storage + ngine_io.cloudstack.cs_service_offering: + name: Tiny + display_text: Tiny 1gb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 1024 + storage_type: shared + is_volatile: yes + host_tags: eco + storage_tags: eco + +- name: Create or update a volatile compute service offering with shared storage + ngine_io.cloudstack.cs_service_offering: + name: Tiny + display_text: Tiny 1gb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 1024 + storage_type: shared + is_volatile: yes + host_tags: eco + storage_tags: eco + +- name: Create or update a custom compute service offering + ngine_io.cloudstack.cs_service_offering: + name: custom + display_text: custom compute offer + is_customized: yes + storage_type: shared + host_tags: eco + storage_tags: eco + +- name: Remove a compute service offering + ngine_io.cloudstack.cs_service_offering: + name: Tiny + state: absent + +- name: Create or update a system offering for the console proxy + ngine_io.cloudstack.cs_service_offering: + name: System Offering for Console Proxy 2GB + display_text: System Offering for Console Proxy 2GB RAM + is_system: yes + system_vm_type: consoleproxy + cpu_number: 1 + cpu_speed: 2198 + memory: 2048 + storage_type: shared + storage_tags: perf + +- name: Remove a system offering + ngine_io.cloudstack.cs_service_offering: + name: System Offering for Console Proxy 2GB + is_system: yes + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the service offering + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +cpu_number: + description: Number of CPUs in the service offering + returned: success + type: int + sample: 4 +cpu_speed: + description: Speed of CPUs in MHz in the service offering + returned: success + type: int + sample: 2198 +disk_iops_max: + description: Max iops of the disk offering + returned: success + type: int + sample: 1000 +disk_iops_min: + description: Min iops of the disk offering + returned: success + type: int + sample: 500 +disk_bytes_read_rate: + description: Bytes read rate of the service offering + returned: success + type: int + sample: 1000 +disk_bytes_write_rate: + description: Bytes write rate of the service offering + returned: success + type: int + sample: 1000 +disk_iops_read_rate: + description: IO requests per second read rate of the service offering + returned: success + type: int + sample: 1000 +disk_iops_write_rate: + description: IO requests per second write rate of the service offering + returned: success + type: int + sample: 1000 +created: + description: Date the offering was created + returned: success + type: str + sample: 2017-11-19T10:48:59+0000 +display_text: + description: Display text of the offering + returned: success + type: str + sample: Micro 512mb 1cpu +domain: + description: Domain the offering is into + returned: success + type: str + sample: ROOT +host_tags: + description: List of host tags + returned: success + type: list + sample: [ 'eco' ] +storage_tags: + description: List of storage tags + returned: success + type: list + sample: [ 'eco' ] +is_system: + description: Whether the offering is for system VMs or not + returned: success + type: bool + sample: false +is_iops_customized: + description: Whether the offering uses custom IOPS or not + returned: success + type: bool + sample: false +is_volatile: + description: Whether the offering is volatile or not + returned: success + type: bool + sample: false +limit_cpu_usage: + description: Whether the CPU usage is restricted to committed service offering + returned: success + type: bool + sample: false +memory: + description: Memory of the system offering + returned: success + type: int + sample: 512 +name: + description: Name of the system offering + returned: success + type: str + sample: Micro +offer_ha: + description: Whether HA support is enabled in the offering or not + returned: success + type: bool + sample: false +provisioning_type: + description: Provisioning type used to create volumes + returned: success + type: str + sample: thin +storage_type: + description: Storage type used to create volumes + returned: success + type: str + sample: shared +system_vm_type: + description: System VM type of this offering + returned: success + type: str + sample: consoleproxy +service_offering_details: + description: Additioanl service offering details + returned: success + type: dict + sample: "{'vgpuType': 'GRID K180Q','pciDevice':'Group of NVIDIA Corporation GK107GL [GRID K1] GPUs'}" +network_rate: + description: Data transfer rate in megabits per second allowed + returned: success + type: int + sample: 1000 +is_customized: + description: Whether the offering is customizable or not + returned: success + type: bool + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackServiceOffering(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackServiceOffering, self).__init__(module) + self.returns = { + 'cpunumber': 'cpu_number', + 'cpuspeed': 'cpu_speed', + 'deploymentplanner': 'deployment_planner', + 'diskBytesReadRate': 'disk_bytes_read_rate', + 'diskBytesWriteRate': 'disk_bytes_write_rate', + 'diskIopsReadRate': 'disk_iops_read_rate', + 'diskIopsWriteRate': 'disk_iops_write_rate', + 'maxiops': 'disk_iops_max', + 'miniops': 'disk_iops_min', + 'hypervisorsnapshotreserve': 'hypervisor_snapshot_reserve', + 'iscustomized': 'is_customized', + 'iscustomizediops': 'is_iops_customized', + 'issystem': 'is_system', + 'isvolatile': 'is_volatile', + 'limitcpuuse': 'limit_cpu_usage', + 'memory': 'memory', + 'networkrate': 'network_rate', + 'offerha': 'offer_ha', + 'provisioningtype': 'provisioning_type', + 'serviceofferingdetails': 'service_offering_details', + 'storagetype': 'storage_type', + 'systemvmtype': 'system_vm_type', + 'tags': 'storage_tags', + } + + def get_service_offering(self): + args = { + 'name': self.module.params.get('name'), + 'domainid': self.get_domain(key='id'), + 'issystem': self.module.params.get('is_system'), + 'systemvmtype': self.module.params.get('system_vm_type'), + } + service_offerings = self.query_api('listServiceOfferings', **args) + if service_offerings: + return service_offerings['serviceoffering'][0] + + def present_service_offering(self): + service_offering = self.get_service_offering() + if not service_offering: + service_offering = self._create_offering(service_offering) + else: + service_offering = self._update_offering(service_offering) + + return service_offering + + def absent_service_offering(self): + service_offering = self.get_service_offering() + if service_offering: + self.result['changed'] = True + if not self.module.check_mode: + args = { + 'id': service_offering['id'], + } + self.query_api('deleteServiceOffering', **args) + return service_offering + + def _create_offering(self, service_offering): + self.result['changed'] = True + + system_vm_type = self.module.params.get('system_vm_type') + is_system = self.module.params.get('is_system') + + required_params = [] + if is_system and not system_vm_type: + required_params.append('system_vm_type') + self.module.fail_on_missing_params(required_params=required_params) + + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'bytesreadrate': self.module.params.get('disk_bytes_read_rate'), + 'byteswriterate': self.module.params.get('disk_bytes_write_rate'), + 'cpunumber': self.module.params.get('cpu_number'), + 'cpuspeed': self.module.params.get('cpu_speed'), + 'customizediops': self.module.params.get('is_iops_customized'), + 'deploymentplanner': self.module.params.get('deployment_planner'), + 'domainid': self.get_domain(key='id'), + 'hosttags': self.module.params.get('host_tags'), + 'hypervisorsnapshotreserve': self.module.params.get('hypervisor_snapshot_reserve'), + 'iopsreadrate': self.module.params.get('disk_iops_read_rate'), + 'iopswriterate': self.module.params.get('disk_iops_write_rate'), + 'maxiops': self.module.params.get('disk_iops_max'), + 'miniops': self.module.params.get('disk_iops_min'), + 'issystem': is_system, + 'isvolatile': self.module.params.get('is_volatile'), + 'memory': self.module.params.get('memory'), + 'networkrate': self.module.params.get('network_rate'), + 'offerha': self.module.params.get('offer_ha'), + 'provisioningtype': self.module.params.get('provisioning_type'), + 'serviceofferingdetails': self.module.params.get('service_offering_details'), + 'storagetype': self.module.params.get('storage_type'), + 'systemvmtype': system_vm_type, + 'tags': self.module.params.get('storage_tags'), + 'limitcpuuse': self.module.params.get('limit_cpu_usage'), + 'customized': self.module.params.get('is_customized') + } + if not self.module.check_mode: + res = self.query_api('createServiceOffering', **args) + service_offering = res['serviceoffering'] + return service_offering + + def _update_offering(self, service_offering): + args = { + 'id': service_offering['id'], + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + } + if self.has_changed(args, service_offering): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateServiceOffering', **args) + service_offering = res['serviceoffering'] + return service_offering + + def get_result(self, service_offering): + super(AnsibleCloudStackServiceOffering, self).get_result(service_offering) + if service_offering: + if 'hosttags' in service_offering: + self.result['host_tags'] = service_offering['hosttags'].split(',') or [service_offering['hosttags']] + + # Prevent confusion, the api returns a tags key for storage tags. + if 'tags' in service_offering: + self.result['storage_tags'] = service_offering['tags'].split(',') or [service_offering['tags']] + if 'tags' in self.result: + del self.result['tags'] + + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + cpu_number=dict(type='int'), + cpu_speed=dict(type='int'), + limit_cpu_usage=dict(type='bool'), + deployment_planner=dict(), + domain=dict(), + host_tags=dict(type='list', elements='str', aliases=['host_tag']), + hypervisor_snapshot_reserve=dict(type='int'), + disk_bytes_read_rate=dict(type='int', aliases=['bytes_read_rate']), + disk_bytes_write_rate=dict(type='int', aliases=['bytes_write_rate']), + disk_iops_read_rate=dict(type='int'), + disk_iops_write_rate=dict(type='int'), + disk_iops_max=dict(type='int'), + disk_iops_min=dict(type='int'), + is_system=dict(type='bool', default=False), + is_volatile=dict(type='bool'), + is_iops_customized=dict(type='bool', aliases=['disk_iops_customized']), + memory=dict(type='int'), + network_rate=dict(type='int'), + offer_ha=dict(type='bool'), + provisioning_type=dict(choices=['thin', 'sparse', 'fat']), + service_offering_details=dict(type='list', elements='dict'), + storage_type=dict(choices=['local', 'shared']), + system_vm_type=dict(choices=['domainrouter', 'consoleproxy', 'secondarystoragevm']), + storage_tags=dict(type='list', elements='str', aliases=['storage_tag']), + state=dict(choices=['present', 'absent'], default='present'), + is_customized=dict(type='bool'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_so = AnsibleCloudStackServiceOffering(module) + + state = module.params.get('state') + if state == "absent": + service_offering = acs_so.absent_service_offering() + else: + service_offering = acs_so.present_service_offering() + + result = acs_so.get_result(service_offering) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py new file mode 100644 index 00000000..bd11f367 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_snapshot_policy.py @@ -0,0 +1,349 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_snapshot_policy +short_description: Manages volume snapshot policies on Apache CloudStack based clouds. +description: + - Create, update and delete volume snapshot policies. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + volume: + description: + - Name of the volume. + - Either I(volume) or I(vm) is required. + type: str + volume_type: + description: + - Type of the volume. + type: str + choices: + - DATADISK + - ROOT + vm: + description: + - Name of the instance to select the volume from. + - Use I(volume_type) if VM has a DATADISK and ROOT volume. + - In case of I(volume_type=DATADISK), additionally use I(device_id) if VM has more than one DATADISK volume. + - Either I(volume) or I(vm) is required. + type: str + device_id: + description: + - ID of the device on a VM the volume is attached to. + - This will only be considered if VM has multiple DATADISK volumes. + type: int + vpc: + description: + - Name of the vpc the instance is deployed in. + type: str + interval_type: + description: + - Interval of the snapshot. + type: str + default: daily + choices: [ hourly, daily, weekly, monthly ] + aliases: [ interval ] + max_snaps: + description: + - Max number of snapshots. + type: int + default: 8 + aliases: [ max ] + schedule: + description: + - Time the snapshot is scheduled. Required if I(state=present). + - 'Format for I(interval_type=HOURLY): C(MM)' + - 'Format for I(interval_type=DAILY): C(MM:HH)' + - 'Format for I(interval_type=WEEKLY): C(MM:HH:DD (1-7))' + - 'Format for I(interval_type=MONTHLY): C(MM:HH:DD (1-28))' + type: str + time_zone: + description: + - Specifies a timezone for this command. + type: str + default: UTC + aliases: [ timezone ] + state: + description: + - State of the snapshot policy. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the volume is related to. + type: str + account: + description: + - Account the volume is related to. + type: str + project: + description: + - Name of the project the volume is related to. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: ensure a snapshot policy daily at 1h00 UTC + ngine_io.cloudstack.cs_snapshot_policy: + volume: ROOT-478 + schedule: '00:1' + max_snaps: 3 + +- name: ensure a snapshot policy daily at 1h00 UTC on the second DATADISK of VM web-01 + ngine_io.cloudstack.cs_snapshot_policy: + vm: web-01 + volume_type: DATADISK + device_id: 2 + schedule: '00:1' + max_snaps: 3 + +- name: ensure a snapshot policy hourly at minute 5 UTC + ngine_io.cloudstack.cs_snapshot_policy: + volume: ROOT-478 + schedule: '5' + interval_type: hourly + max_snaps: 1 + +- name: ensure a snapshot policy weekly on Sunday at 05h00, TZ Europe/Zurich + ngine_io.cloudstack.cs_snapshot_policy: + volume: ROOT-478 + schedule: '00:5:1' + interval_type: weekly + max_snaps: 1 + time_zone: 'Europe/Zurich' + +- name: ensure a snapshot policy is absent + ngine_io.cloudstack.cs_snapshot_policy: + volume: ROOT-478 + interval_type: hourly + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the snapshot policy. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +interval_type: + description: interval type of the snapshot policy. + returned: success + type: str + sample: daily +schedule: + description: schedule of the snapshot policy. + returned: success + type: str + sample: +max_snaps: + description: maximum number of snapshots retained. + returned: success + type: int + sample: 10 +time_zone: + description: the time zone of the snapshot policy. + returned: success + type: str + sample: Etc/UTC +volume: + description: the volume of the snapshot policy. + returned: success + type: str + sample: Etc/UTC +zone: + description: Name of zone the volume is related to. + returned: success + type: str + sample: ch-gva-2 +project: + description: Name of project the volume is related to. + returned: success + type: str + sample: Production +account: + description: Account the volume is related to. + returned: success + type: str + sample: example account +domain: + description: Domain the volume is related to. + returned: success + type: str + sample: example domain +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackSnapshotPolicy(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackSnapshotPolicy, self).__init__(module) + self.returns = { + 'schedule': 'schedule', + 'timezone': 'time_zone', + 'maxsnaps': 'max_snaps', + } + self.interval_types = { + 'hourly': 0, + 'daily': 1, + 'weekly': 2, + 'monthly': 3, + } + self.volume = None + + def get_interval_type(self): + interval_type = self.module.params.get('interval_type') + return self.interval_types[interval_type] + + def get_volume(self, key=None): + if self.volume: + return self._get_by_key(key, self.volume) + + args = { + 'name': self.module.params.get('volume'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'virtualmachineid': self.get_vm(key='id', filter_zone=False), + 'type': self.module.params.get('volume_type'), + } + volumes = self.query_api('listVolumes', **args) + if volumes: + if volumes['count'] > 1: + device_id = self.module.params.get('device_id') + if not device_id: + self.module.fail_json(msg="Found more then 1 volume: combine params 'vm', 'volume_type', 'device_id' and/or 'volume' to select the volume") + else: + for v in volumes['volume']: + if v.get('deviceid') == device_id: + self.volume = v + return self._get_by_key(key, self.volume) + self.module.fail_json(msg="No volume found with device id %s" % device_id) + self.volume = volumes['volume'][0] + return self._get_by_key(key, self.volume) + return None + + def get_snapshot_policy(self): + args = { + 'volumeid': self.get_volume(key='id') + } + policies = self.query_api('listSnapshotPolicies', **args) + if policies: + for policy in policies['snapshotpolicy']: + if policy['intervaltype'] == self.get_interval_type(): + return policy + return None + + def present_snapshot_policy(self): + required_params = [ + 'schedule', + ] + self.module.fail_on_missing_params(required_params=required_params) + + policy = self.get_snapshot_policy() + args = { + 'id': policy.get('id') if policy else None, + 'intervaltype': self.module.params.get('interval_type'), + 'schedule': self.module.params.get('schedule'), + 'maxsnaps': self.module.params.get('max_snaps'), + 'timezone': self.module.params.get('time_zone'), + 'volumeid': self.get_volume(key='id') + } + if not policy or (policy and self.has_changed(policy, args, only_keys=['schedule', 'maxsnaps', 'timezone'])): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('createSnapshotPolicy', **args) + policy = res['snapshotpolicy'] + return policy + + def absent_snapshot_policy(self): + policy = self.get_snapshot_policy() + if policy: + self.result['changed'] = True + args = { + 'id': policy['id'] + } + if not self.module.check_mode: + self.query_api('deleteSnapshotPolicies', **args) + return policy + + def get_result(self, policy): + super(AnsibleCloudStackSnapshotPolicy, self).get_result(policy) + if policy and 'intervaltype' in policy: + for key, value in self.interval_types.items(): + if value == policy['intervaltype']: + self.result['interval_type'] = key + break + volume = self.get_volume() + if volume: + volume_results = { + 'volume': volume.get('name'), + 'zone': volume.get('zonename'), + 'project': volume.get('project'), + 'account': volume.get('account'), + 'domain': volume.get('domain'), + } + self.result.update(volume_results) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + volume=dict(), + volume_type=dict(choices=['DATADISK', 'ROOT']), + vm=dict(), + device_id=dict(type='int'), + vpc=dict(), + interval_type=dict(default='daily', choices=['hourly', 'daily', 'weekly', 'monthly'], aliases=['interval']), + schedule=dict(), + time_zone=dict(default='UTC', aliases=['timezone']), + max_snaps=dict(type='int', default=8, aliases=['max']), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + required_one_of=( + ['vm', 'volume'], + ), + supports_check_mode=True + ) + + acs_snapshot_policy = AnsibleCloudStackSnapshotPolicy(module) + + state = module.params.get('state') + if state in ['absent']: + policy = acs_snapshot_policy.absent_snapshot_policy() + else: + policy = acs_snapshot_policy.present_snapshot_policy() + + result = acs_snapshot_policy.get_result(policy) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py new file mode 100644 index 00000000..3e32171c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_sshkeypair.py @@ -0,0 +1,261 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_sshkeypair +short_description: Manages SSH keys on Apache CloudStack based clouds. +description: + - Create, register and remove SSH keys. + - If no key was found and no public key was provided and a new SSH + private/public key pair will be created and the private key will be returned. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of public key. + type: str + required: true + domain: + description: + - Domain the public key is related to. + type: str + account: + description: + - Account the public key is related to. + type: str + project: + description: + - Name of the project the public key to be registered in. + type: str + state: + description: + - State of the public key. + type: str + default: present + choices: [ present, absent ] + public_key: + description: + - String of the public key. + type: str +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a new private / public key pair + ngine_io.cloudstack.cs_sshkeypair: + name: linus@example.com + register: key + +- debug: + msg: 'Private key is {{ key.private_key }}' + +- name: remove a public key by its name + ngine_io.cloudstack.cs_sshkeypair: + name: linus@example.com + state: absent + +- name: register your existing local public key + ngine_io.cloudstack.cs_sshkeypair: + name: linus@example.com + public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" +''' + +RETURN = ''' +--- +id: + description: UUID of the SSH public key. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: Name of the SSH public key. + returned: success + type: str + sample: linus@example.com +fingerprint: + description: Fingerprint of the SSH public key. + returned: success + type: str + sample: "86:5e:a3:e8:bd:95:7b:07:7c:c2:5c:f7:ad:8b:09:28" +private_key: + description: Private key of generated SSH keypair. + returned: changed + type: str + sample: "-----BEGIN RSA PRIVATE KEY-----\nMII...8tO\n-----END RSA PRIVATE KEY-----\n" +''' + +import traceback + +SSHPUBKEYS_IMP_ERR = None +try: + import sshpubkeys + HAS_LIB_SSHPUBKEYS = True +except ImportError: + SSHPUBKEYS_IMP_ERR = traceback.format_exc() + HAS_LIB_SSHPUBKEYS = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib +from ansible.module_utils._text import to_native +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_required_together, + cs_argument_spec +) + + +class AnsibleCloudStackSshKey(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackSshKey, self).__init__(module) + self.returns = { + 'privatekey': 'private_key', + 'fingerprint': 'fingerprint', + } + self.ssh_key = None + + def register_ssh_key(self, public_key): + ssh_key = self.get_ssh_key() + args = self._get_common_args() + name = self.module.params.get('name') + + res = None + if not ssh_key: + self.result['changed'] = True + args['publickey'] = public_key + if not self.module.check_mode: + args['name'] = name + res = self.query_api('registerSSHKeyPair', **args) + else: + fingerprint = self._get_ssh_fingerprint(public_key) + if ssh_key['fingerprint'] != fingerprint: + self.result['changed'] = True + if not self.module.check_mode: + # delete the ssh key with matching name but wrong fingerprint + args['name'] = name + self.query_api('deleteSSHKeyPair', **args) + + elif ssh_key['name'].lower() != name.lower(): + self.result['changed'] = True + if not self.module.check_mode: + # delete the ssh key with matching fingerprint but wrong name + args['name'] = ssh_key['name'] + self.query_api('deleteSSHKeyPair', **args) + # First match for key retrievement will be the fingerprint. + # We need to make another lookup if there is a key with identical name. + self.ssh_key = None + ssh_key = self.get_ssh_key() + if ssh_key and ssh_key['fingerprint'] != fingerprint: + args['name'] = name + self.query_api('deleteSSHKeyPair', **args) + + if not self.module.check_mode and self.result['changed']: + args['publickey'] = public_key + args['name'] = name + res = self.query_api('registerSSHKeyPair', **args) + + if res and 'keypair' in res: + ssh_key = res['keypair'] + + return ssh_key + + def create_ssh_key(self): + ssh_key = self.get_ssh_key() + if not ssh_key: + self.result['changed'] = True + args = self._get_common_args() + args['name'] = self.module.params.get('name') + if not self.module.check_mode: + res = self.query_api('createSSHKeyPair', **args) + ssh_key = res['keypair'] + return ssh_key + + def remove_ssh_key(self, name=None): + ssh_key = self.get_ssh_key() + if ssh_key: + self.result['changed'] = True + args = self._get_common_args() + args['name'] = name or self.module.params.get('name') + if not self.module.check_mode: + self.query_api('deleteSSHKeyPair', **args) + return ssh_key + + def _get_common_args(self): + return { + 'domainid': self.get_domain('id'), + 'account': self.get_account('name'), + 'projectid': self.get_project('id') + } + + def get_ssh_key(self): + if not self.ssh_key: + public_key = self.module.params.get('public_key') + if public_key: + # Query by fingerprint of the public key + args_fingerprint = self._get_common_args() + args_fingerprint['fingerprint'] = self._get_ssh_fingerprint(public_key) + ssh_keys = self.query_api('listSSHKeyPairs', **args_fingerprint) + if ssh_keys and 'sshkeypair' in ssh_keys: + self.ssh_key = ssh_keys['sshkeypair'][0] + # When key has not been found by fingerprint, use the name + if not self.ssh_key: + args_name = self._get_common_args() + args_name['name'] = self.module.params.get('name') + ssh_keys = self.query_api('listSSHKeyPairs', **args_name) + if ssh_keys and 'sshkeypair' in ssh_keys: + self.ssh_key = ssh_keys['sshkeypair'][0] + return self.ssh_key + + def _get_ssh_fingerprint(self, public_key): + key = sshpubkeys.SSHKey(public_key) + if hasattr(key, 'hash_md5'): + return key.hash_md5().replace(to_native('MD5:'), to_native('')) + return key.hash() + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + public_key=dict(), + domain=dict(), + account=dict(), + project=dict(), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + if not HAS_LIB_SSHPUBKEYS: + module.fail_json(msg=missing_required_lib("sshpubkeys"), exception=SSHPUBKEYS_IMP_ERR) + + acs_sshkey = AnsibleCloudStackSshKey(module) + state = module.params.get('state') + if state in ['absent']: + ssh_key = acs_sshkey.remove_ssh_key() + else: + public_key = module.params.get('public_key') + if public_key: + ssh_key = acs_sshkey.register_ssh_key(public_key) + else: + ssh_key = acs_sshkey.create_ssh_key() + + result = acs_sshkey.get_result(ssh_key) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py new file mode 100644 index 00000000..5d223715 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_staticnat.py @@ -0,0 +1,249 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_staticnat +short_description: Manages static NATs on Apache CloudStack based clouds. +description: + - Create, update and remove static NATs. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + ip_address: + description: + - Public IP address the static NAT is assigned to. + type: str + required: true + vm: + description: + - Name of virtual machine which we make the static NAT for. + - Required if I(state=present). + type: str + vm_guest_ip: + description: + - VM guest NIC secondary IP address for the static NAT. + type: str + network: + description: + - Network the IP address is related to. + type: str + vpc: + description: + - VPC the network related to. + type: str + state: + description: + - State of the static NAT. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the static NAT is related to. + type: str + account: + description: + - Account the static NAT is related to. + type: str + project: + description: + - Name of the project the static NAT is related to. + type: str + zone: + description: + - Name of the zone in which the virtual machine is in. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a static NAT for IP 1.2.3.4 to web01 + ngine_io.cloudstack.cs_staticnat: + ip_address: 1.2.3.4 + vm: web01 + +- name: Remove a static NAT + ngine_io.cloudstack.cs_staticnat: + ip_address: 1.2.3.4 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the ip_address. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +ip_address: + description: Public IP address. + returned: success + type: str + sample: 1.2.3.4 +vm_name: + description: Name of the virtual machine. + returned: success + type: str + sample: web-01 +vm_display_name: + description: Display name of the virtual machine. + returned: success + type: str + sample: web-01 +vm_guest_ip: + description: IP of the virtual machine. + returned: success + type: str + sample: 10.101.65.152 +zone: + description: Name of zone the static NAT is related to. + returned: success + type: str + sample: ch-gva-2 +project: + description: Name of project the static NAT is related to. + returned: success + type: str + sample: Production +account: + description: Account the static NAT is related to. + returned: success + type: str + sample: example account +domain: + description: Domain the static NAT is related to. + returned: success + type: str + sample: example domain +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackStaticNat(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackStaticNat, self).__init__(module) + self.returns = { + 'virtualmachinedisplayname': 'vm_display_name', + 'virtualmachinename': 'vm_name', + 'ipaddress': 'ip_address', + 'vmipaddress': 'vm_guest_ip', + } + + def create_static_nat(self, ip_address): + self.result['changed'] = True + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'ipaddressid': ip_address['id'], + 'vmguestip': self.get_vm_guest_ip(), + 'networkid': self.get_network(key='id') + } + if not self.module.check_mode: + self.query_api('enableStaticNat', **args) + + # reset ip address and query new values + self.ip_address = None + ip_address = self.get_ip_address() + return ip_address + + def update_static_nat(self, ip_address): + args = { + 'virtualmachineid': self.get_vm(key='id'), + 'ipaddressid': ip_address['id'], + 'vmguestip': self.get_vm_guest_ip(), + 'networkid': self.get_network(key='id') + } + # make an alias, so we can use has_changed() + ip_address['vmguestip'] = ip_address['vmipaddress'] + if self.has_changed(args, ip_address, ['vmguestip', 'virtualmachineid']): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('disableStaticNat', ipaddressid=ip_address['id']) + self.poll_job(res, 'staticnat') + + self.query_api('enableStaticNat', **args) + + # reset ip address and query new values + self.ip_address = None + ip_address = self.get_ip_address() + return ip_address + + def present_static_nat(self): + ip_address = self.get_ip_address() + if not ip_address['isstaticnat']: + ip_address = self.create_static_nat(ip_address) + else: + ip_address = self.update_static_nat(ip_address) + return ip_address + + def absent_static_nat(self): + ip_address = self.get_ip_address() + if ip_address['isstaticnat']: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('disableStaticNat', ipaddressid=ip_address['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'staticnat') + return ip_address + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + ip_address=dict(required=True), + vm=dict(), + vm_guest_ip=dict(), + network=dict(), + vpc=dict(), + state=dict(choices=['present', 'absent'], default='present'), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_static_nat = AnsibleCloudStackStaticNat(module) + + state = module.params.get('state') + if state in ['absent']: + ip_address = acs_static_nat.absent_static_nat() + else: + ip_address = acs_static_nat.present_static_nat() + + result = acs_static_nat.get_result(ip_address) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py new file mode 100644 index 00000000..e4034587 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_storage_pool.py @@ -0,0 +1,489 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, Netservers Ltd. <support@netservers.co.uk> +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_storage_pool +short_description: Manages Primary Storage Pools on Apache CloudStack based clouds. +description: + - Create, update, put into maintenance, disable, enable and remove storage pools. +author: + - Netservers Ltd. (@netservers) + - René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the storage pool. + type: str + required: true + zone: + description: + - Name of the zone in which the host should be deployed. + - If not set, default zone is used. + type: str + storage_url: + description: + - URL of the storage pool. + - Required if I(state=present). + type: str + pod: + description: + - Name of the pod. + type: str + cluster: + description: + - Name of the cluster. + type: str + scope: + description: + - The scope of the storage pool. + - Defaults to cluster when C(cluster) is provided, otherwise zone. + type: str + choices: [ cluster, zone ] + managed: + description: + - Whether the storage pool should be managed by CloudStack. + - Only considered on creation. + type: bool + hypervisor: + description: + - Required when creating a zone scoped pool. + - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator). + type: str + storage_tags: + description: + - Tags associated with this storage pool. + type: list + elements: str + aliases: [ storage_tag ] + provider: + description: + - Name of the storage provider e.g. SolidFire, SolidFireShared, DefaultPrimary, CloudByte. + type: str + default: DefaultPrimary + capacity_bytes: + description: + - Bytes CloudStack can provision from this storage pool. + type: int + capacity_iops: + description: + - Bytes CloudStack can provision from this storage pool. + type: int + allocation_state: + description: + - Allocation state of the storage pool. + type: str + choices: [ enabled, disabled, maintenance ] + state: + description: + - State of the storage pool. + type: str + default: present + choices: [ present, absent ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: ensure a zone scoped storage_pool is present + ngine_io.cloudstack.cs_storage_pool: + zone: zone01 + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + provider: DefaultPrimary + name: Ceph RBD + scope: zone + hypervisor: KVM + +- name: ensure a cluster scoped storage_pool is disabled + ngine_io.cloudstack.cs_storage_pool: + name: Ceph RBD + zone: zone01 + cluster: cluster01 + pod: pod01 + storage_url: rbd://admin:SECRET@ceph-the-mons.domain/poolname + provider: DefaultPrimary + scope: cluster + allocation_state: disabled + +- name: ensure a cluster scoped storage_pool is in maintenance + ngine_io.cloudstack.cs_storage_pool: + name: Ceph RBD + zone: zone01 + cluster: cluster01 + pod: pod01 + storage_url: rbd://admin:SECRET@ceph-the-mons.domain/poolname + provider: DefaultPrimary + scope: cluster + allocation_state: maintenance + +- name: ensure a storage_pool is absent + ngine_io.cloudstack.cs_storage_pool: + name: Ceph RBD + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the pool. + returned: success + type: str + sample: a3fca65a-7db1-4891-b97c-48806a978a96 +created: + description: Date of the pool was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +capacity_iops: + description: IOPS CloudStack can provision from this storage pool + returned: when available + type: int + sample: 60000 +zone: + description: The name of the zone. + returned: success + type: str + sample: Zone01 +cluster: + description: The name of the cluster. + returned: when scope is cluster + type: str + sample: Cluster01 +pod: + description: The name of the pod. + returned: when scope is cluster + type: str + sample: Cluster01 +disk_size_allocated: + description: The pool's currently allocated disk space. + returned: success + type: int + sample: 2443517624320 +disk_size_total: + description: The total size of the pool. + returned: success + type: int + sample: 3915055693824 +disk_size_used: + description: The pool's currently used disk size. + returned: success + type: int + sample: 1040862622180 +scope: + description: The scope of the storage pool. + returned: success + type: str + sample: cluster +hypervisor: + description: Hypervisor related to this storage pool. + returned: when available + type: str + sample: KVM +state: + description: The state of the storage pool as returned by the API. + returned: success + type: str + sample: Up +allocation_state: + description: The state of the storage pool. + returned: success + type: str + sample: enabled +path: + description: The storage pool path used in the storage_url. + returned: success + type: str + sample: poolname +overprovision_factor: + description: The overprovision factor of the storage pool. + returned: success + type: str + sample: 2.0 +suitable_for_migration: + description: Whether the storage pool is suitable to migrate a volume or not. + returned: success + type: bool + sample: false +storage_capabilities: + description: Capabilities of the storage pool. + returned: success + type: dict + sample: {"VOLUME_SNAPSHOT_QUIESCEVM": "false"} +storage_tags: + description: the tags for the storage pool. + returned: success + type: list + sample: ["perf", "ssd"] +''' + +# import cloudstack common +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackStoragePool(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackStoragePool, self).__init__(module) + self.returns = { + 'capacityiops': 'capacity_iops', + 'podname': 'pod', + 'clustername': 'cluster', + 'disksizeallocated': 'disk_size_allocated', + 'disksizetotal': 'disk_size_total', + 'disksizeused': 'disk_size_used', + 'scope': 'scope', + 'hypervisor': 'hypervisor', + 'type': 'type', + 'ip_address': 'ipaddress', + 'path': 'path', + 'overprovisionfactor': 'overprovision_factor', + 'storagecapabilities': 'storage_capabilities', + 'suitableformigration': 'suitable_for_migration', + } + self.allocation_states = { + # Host state: param state + 'Up': 'enabled', + 'Disabled': 'disabled', + 'Maintenance': 'maintenance', + } + self.storage_pool = None + + def _get_common_args(self): + return { + 'name': self.module.params.get('name'), + 'url': self.module.params.get('storage_url'), + 'zoneid': self.get_zone(key='id'), + 'provider': self.get_storage_provider(), + 'scope': self.module.params.get('scope'), + 'hypervisor': self.module.params.get('hypervisor'), + 'capacitybytes': self.module.params.get('capacity_bytes'), + 'capacityiops': self.module.params.get('capacity_iops'), + } + + def _allocation_state_enabled_disabled_changed(self, pool, allocation_state): + if allocation_state in ['enabled', 'disabled']: + for pool_state, param_state in self.allocation_states.items(): + if pool_state == pool['state'] and allocation_state != param_state: + return True + return False + + def _handle_allocation_state(self, pool, state=None): + allocation_state = state or self.module.params.get('allocation_state') + if not allocation_state: + return pool + + if self.allocation_states.get(pool['state']) == allocation_state: + return pool + + # Cancel maintenance if target state is enabled/disabled + elif allocation_state in ['enabled', 'disabled']: + pool = self._cancel_maintenance(pool) + pool = self._update_storage_pool(pool=pool, allocation_state=allocation_state) + + # Only an enabled host can put in maintenance + elif allocation_state == 'maintenance': + pool = self._update_storage_pool(pool=pool, allocation_state='enabled') + pool = self._enable_maintenance(pool=pool) + + return pool + + def _create_storage_pool(self): + args = self._get_common_args() + args.update({ + 'clusterid': self.get_cluster(key='id'), + 'podid': self.get_pod(key='id'), + 'managed': self.module.params.get('managed'), + }) + + scope = self.module.params.get('scope') + if scope is None: + args['scope'] = 'cluster' if args['clusterid'] else 'zone' + + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('createStoragePool', **args) + return res['storagepool'] + + def _update_storage_pool(self, pool, allocation_state=None): + args = { + 'id': pool['id'], + 'capacitybytes': self.module.params.get('capacity_bytes'), + 'capacityiops': self.module.params.get('capacity_iops'), + 'tags': self.get_storage_tags(), + } + + if self.has_changed(args, pool) or self._allocation_state_enabled_disabled_changed(pool, allocation_state): + self.result['changed'] = True + args['enabled'] = allocation_state == 'enabled' if allocation_state in ['enabled', 'disabled'] else None + if not self.module.check_mode: + res = self.query_api('updateStoragePool', **args) + pool = res['storagepool'] + return pool + + def _enable_maintenance(self, pool): + if pool['state'].lower() != "maintenance": + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('enableStorageMaintenance', id=pool['id']) + pool = self.poll_job(res, 'storagepool') + return pool + + def _cancel_maintenance(self, pool): + if pool['state'].lower() == "maintenance": + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('cancelStorageMaintenance', id=pool['id']) + pool = self.poll_job(res, 'storagepool') + return pool + + def get_storage_tags(self): + storage_tags = self.module.params.get('storage_tags') + if storage_tags is None: + return None + return ','.join(storage_tags) + + def get_storage_pool(self, key=None): + if self.storage_pool is None: + zoneid = self.get_zone(key='id') + clusterid = self.get_cluster(key='id') + podid = self.get_pod(key='id') + + args = { + 'zoneid': zoneid, + 'podid': podid, + 'clusterid': clusterid, + 'name': self.module.params.get('name'), + } + + res = self.query_api('listStoragePools', **args) + if 'storagepool' not in res: + return None + + self.storage_pool = res['storagepool'][0] + + return self.storage_pool + + def present_storage_pool(self): + pool = self.get_storage_pool() + if pool: + pool = self._update_storage_pool(pool=pool) + else: + pool = self._create_storage_pool() + + if pool: + pool = self._handle_allocation_state(pool=pool) + + return pool + + def absent_storage_pool(self): + pool = self.get_storage_pool() + if pool: + self.result['changed'] = True + + args = { + 'id': pool['id'], + } + if not self.module.check_mode: + # Only a pool in maintenance can be deleted + self._handle_allocation_state(pool=pool, state='maintenance') + self.query_api('deleteStoragePool', **args) + return pool + + def get_storage_provider(self, type="primary"): + args = { + 'type': type, + } + provider = self.module.params.get('provider') + storage_providers = self.query_api('listStorageProviders', **args) + for sp in storage_providers.get('dataStoreProvider') or []: + if sp['name'].lower() == provider.lower(): + return provider + self.fail_json(msg="Storage provider %s not found" % provider) + + def get_cluster(self, key=None): + cluster = self.module.params.get('cluster') + if not cluster: + return None + + args = { + 'name': cluster, + 'zoneid': self.get_zone(key='id'), + } + + clusters = self.query_api('listClusters', **args) + if clusters: + return self._get_by_key(key, clusters['cluster'][0]) + + self.fail_json(msg="Cluster %s not found" % cluster) + + def get_result(self, pool): + super(AnsibleCloudStackStoragePool, self).get_result(pool) + if pool: + self.result['storage_url'] = "%s://%s/%s" % (pool['type'], pool['ipaddress'], pool['path']) + self.result['scope'] = pool['scope'].lower() + self.result['storage_tags'] = pool['tags'].split(',') if pool.get('tags') else [] + self.result['allocation_state'] = self.allocation_states.get(pool['state']) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + storage_url=dict(), + zone=dict(), + pod=dict(), + cluster=dict(), + scope=dict(choices=['zone', 'cluster']), + hypervisor=dict(), + provider=dict(default='DefaultPrimary'), + capacity_bytes=dict(type='int'), + capacity_iops=dict(type='int'), + managed=dict(type='bool'), + storage_tags=dict(type='list', elements='str', aliases=['storage_tag']), + allocation_state=dict(choices=['enabled', 'disabled', 'maintenance']), + state=dict(choices=['present', 'absent'], default='present'), + )) + + required_together = cs_required_together() + required_together.extend([ + ['pod', 'cluster'], + ]) + module = AnsibleModule( + argument_spec=argument_spec, + required_together=required_together, + required_if=[ + ('state', 'present', ['storage_url']), + ], + supports_check_mode=True + ) + + acs_storage_pool = AnsibleCloudStackStoragePool(module) + + state = module.params.get('state') + if state in ['absent']: + pool = acs_storage_pool.absent_storage_pool() + else: + pool = acs_storage_pool.present_storage_pool() + + result = acs_storage_pool.get_result(pool) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py new file mode 100644 index 00000000..16902595 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_template.py @@ -0,0 +1,741 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_template +short_description: Manages templates on Apache CloudStack based clouds. +description: + - Register templates from an URL. + - Create templates from a ROOT volume of a stopped VM or its snapshot. + - Update, extract and delete templates. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the template. + type: str + required: true + url: + description: + - URL of where the template is hosted on I(state=present). + - URL to which the template would be extracted on I(state=extracted). + - Mutually exclusive with I(vm). + type: str + vm: + description: + - VM name the template will be created from its volume or alternatively from a snapshot. + - VM must be in stopped state if created from its volume. + - Mutually exclusive with I(url). + type: str + snapshot: + description: + - Name of the snapshot, created from the VM ROOT volume, the template will be created from. + - I(vm) is required together with this argument. + type: str + os_type: + description: + - OS type that best represents the OS of this template. + type: str + checksum: + description: + - The MD5 checksum value of this template. + - If set, we search by checksum instead of name. + type: str + is_public: + description: + - Register the template to be publicly available to all users. + - Only used if I(state) is C(present). + type: bool + is_featured: + description: + - Register the template to be featured. + - Only used if I(state) is C(present). + type: bool + is_dynamically_scalable: + description: + - Register the template having XS/VMware tools installed in order to support dynamic scaling of VM CPU/memory. + - Only used if I(state) is C(present). + type: bool + cross_zones: + description: + - Whether the template should be synced or removed across zones. + - Only used if I(state) is C(present) or C(absent). + default: no + type: bool + mode: + description: + - Mode for the template extraction. + - Only used if I(state=extracted). + type: str + default: http_download + choices: [ http_download, ftp_upload ] + domain: + description: + - Domain the template, snapshot or VM is related to. + type: str + account: + description: + - Account the template, snapshot or VM is related to. + type: str + project: + description: + - Name of the project the template to be registered in. + type: str + zone: + description: + - Name of the zone you wish the template to be registered or deleted from. + - If not specified, first found zone will be used. + type: str + template_filter: + description: + - Name of the filter used to search for the template. + - The filter C(all) was added in 2.7. + type: str + default: self + choices: [ all, featured, self, selfexecutable, sharedexecutable, executable, community ] + template_find_options: + description: + - Options to find a template uniquely. + - More than one allowed. + type: list + elements: str + choices: [ display_text, checksum, cross_zones ] + aliases: [ template_find_option ] + default: [] + hypervisor: + description: + - Name the hypervisor to be used for creating the new template. + - Relevant when using I(state=present). + - Possible values are C(KVM), C(VMware), C(BareMetal), C(XenServer), C(LXC), C(HyperV), C(UCS), C(OVM), C(Simulator). + type: str + requires_hvm: + description: + - Whether the template requires HVM or not. + - Only considered while creating the template. + type: bool + password_enabled: + description: + - Enable template password reset support. + type: bool + template_tag: + description: + - The tag for this template. + type: str + sshkey_enabled: + description: + - True if the template supports the sshkey upload feature. + - Only considered if I(url) is used (API limitation). + type: bool + is_routing: + description: + - Sets the template type to routing, i.e. if template is used to deploy routers. + - Only considered if I(url) is used. + type: bool + format: + description: + - The format for the template. + - Only considered if I(state=present). + type: str + choices: [ QCOW2, RAW, VHD, OVA ] + is_extractable: + description: + - Allows the template or its derivatives to be extractable. + type: bool + details: + description: + - Template details in key/value pairs. + type: str + bits: + description: + - 32 or 64 bits support. + type: int + default: 64 + choices: [ 32, 64 ] + display_text: + description: + - Display text of the template. + type: str + state: + description: + - State of the template. + type: str + default: present + choices: [ present, absent, extracted ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: register a systemvm template + ngine_io.cloudstack.cs_template: + name: systemvm-vmware-4.5 + url: "http://packages.shapeblue.com/systemvmtemplate/4.5/systemvm64template-4.5-vmware.ova" + hypervisor: VMware + format: OVA + cross_zones: yes + os_type: Debian GNU/Linux 7(64-bit) + +- name: Create a template from a stopped virtual machine's volume + ngine_io.cloudstack.cs_template: + name: Debian 9 (64-bit) 20GB ({{ ansible_date_time.date }}) + vm: debian-9-base-vm + os_type: Debian GNU/Linux 9 (64-bit) + zone: tokio-ix + password_enabled: yes + is_public: yes + + +# Note: Use template_find_option(s) when a template name is not unique +- name: Create a template from a stopped virtual machine's volume + ngine_io.cloudstack.cs_template: + name: Debian 9 (64-bit) + display_text: Debian 9 (64-bit) 20GB ({{ ansible_date_time.date }}) + template_find_option: display_text + vm: debian-9-base-vm + os_type: Debian GNU/Linux 9 (64-bit) + zone: tokio-ix + password_enabled: yes + is_public: yes + +- name: create a template from a virtual machine's root volume snapshot + ngine_io.cloudstack.cs_template: + name: Debian 9 (64-bit) Snapshot ROOT-233_2015061509114 + snapshot: ROOT-233_2015061509114 + os_type: Debian GNU/Linux 9 (64-bit) + zone: tokio-ix + password_enabled: yes + is_public: yes + +- name: Remove a template + ngine_io.cloudstack.cs_template: + name: systemvm-4.2 + cross_zones: yes + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the template or extracted object. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: Name of the template or extracted object. + returned: success + type: str + sample: Debian 7 64-bit +display_text: + description: Display text of the template. + returned: if available + type: str + sample: Debian 7.7 64-bit minimal 2015-03-19 +checksum: + description: MD5 checksum of the template. + returned: if available + type: str + sample: 0b31bccccb048d20b551f70830bb7ad0 +status: + description: Status of the template or extracted object. + returned: success + type: str + sample: Download Complete +is_ready: + description: True if the template is ready to be deployed from. + returned: if available + type: bool + sample: true +is_public: + description: True if the template is public. + returned: if available + type: bool + sample: true +is_featured: + description: True if the template is featured. + returned: if available + type: bool + sample: true +is_extractable: + description: True if the template is extractable. + returned: if available + type: bool + sample: true +format: + description: Format of the template. + returned: if available + type: str + sample: OVA +os_type: + description: Type of the OS. + returned: if available + type: str + sample: CentOS 6.5 (64-bit) +password_enabled: + description: True if the reset password feature is enabled, false otherwise. + returned: if available + type: bool + sample: false +sshkey_enabled: + description: true if template is sshkey enabled, false otherwise. + returned: if available + type: bool + sample: false +cross_zones: + description: true if the template is managed across all zones, false otherwise. + returned: if available + type: bool + sample: false +template_type: + description: Type of the template. + returned: if available + type: str + sample: USER +created: + description: Date of registering. + returned: success + type: str + sample: 2015-03-29T14:57:06+0200 +template_tag: + description: Template tag related to this template. + returned: if available + type: str + sample: special +hypervisor: + description: Hypervisor related to this template. + returned: if available + type: str + sample: VMware +mode: + description: Mode of extraction + returned: on state=extracted + type: str + sample: http_download +state: + description: State of the extracted template + returned: on state=extracted + type: str + sample: DOWNLOAD_URL_CREATED +url: + description: Url to which the template is extracted to + returned: on state=extracted + type: str + sample: "http://1.2.3.4/userdata/eb307f13-4aca-45e8-b157-a414a14e6b04.ova" +tags: + description: List of resource tags associated with the template. + returned: if available + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +zone: + description: Name of zone the template is registered in. + returned: success + type: str + sample: zuerich +domain: + description: Domain the template is related to. + returned: success + type: str + sample: example domain +account: + description: Account the template is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the template is related to. + returned: success + type: str + sample: Production +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackTemplate(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackTemplate, self).__init__(module) + self.returns = { + 'checksum': 'checksum', + 'status': 'status', + 'isready': 'is_ready', + 'templatetag': 'template_tag', + 'sshkeyenabled': 'sshkey_enabled', + 'passwordenabled': 'password_enabled', + 'templatetype': 'template_type', + 'ostypename': 'os_type', + 'crossZones': 'cross_zones', + 'format': 'format', + 'hypervisor': 'hypervisor', + 'url': 'url', + 'extractMode': 'mode', + 'state': 'state', + } + + def _get_args(self): + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'bits': self.module.params.get('bits'), + 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'), + 'isextractable': self.module.params.get('is_extractable'), + 'isfeatured': self.module.params.get('is_featured'), + 'ispublic': self.module.params.get('is_public'), + 'passwordenabled': self.module.params.get('password_enabled'), + 'requireshvm': self.module.params.get('requires_hvm'), + 'templatetag': self.module.params.get('template_tag'), + 'ostypeid': self.get_os_type(key='id'), + } + + if not args['ostypeid']: + self.module.fail_json(msg="Missing required arguments: os_type") + + return args + + def get_root_volume(self, key=None): + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'virtualmachineid': self.get_vm(key='id'), + 'type': "ROOT" + } + volumes = self.query_api('listVolumes', **args) + if volumes: + return self._get_by_key(key, volumes['volume'][0]) + self.module.fail_json(msg="Root volume for '%s' not found" % self.get_vm('name')) + + def get_snapshot(self, key=None): + snapshot = self.module.params.get('snapshot') + if not snapshot: + return None + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'volumeid': self.get_root_volume('id'), + 'fetch_list': True, + } + snapshots = self.query_api('listSnapshots', **args) + if snapshots: + for s in snapshots: + if snapshot in [s['name'], s['id']]: + return self._get_by_key(key, s) + self.module.fail_json(msg="Snapshot '%s' not found" % snapshot) + + def present_template(self): + template = self.get_template() + if template: + template = self.update_template(template) + elif self.module.params.get('url'): + template = self.register_template() + elif self.module.params.get('vm'): + template = self.create_template() + else: + self.fail_json(msg="one of the following is required on state=present: url, vm") + return template + + def create_template(self): + template = None + self.result['changed'] = True + + args = self._get_args() + snapshot_id = self.get_snapshot(key='id') + if snapshot_id: + args['snapshotid'] = snapshot_id + else: + args['volumeid'] = self.get_root_volume('id') + + if not self.module.check_mode: + template = self.query_api('createTemplate', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + template = self.poll_job(template, 'template') + + if template: + template = self.ensure_tags(resource=template, resource_type='Template') + + return template + + def register_template(self): + required_params = [ + 'format', + 'url', + 'hypervisor', + ] + self.module.fail_on_missing_params(required_params=required_params) + template = None + self.result['changed'] = True + args = self._get_args() + args.update({ + 'url': self.module.params.get('url'), + 'format': self.module.params.get('format'), + 'checksum': self.module.params.get('checksum'), + 'isextractable': self.module.params.get('is_extractable'), + 'isrouting': self.module.params.get('is_routing'), + 'sshkeyenabled': self.module.params.get('sshkey_enabled'), + 'hypervisor': self.get_hypervisor(), + 'domainid': self.get_domain(key='id'), + 'account': self.get_account(key='name'), + 'projectid': self.get_project(key='id'), + }) + + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + else: + args['zoneid'] = -1 + + if not self.module.check_mode: + self.query_api('registerTemplate', **args) + template = self.get_template() + return template + + def update_template(self, template): + args = { + 'id': template['id'], + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'format': self.module.params.get('format'), + 'isdynamicallyscalable': self.module.params.get('is_dynamically_scalable'), + 'isrouting': self.module.params.get('is_routing'), + 'ostypeid': self.get_os_type(key='id'), + 'passwordenabled': self.module.params.get('password_enabled'), + } + if self.has_changed(args, template): + self.result['changed'] = True + if not self.module.check_mode: + self.query_api('updateTemplate', **args) + template = self.get_template() + + args = { + 'id': template['id'], + 'isextractable': self.module.params.get('is_extractable'), + 'isfeatured': self.module.params.get('is_featured'), + 'ispublic': self.module.params.get('is_public'), + } + if self.has_changed(args, template): + self.result['changed'] = True + if not self.module.check_mode: + self.query_api('updateTemplatePermissions', **args) + # Refresh + template = self.get_template() + + if template: + template = self.ensure_tags(resource=template, resource_type='Template') + + return template + + def _is_find_option(self, param_name): + return param_name in self.module.params.get('template_find_options') + + def _find_option_match(self, template, param_name, internal_name=None): + if not internal_name: + internal_name = param_name + + if param_name in self.module.params.get('template_find_options'): + param_value = self.module.params.get(param_name) + + if not param_value: + self.fail_json(msg="The param template_find_options has %s but param was not provided." % param_name) + + if template[internal_name] == param_value: + return True + return False + + def get_template(self): + args = { + 'name': self.module.params.get('name'), + 'templatefilter': self.module.params.get('template_filter'), + 'domainid': self.get_domain(key='id'), + 'account': self.get_account(key='name'), + 'projectid': self.get_project(key='id') + } + + cross_zones = self.module.params.get('cross_zones') + if not cross_zones: + args['zoneid'] = self.get_zone(key='id') + + template_found = None + + templates = self.query_api('listTemplates', **args) + if templates: + for tmpl in templates['template']: + + if self._is_find_option('cross_zones') and not self._find_option_match( + template=tmpl, + param_name='cross_zones', + internal_name='crossZones'): + continue + + if self._is_find_option('checksum') and not self._find_option_match( + template=tmpl, + param_name='checksum'): + continue + + if self._is_find_option('display_text') and not self._find_option_match( + template=tmpl, + param_name='display_text', + internal_name='displaytext'): + continue + + if not template_found: + template_found = tmpl + # A cross zones template has one entry per zone but the same id + elif tmpl['id'] == template_found['id']: + continue + else: + self.fail_json(msg="Multiple templates found matching provided params. Please use template_find_options.") + + return template_found + + def extract_template(self): + template = self.get_template() + if not template: + self.module.fail_json(msg="Failed: template not found") + + if self.module.params.get('cross_zones'): + self.module.warn('cross_zones parameter is ignored when state is extracted') + + args = { + 'id': template['id'], + 'url': self.module.params.get('url'), + 'mode': self.module.params.get('mode'), + 'zoneid': self.get_zone(key='id') + } + self.result['changed'] = True + + if not self.module.check_mode: + template = self.query_api('extractTemplate', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + template = self.poll_job(template, 'template') + return template + + def remove_template(self): + template = self.get_template() + if template: + self.result['changed'] = True + + args = { + 'id': template['id'] + } + if not self.module.params.get('cross_zones'): + args['zoneid'] = self.get_zone(key='id') + + if not self.module.check_mode: + res = self.query_api('deleteTemplate', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + res = self.poll_job(res, 'template') + return template + + def get_result(self, template): + super(AnsibleCloudStackTemplate, self).get_result(template) + if template: + if 'isextractable' in template: + self.result['is_extractable'] = True if template['isextractable'] else False + if 'isfeatured' in template: + self.result['is_featured'] = True if template['isfeatured'] else False + if 'ispublic' in template: + self.result['is_public'] = True if template['ispublic'] else False + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + url=dict(), + vm=dict(), + snapshot=dict(), + os_type=dict(), + is_public=dict(type='bool'), + is_featured=dict(type='bool'), + is_dynamically_scalable=dict(type='bool'), + is_extractable=dict(type='bool'), + is_routing=dict(type='bool'), + checksum=dict(), + template_filter=dict(default='self', choices=['all', 'featured', 'self', 'selfexecutable', 'sharedexecutable', 'executable', 'community']), + template_find_options=dict( + type='list', + elements='str', + choices=['display_text', 'checksum', 'cross_zones'], + aliases=['template_find_option'], + default=[], + ), + hypervisor=dict(), + requires_hvm=dict(type='bool'), + password_enabled=dict(type='bool', no_log=False), + template_tag=dict(), + sshkey_enabled=dict(type='bool'), + format=dict(choices=['QCOW2', 'RAW', 'VHD', 'OVA']), + details=dict(), + bits=dict(type='int', choices=[32, 64], default=64), + state=dict(choices=['present', 'absent', 'extracted'], default='present'), + cross_zones=dict(type='bool', default=False), + mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['url', 'vm'], + ['zone', 'cross_zones'], + ), + supports_check_mode=True + ) + + acs_tpl = AnsibleCloudStackTemplate(module) + + state = module.params.get('state') + if state == 'absent': + tpl = acs_tpl.remove_template() + + elif state == 'extracted': + tpl = acs_tpl.extract_template() + else: + tpl = acs_tpl.present_template() + + result = acs_tpl.get_result(tpl) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py new file mode 100644 index 00000000..22ec3ec3 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_traffic_type.py @@ -0,0 +1,321 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2019, Patryk D. Cichy <patryk.d.cichy@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_traffic_type +short_description: Manages traffic types on CloudStack Physical Networks +description: + - Add, remove, update Traffic Types associated with CloudStack Physical Networks. +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +author: + - Patryk Cichy (@PatTheSilent) +version_added: 0.1.0 +options: + physical_network: + description: + - the name of the Physical Network + required: true + type: str + zone: + description: + - Name of the zone with the physical network. + - Default zone will be used if this is empty. + type: str + traffic_type: + description: + - the trafficType to be added to the physical network. + required: true + choices: [Management, Guest, Public, Storage] + type: str + state: + description: + - State of the traffic type + choices: [present, absent] + default: present + type: str + hyperv_networklabel: + description: + - The network name label of the physical device dedicated to this traffic on a HyperV host. + type: str + isolation_method: + description: + - Use if the physical network has multiple isolation types and traffic type is public. + choices: [vlan, vxlan] + type: str + kvm_networklabel: + description: + - The network name label of the physical device dedicated to this traffic on a KVM host. + type: str + ovm3_networklabel: + description: + - The network name of the physical device dedicated to this traffic on an OVM3 host. + type: str + vlan: + description: + - The VLAN id to be used for Management traffic by VMware host. + type: str + vmware_networklabel: + description: + - The network name label of the physical device dedicated to this traffic on a VMware host. + type: str + xen_networklabel: + description: + - The network name label of the physical device dedicated to this traffic on a XenServer host. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +''' + +EXAMPLES = ''' +- name: add a traffic type + ngine_io.cloudstack.cs_traffic_type: + physical_network: public-network + traffic_type: Guest + zone: test-zone + +- name: update traffic type + ngine_io.cloudstack.cs_traffic_type: + physical_network: public-network + traffic_type: Guest + kvm_networklabel: cloudbr0 + zone: test-zone + +- name: remove traffic type + ngine_io.cloudstack.cs_traffic_type: + physical_network: public-network + traffic_type: Public + state: absent + zone: test-zone +''' + +RETURN = ''' +--- +id: + description: ID of the network provider + returned: success + type: str + sample: 659c1840-9374-440d-a412-55ca360c9d3c +traffic_type: + description: the trafficType that was added to the physical network + returned: success + type: str + sample: Public +hyperv_networklabel: + description: The network name label of the physical device dedicated to this traffic on a HyperV host + returned: success + type: str + sample: HyperV Internal Switch +kvm_networklabel: + description: The network name label of the physical device dedicated to this traffic on a KVM host + returned: success + type: str + sample: cloudbr0 +ovm3_networklabel: + description: The network name of the physical device dedicated to this traffic on an OVM3 host + returned: success + type: str + sample: cloudbr0 +physical_network: + description: the physical network this belongs to + returned: success + type: str + sample: 28ed70b7-9a1f-41bf-94c3-53a9f22da8b6 +vmware_networklabel: + description: The network name label of the physical device dedicated to this traffic on a VMware host + returned: success + type: str + sample: Management Network +xen_networklabel: + description: The network name label of the physical device dedicated to this traffic on a XenServer host + returned: success + type: str + sample: xenbr0 +zone: + description: Name of zone the physical network is in. + returned: success + type: str + sample: ch-gva-2 +''' + +from ..module_utils.cloudstack import AnsibleCloudStack, cs_argument_spec, cs_required_together +from ansible.module_utils.basic import AnsibleModule + + +class AnsibleCloudStackTrafficType(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackTrafficType, self).__init__(module) + self.returns = { + 'traffictype': 'traffic_type', + 'hypervnetworklabel': 'hyperv_networklabel', + 'kvmnetworklabel': 'kvm_networklabel', + 'ovm3networklabel': 'ovm3_networklabel', + 'physicalnetworkid': 'physical_network', + 'vmwarenetworklabel': 'vmware_networklabel', + 'xennetworklabel': 'xen_networklabel' + } + + self.traffic_type = None + + def _get_label_args(self): + label_args = dict() + if self.module.params.get('hyperv_networklabel'): + label_args.update(dict(hypervnetworklabel=self.module.params.get('hyperv_networklabel'))) + if self.module.params.get('kvm_networklabel'): + label_args.update(dict(kvmnetworklabel=self.module.params.get('kvm_networklabel'))) + if self.module.params.get('ovm3_networklabel'): + label_args.update(dict(ovm3networklabel=self.module.params.get('ovm3_networklabel'))) + if self.module.params.get('vmware_networklabel'): + label_args.update(dict(vmwarenetworklabel=self.module.params.get('vmware_networklabel'))) + return label_args + + def _get_additional_args(self): + additional_args = dict() + + if self.module.params.get('isolation_method'): + additional_args.update(dict(isolationmethod=self.module.params.get('isolation_method'))) + + if self.module.params.get('vlan'): + additional_args.update(dict(vlan=self.module.params.get('vlan'))) + + additional_args.update(self._get_label_args()) + + return additional_args + + def get_traffic_types(self): + args = { + 'physicalnetworkid': self.get_physical_network(key='id') + } + traffic_types = self.query_api('listTrafficTypes', **args) + return traffic_types + + def get_traffic_type(self): + if self.traffic_type: + return self.traffic_type + + traffic_type = self.module.params.get('traffic_type') + + traffic_types = self.get_traffic_types() + + if traffic_types: + for t_type in traffic_types['traffictype']: + if traffic_type.lower() in [t_type['traffictype'].lower(), t_type['id']]: + self.traffic_type = t_type + break + return self.traffic_type + + def present_traffic_type(self): + traffic_type = self.get_traffic_type() + if traffic_type: + self.traffic_type = self.update_traffic_type() + else: + self.result['changed'] = True + self.traffic_type = self.add_traffic_type() + + return self.traffic_type + + def add_traffic_type(self): + traffic_type = self.module.params.get('traffic_type') + args = { + 'physicalnetworkid': self.get_physical_network(key='id'), + 'traffictype': traffic_type + } + args.update(self._get_additional_args()) + if not self.module.check_mode: + resource = self.query_api('addTrafficType', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.traffic_type = self.poll_job(resource, 'traffictype') + return self.traffic_type + + def absent_traffic_type(self): + traffic_type = self.get_traffic_type() + if traffic_type: + + args = { + 'id': traffic_type['id'] + } + self.result['changed'] = True + if not self.module.check_mode: + resource = self.query_api('deleteTrafficType', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(resource, 'traffictype') + + return traffic_type + + def update_traffic_type(self): + + traffic_type = self.get_traffic_type() + args = { + 'id': traffic_type['id'] + } + args.update(self._get_label_args()) + if self.has_changed(args, traffic_type): + self.result['changed'] = True + if not self.module.check_mode: + resource = self.query_api('updateTrafficType', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.traffic_type = self.poll_job(resource, 'traffictype') + + return self.traffic_type + + +def setup_module_object(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + physical_network=dict(required=True), + zone=dict(), + state=dict(choices=['present', 'absent'], default='present'), + traffic_type=dict(required=True, choices=['Management', 'Guest', 'Public', 'Storage']), + hyperv_networklabel=dict(), + isolation_method=dict(choices=['vlan', 'vxlan']), + kvm_networklabel=dict(), + ovm3_networklabel=dict(), + vlan=dict(), + vmware_networklabel=dict(), + xen_networklabel=dict(), + poll_async=dict(type='bool', default=True) + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + return module + + +def execute_module(module): + actt = AnsibleCloudStackTrafficType(module) + state = module.params.get('state') + + if state in ['present']: + result = actt.present_traffic_type() + else: + result = actt.absent_traffic_type() + + return actt.get_result(result) + + +def main(): + module = setup_module_object() + result = execute_module(module) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py new file mode 100644 index 00000000..816e5f70 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_user.py @@ -0,0 +1,436 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_user +short_description: Manages users on Apache CloudStack based clouds. +description: + - Create, update, disable, lock, enable and remove users. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + username: + description: + - Username of the user. + type: str + required: true + account: + description: + - Account the user will be created under. + - Required on I(state=present). + type: str + password: + description: + - Password of the user to be created. + - Required on I(state=present). + - Only considered on creation and will not be updated if user exists. + type: str + first_name: + description: + - First name of the user. + - Required on I(state=present). + type: str + last_name: + description: + - Last name of the user. + - Required on I(state=present). + type: str + email: + description: + - Email of the user. + - Required on I(state=present). + type: str + timezone: + description: + - Timezone of the user. + type: str + keys_registered: + description: + - If API keys of the user should be generated. + - "Note: Keys can not be removed by the API again." + type: bool + default: no + domain: + description: + - Domain the user is related to. + type: str + default: ROOT + state: + description: + - State of the user. + - C(unlocked) is an alias for C(enabled). + type: str + default: present + choices: [ present, absent, enabled, disabled, locked, unlocked ] + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create an user in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_user: + account: developers + username: johndoe + password: S3Cur3 + last_name: Doe + first_name: John + email: john.doe@example.com + domain: CUSTOMERS + +- name: Lock an existing user in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_user: + username: johndoe + domain: CUSTOMERS + state: locked + +- name: Disable an existing user in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_user: + username: johndoe + domain: CUSTOMERS + state: disabled + +- name: Enable/unlock an existing user in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_user: + username: johndoe + domain: CUSTOMERS + state: enabled + +- name: Remove an user in domain 'CUSTOMERS' + ngine_io.cloudstack.cs_user: + name: customer_xy + domain: CUSTOMERS + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the user. + returned: success + type: str + sample: 87b1e0ce-4e01-11e4-bb66-0050569e64b8 +username: + description: Username of the user. + returned: success + type: str + sample: johndoe +fist_name: + description: First name of the user. + returned: success + type: str + sample: John +last_name: + description: Last name of the user. + returned: success + type: str + sample: Doe +email: + description: Emailof the user. + returned: success + type: str + sample: john.doe@example.com +user_api_key: + description: API key of the user. + returned: success + type: str + sample: JLhcg8VWi8DoFqL2sSLZMXmGojcLnFrOBTipvBHJjySODcV4mCOo29W2duzPv5cALaZnXj5QxDx3xQfaQt3DKg +user_api_secret: + description: API secret of the user. + returned: success + type: str + sample: FUELo3LB9fa1UopjTLPdqLv_6OXQMJZv9g9N4B_Ao3HFz8d6IGFCV9MbPFNM8mwz00wbMevja1DoUNDvI8C9-g +account: + description: Account name of the user. + returned: success + type: str + sample: developers +account_type: + description: Type of the account. + returned: success + type: str + sample: user +timezone: + description: Timezone of the user. + returned: success + type: str + sample: enabled +created: + description: Date the user was created. + returned: success + type: str + sample: Doe +state: + description: State of the user. + returned: success + type: str + sample: enabled +domain: + description: Domain the user is related. + returned: success + type: str + sample: ROOT +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackUser(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackUser, self).__init__(module) + self.returns = { + 'username': 'username', + 'firstname': 'first_name', + 'lastname': 'last_name', + 'email': 'email', + 'secretkey': 'user_api_secret', + 'apikey': 'user_api_key', + 'timezone': 'timezone', + } + self.account_types = { + 'user': 0, + 'root_admin': 1, + 'domain_admin': 2, + } + self.user = None + + def get_account_type(self): + account_type = self.module.params.get('account_type') + return self.account_types[account_type] + + def get_user(self): + if not self.user: + args = { + 'domainid': self.get_domain('id'), + 'fetch_list': True, + } + + users = self.query_api('listUsers', **args) + + if users: + user_name = self.module.params.get('username') + for u in users: + if user_name.lower() == u['username'].lower(): + self.user = u + break + return self.user + + def enable_user(self): + user = self.get_user() + if not user: + user = self.present_user() + + if user['state'].lower() != 'enabled': + self.result['changed'] = True + args = { + 'id': user['id'], + } + if not self.module.check_mode: + res = self.query_api('enableUser', **args) + user = res['user'] + return user + + def lock_user(self): + user = self.get_user() + if not user: + user = self.present_user() + + # we need to enable the user to lock it. + if user['state'].lower() == 'disabled': + user = self.enable_user() + + if user['state'].lower() != 'locked': + self.result['changed'] = True + + args = { + 'id': user['id'], + } + + if not self.module.check_mode: + res = self.query_api('lockUser', **args) + user = res['user'] + + return user + + def disable_user(self): + user = self.get_user() + if not user: + user = self.present_user() + + if user['state'].lower() != 'disabled': + self.result['changed'] = True + args = { + 'id': user['id'], + } + if not self.module.check_mode: + user = self.query_api('disableUser', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + user = self.poll_job(user, 'user') + return user + + def present_user(self): + required_params = [ + 'account', + 'email', + 'password', + 'first_name', + 'last_name', + ] + self.module.fail_on_missing_params(required_params=required_params) + + user = self.get_user() + if user: + user = self._update_user(user) + else: + user = self._create_user(user) + return user + + def _get_common_args(self): + return { + 'firstname': self.module.params.get('first_name'), + 'lastname': self.module.params.get('last_name'), + 'email': self.module.params.get('email'), + 'timezone': self.module.params.get('timezone'), + } + + def _create_user(self, user): + self.result['changed'] = True + + args = self._get_common_args() + args.update({ + 'account': self.get_account(key='name'), + 'domainid': self.get_domain('id'), + 'username': self.module.params.get('username'), + 'password': self.module.params.get('password'), + }) + + if not self.module.check_mode: + res = self.query_api('createUser', **args) + user = res['user'] + + # register user api keys + if self.module.params.get('keys_registered'): + res = self.query_api('registerUserKeys', id=user['id']) + user.update(res['userkeys']) + + return user + + def _update_user(self, user): + args = self._get_common_args() + args.update({ + 'id': user['id'], + }) + + if self.has_changed(args, user): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateUser', **args) + + user = res['user'] + + # register user api keys + if 'apikey' not in user and self.module.params.get('keys_registered'): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('registerUserKeys', id=user['id']) + user.update(res['userkeys']) + return user + + def absent_user(self): + user = self.get_user() + if user: + self.result['changed'] = True + + if not self.module.check_mode: + self.query_api('deleteUser', id=user['id']) + + return user + + def get_result(self, user): + super(AnsibleCloudStackUser, self).get_result(user) + if user: + if 'accounttype' in user: + for key, value in self.account_types.items(): + if value == user['accounttype']: + self.result['account_type'] = key + break + + # secretkey has been removed since CloudStack 4.10 from listUsers API + if self.module.params.get('keys_registered') and 'apikey' in user and 'secretkey' not in user: + user_keys = self.query_api('getUserKeys', id=user['id']) + if user_keys: + self.result['user_api_secret'] = user_keys['userkeys'].get('secretkey') + + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + username=dict(required=True), + account=dict(), + state=dict(choices=['present', 'absent', 'enabled', 'disabled', 'locked', 'unlocked'], default='present'), + domain=dict(default='ROOT'), + email=dict(), + first_name=dict(), + last_name=dict(), + password=dict(no_log=True), + timezone=dict(), + keys_registered=dict(type='bool', default=False), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_acc = AnsibleCloudStackUser(module) + + state = module.params.get('state') + + if state == 'absent': + user = acs_acc.absent_user() + + elif state in ['enabled', 'unlocked']: + user = acs_acc.enable_user() + + elif state == 'disabled': + user = acs_acc.disable_user() + + elif state == 'locked': + user = acs_acc.lock_user() + + else: + user = acs_acc.present_user() + + result = acs_acc.get_result(user) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py new file mode 100644 index 00000000..aaca4158 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vlan_ip_range.py @@ -0,0 +1,397 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, David Passante <@dpassante> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_vlan_ip_range +short_description: Manages VLAN IP ranges on Apache CloudStack based clouds. +description: + - Create and delete VLAN IP range. +author: David Passante (@dpassante) +version_added: 0.1.0 +options: + network: + description: + - The network name or id. + - Required if I(for_virtual_network) and I(physical_network) are not set. + type: str + physical_network: + description: + - The physical network name or id. + type: str + start_ip: + description: + - The beginning IPv4 address in the VLAN IP range. + - Only considered on create. + type: str + required: true + end_ip: + description: + - The ending IPv4 address in the VLAN IP range. + - If not specified, value of I(start_ip) is used. + - Only considered on create. + type: str + gateway: + description: + - The gateway of the VLAN IP range. + - Required if I(state=present). + type: str + netmask: + description: + - The netmask of the VLAN IP range. + - Required if I(state=present). + type: str + start_ipv6: + description: + - The beginning IPv6 address in the IPv6 network range. + - Only considered on create. + type: str + end_ipv6: + description: + - The ending IPv6 address in the IPv6 network range. + - If not specified, value of I(start_ipv6) is used. + - Only considered on create. + type: str + gateway_ipv6: + description: + - The gateway of the IPv6 network. + - Only considered on create. + type: str + cidr_ipv6: + description: + - The CIDR of IPv6 network, must be at least /64. + type: str + vlan: + description: + - The ID or VID of the network. + - If not specified, will be defaulted to the vlan of the network. + type: str + pod: + description: + - Name of the pod. + type: str + version_added: 1.0.0 + state: + description: + - State of the network ip range. + type: str + default: present + choices: [ present, absent ] + zone: + description: + - The Zone ID of the VLAN IP range. + - If not set, default zone is used. + type: str + domain: + description: + - Domain of the account owning the VLAN. + type: str + account: + description: + - Account who owns the VLAN. + - Mutually exclusive with I(project). + type: str + project: + description: + - Project who owns the VLAN. + - Mutually exclusive with I(account). + type: str + for_virtual_network: + description: + - C(yes) if VLAN is of Virtual type, C(no) if Direct. + - If set to C(yes) but neither I(physical_network) or I(network) is set CloudStack will try to add the + VLAN range to the Physical Network with a Public traffic type. + type: bool + default: no + version_added: 1.0.0 + for_system_vms: + description: + - C(yes) if IP range is set to system vms, C(no) if not + type: bool + default: no +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create a VLAN IP range for network test + ngine_io.cloudstack.cs_vlan_ip_range: + network: test + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: zone-02 + +- name: remove a VLAN IP range for network test + ngine_io.cloudstack.cs_vlan_ip_range: + state: absent + network: test + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + zone: zone-02 +''' + +RETURN = ''' +--- +id: + description: UUID of the VLAN IP range. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +network: + description: The network of vlan range + returned: if available + type: str + sample: test +vlan: + description: The ID or VID of the VLAN. + returned: success + type: str + sample: vlan://98 +gateway: + description: IPv4 gateway. + returned: success + type: str + sample: 10.2.4.1 +netmask: + description: IPv4 netmask. + returned: success + type: str + sample: 255.255.255.0 +gateway_ipv6: + description: IPv6 gateway. + returned: if available + type: str + sample: 2001:db8::1 +cidr_ipv6: + description: The CIDR of IPv6 network. + returned: if available + type: str + sample: 2001:db8::/64 +zone: + description: Name of zone. + returned: success + type: str + sample: zone-02 +domain: + description: Domain name of the VLAN IP range. + returned: success + type: str + sample: ROOT +account: + description: Account who owns the network. + returned: if available + type: str + sample: example account +project: + description: Project who owns the network. + returned: if available + type: str + sample: example project +for_systemvms: + description: Whether VLAN IP range is dedicated to system vms or not. + returned: success + type: bool + sample: false +for_virtual_network: + description: Whether VLAN IP range is of Virtual type or not. + returned: success + type: bool + sample: false +physical_network: + description: The physical network VLAN IP range belongs to. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +start_ip: + description: The start ip of the VLAN IP range. + returned: success + type: str + sample: 10.2.4.10 +end_ip: + description: The end ip of the VLAN IP range. + returned: success + type: str + sample: 10.2.4.100 +start_ipv6: + description: The start ipv6 of the VLAN IP range. + returned: if available + type: str + sample: 2001:db8::10 +end_ipv6: + description: The end ipv6 of the VLAN IP range. + returned: if available + type: str + sample: 2001:db8::50 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackVlanIpRange(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVlanIpRange, self).__init__(module) + self.returns = { + 'startip': 'start_ip', + 'endip': 'end_ip', + 'physicalnetworkid': 'physical_network', + 'vlan': 'vlan', + 'forsystemvms': 'for_systemvms', + 'forvirtualnetwork': 'for_virtual_network', + 'gateway': 'gateway', + 'netmask': 'netmask', + 'ip6gateway': 'gateway_ipv6', + 'ip6cidr': 'cidr_ipv6', + 'startipv6': 'start_ipv6', + 'endipv6': 'end_ipv6', + } + self.ip_range = None + + def get_vlan_ip_range(self): + if not self.ip_range: + args = { + 'zoneid': self.get_zone(key='id'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'networkid': self.get_network(key='id'), + } + + res = self.query_api('listVlanIpRanges', **args) + if res: + ip_range_list = res['vlaniprange'] + + params = { + 'startip': self.module.params.get('start_ip'), + 'endip': self.get_or_fallback('end_ip', 'start_ip'), + } + + for ipr in ip_range_list: + if params['startip'] == ipr['startip'] and params['endip'] == ipr['endip']: + self.ip_range = ipr + break + + return self.ip_range + + def present_vlan_ip_range(self): + ip_range = self.get_vlan_ip_range() + + if not ip_range: + ip_range = self.create_vlan_ip_range() + + return ip_range + + def create_vlan_ip_range(self): + self.result['changed'] = True + + vlan = self.module.params.get('vlan') + + args = { + 'zoneid': self.get_zone(key='id'), + 'projectid': self.get_project(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'startip': self.module.params.get('start_ip'), + 'endip': self.get_or_fallback('end_ip', 'start_ip'), + 'netmask': self.module.params.get('netmask'), + 'gateway': self.module.params.get('gateway'), + 'startipv6': self.module.params.get('start_ipv6'), + 'endipv6': self.get_or_fallback('end_ipv6', 'start_ipv6'), + 'ip6gateway': self.module.params.get('gateway_ipv6'), + 'ip6cidr': self.module.params.get('cidr_ipv6'), + 'vlan': self.get_network(key='vlan') if not vlan else vlan, + 'networkid': self.get_network(key='id'), + 'forvirtualnetwork': self.module.params.get('for_virtual_network'), + 'forsystemvms': self.module.params.get('for_system_vms'), + 'podid': self.get_pod(key='id'), + } + if self.module.params.get('physical_network'): + args['physicalnetworkid'] = self.get_physical_network(key='id') + + if not self.module.check_mode: + res = self.query_api('createVlanIpRange', **args) + + self.ip_range = res['vlan'] + + return self.ip_range + + def absent_vlan_ip_range(self): + ip_range = self.get_vlan_ip_range() + + if ip_range: + self.result['changed'] = True + + args = { + 'id': ip_range['id'], + } + + if not self.module.check_mode: + self.query_api('deleteVlanIpRange', **args) + + return ip_range + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + network=dict(type='str'), + physical_network=dict(type='str'), + zone=dict(type='str'), + start_ip=dict(type='str', required=True), + end_ip=dict(type='str'), + gateway=dict(type='str'), + netmask=dict(type='str'), + start_ipv6=dict(type='str'), + end_ipv6=dict(type='str'), + gateway_ipv6=dict(type='str'), + cidr_ipv6=dict(type='str'), + vlan=dict(type='str'), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(type='str'), + account=dict(type='str'), + project=dict(type='str'), + pod=dict(type='str'), + for_virtual_network=dict(type='bool', default=False), + for_system_vms=dict(type='bool', default=False), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['account', 'project'], + ), + required_if=(("state", "present", ("gateway", "netmask")),), + supports_check_mode=True, + ) + + acs_vlan_ip_range = AnsibleCloudStackVlanIpRange(module) + + state = module.params.get('state') + if state == 'absent': + ipr = acs_vlan_ip_range.absent_vlan_ip_range() + + else: + ipr = acs_vlan_ip_range.present_vlan_ip_range() + + result = acs_vlan_ip_range.get_result(ipr) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py new file mode 100644 index 00000000..83b77a70 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vmsnapshot.py @@ -0,0 +1,278 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_vmsnapshot +short_description: Manages VM snapshots on Apache CloudStack based clouds. +description: + - Create, remove and revert VM from snapshots. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Unique Name of the snapshot. In CloudStack terms display name. + type: str + required: true + aliases: [ display_name ] + vm: + description: + - Name of the virtual machine. + type: str + required: true + description: + description: + - Description of the snapshot. + type: str + snapshot_memory: + description: + - Snapshot memory if set to true. + default: no + type: bool + zone: + description: + - Name of the zone in which the VM is in. If not set, default zone is used. + type: str + project: + description: + - Name of the project the VM is assigned to. + type: str + state: + description: + - State of the snapshot. + type: str + default: present + choices: [ present, absent, revert ] + domain: + description: + - Domain the VM snapshot is related to. + type: str + account: + description: + - Account the VM snapshot is related to. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a VM snapshot of disk and memory before an upgrade + ngine_io.cloudstack.cs_vmsnapshot: + name: Snapshot before upgrade + vm: web-01 + snapshot_memory: yes + +- name: Revert a VM to a snapshot after a failed upgrade + ngine_io.cloudstack.cs_vmsnapshot: + name: Snapshot before upgrade + vm: web-01 + state: revert + +- name: Remove a VM snapshot after successful upgrade + ngine_io.cloudstack.cs_vmsnapshot: + name: Snapshot before upgrade + vm: web-01 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the snapshot. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: Name of the snapshot. + returned: success + type: str + sample: snapshot before update +display_name: + description: Display name of the snapshot. + returned: success + type: str + sample: snapshot before update +created: + description: date of the snapshot. + returned: success + type: str + sample: 2015-03-29T14:57:06+0200 +current: + description: true if the snapshot is current + returned: success + type: bool + sample: True +state: + description: state of the vm snapshot + returned: success + type: str + sample: Allocated +type: + description: type of vm snapshot + returned: success + type: str + sample: DiskAndMemory +description: + description: description of vm snapshot + returned: success + type: str + sample: snapshot brought to you by Ansible +domain: + description: Domain the vm snapshot is related to. + returned: success + type: str + sample: example domain +account: + description: Account the vm snapshot is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the vm snapshot is related to. + returned: success + type: str + sample: Production +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackVmSnapshot(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVmSnapshot, self).__init__(module) + self.returns = { + 'type': 'type', + 'current': 'current', + } + + def get_snapshot(self): + args = { + 'virtualmachineid': self.get_vm('id'), + 'account': self.get_account('name'), + 'domainid': self.get_domain('id'), + 'projectid': self.get_project('id'), + 'name': self.module.params.get('name'), + } + snapshots = self.query_api('listVMSnapshot', **args) + if snapshots: + return snapshots['vmSnapshot'][0] + return None + + def create_snapshot(self): + snapshot = self.get_snapshot() + if not snapshot: + self.result['changed'] = True + + args = { + 'virtualmachineid': self.get_vm('id'), + 'name': self.module.params.get('name'), + 'description': self.module.params.get('description'), + 'snapshotmemory': self.module.params.get('snapshot_memory'), + } + if not self.module.check_mode: + res = self.query_api('createVMSnapshot', **args) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + snapshot = self.poll_job(res, 'vmsnapshot') + + if snapshot: + snapshot = self.ensure_tags(resource=snapshot, resource_type='Snapshot') + + return snapshot + + def remove_snapshot(self): + snapshot = self.get_snapshot() + if snapshot: + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('deleteVMSnapshot', vmsnapshotid=snapshot['id']) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + res = self.poll_job(res, 'vmsnapshot') + return snapshot + + def revert_vm_to_snapshot(self): + snapshot = self.get_snapshot() + if snapshot: + self.result['changed'] = True + + if snapshot['state'] != "Ready": + self.module.fail_json(msg="snapshot state is '%s', not ready, could not revert VM" % snapshot['state']) + + if not self.module.check_mode: + res = self.query_api('revertToVMSnapshot', vmsnapshotid=snapshot['id']) + + poll_async = self.module.params.get('poll_async') + if res and poll_async: + res = self.poll_job(res, 'vmsnapshot') + return snapshot + + self.module.fail_json(msg="snapshot not found, could not revert VM") + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True, aliases=['display_name']), + vm=dict(required=True), + description=dict(), + zone=dict(), + snapshot_memory=dict(type='bool', default=False), + state=dict(choices=['present', 'absent', 'revert'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_vmsnapshot = AnsibleCloudStackVmSnapshot(module) + + state = module.params.get('state') + if state in ['revert']: + snapshot = acs_vmsnapshot.revert_vm_to_snapshot() + elif state in ['absent']: + snapshot = acs_vmsnapshot.remove_snapshot() + else: + snapshot = acs_vmsnapshot.create_snapshot() + + result = acs_vmsnapshot.get_result(snapshot) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py new file mode 100644 index 00000000..5947675c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_volume.py @@ -0,0 +1,561 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2015, Jefferson Girão <jefferson@girao.net> +# Copyright (c) 2015, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_volume +short_description: Manages volumes on Apache CloudStack based clouds. +description: + - Create, destroy, attach, detach, extract or upload volumes. +author: + - Jefferson Girão (@jeffersongirao) + - René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the volume. + - I(name) can only contain ASCII letters. + type: str + required: true + account: + description: + - Account the volume is related to. + type: str + device_id: + description: + - ID of the device on a VM the volume is attached to. + - Only considered if I(state) is C(attached). + type: int + custom_id: + description: + - Custom id to the resource. + - Allowed to Root Admins only. + type: str + disk_offering: + description: + - Name of the disk offering to be used. + - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present). + type: str + display_volume: + description: + - Whether to display the volume to the end user or not. + - Allowed to Root Admins only. + type: bool + domain: + description: + - Name of the domain the volume to be deployed in. + type: str + max_iops: + description: + - Max iops + type: int + min_iops: + description: + - Min iops + type: int + project: + description: + - Name of the project the volume to be deployed in. + type: str + size: + description: + - Size of disk in GB + type: int + snapshot: + description: + - The snapshot name for the disk volume. + - Required one of I(disk_offering), I(snapshot) if volume is not already I(state=present). + type: str + force: + description: + - Force removal of volume even it is attached to a VM. + - Considered on I(state=absent) only. + default: no + type: bool + shrink_ok: + description: + - Whether to allow to shrink the volume. + default: no + type: bool + vm: + description: + - Name of the virtual machine to attach the volume to. + type: str + zone: + description: + - Name of the zone in which the volume should be deployed. + - If not set, default zone is used. + type: str + state: + description: + - State of the volume. + type: str + default: present + choices: [ present, absent, attached, detached, extracted, uploaded ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "To delete all tags, set a empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + url: + description: + - URL to which the volume would be extracted on I(state=extracted) + - or the URL where to download the volume on I(state=uploaded). + - Only considered if I(state) is C(extracted) or C(uploaded). + type: str + mode: + description: + - Mode for the volume extraction. + - Only considered if I(state=extracted). + type: str + choices: [ http_download, ftp_upload ] + default: http_download + format: + description: + - The format for the volume. + - Only considered if I(state=uploaded). + type: str + choices: [ QCOW2, RAW, VHD, VHDX, OVA ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: create volume within project and zone with specified storage options + ngine_io.cloudstack.cs_volume: + name: web-vm-1-volume + project: Integration + zone: ch-zrh-ix-01 + disk_offering: PerfPlus Storage + size: 20 + +- name: create/attach volume to instance + ngine_io.cloudstack.cs_volume: + name: web-vm-1-volume + disk_offering: PerfPlus Storage + size: 20 + vm: web-vm-1 + state: attached + +- name: detach volume + ngine_io.cloudstack.cs_volume: + name: web-vm-1-volume + state: detached + +- name: remove volume + ngine_io.cloudstack.cs_volume: + name: web-vm-1-volume + state: absent + +- name: Extract DATA volume to make it downloadable + ngine_io.cloudstack.cs_volume: + state: extracted + name: web-vm-1-volume + register: data_vol_out + +- name: Create new volume by downloading source volume + ngine_io.cloudstack.cs_volume: + state: uploaded + name: web-vm-1-volume-2 + format: VHD + url: "{{ data_vol_out.url }}" +''' + +RETURN = ''' +id: + description: ID of the volume. + returned: success + type: str + sample: +name: + description: Name of the volume. + returned: success + type: str + sample: web-volume-01 +display_name: + description: Display name of the volume. + returned: success + type: str + sample: web-volume-01 +group: + description: Group the volume belongs to + returned: success + type: str + sample: web +domain: + description: Domain the volume belongs to + returned: success + type: str + sample: example domain +project: + description: Project the volume belongs to + returned: success + type: str + sample: Production +zone: + description: Name of zone the volume is in. + returned: success + type: str + sample: ch-gva-2 +created: + description: Date of the volume was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +attached: + description: Date of the volume was attached. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +type: + description: Disk volume type. + returned: success + type: str + sample: DATADISK +size: + description: Size of disk volume. + returned: success + type: int + sample: 20 +vm: + description: Name of the vm the volume is attached to (not returned when detached) + returned: success + type: str + sample: web-01 +state: + description: State of the volume + returned: success + type: str + sample: Attached +device_id: + description: Id of the device on user vm the volume is attached to (not returned when detached) + returned: success + type: int + sample: 1 +url: + description: The url of the uploaded volume or the download url depending extraction mode. + returned: success when I(state=extracted) + type: str + sample: http://1.12.3.4/userdata/387e2c7c-7c42-4ecc-b4ed-84e8367a1965.vhd +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_required_together, + cs_argument_spec +) + + +class AnsibleCloudStackVolume(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVolume, self).__init__(module) + self.returns = { + 'group': 'group', + 'attached': 'attached', + 'vmname': 'vm', + 'deviceid': 'device_id', + 'type': 'type', + 'size': 'size', + 'url': 'url', + } + self.volume = None + + def get_volume(self): + if not self.volume: + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'displayvolume': self.module.params.get('display_volume'), + 'type': 'DATADISK', + 'fetch_list': True, + } + # Do not filter on DATADISK when state=extracted + if self.module.params.get('state') == 'extracted': + del args['type'] + + volumes = self.query_api('listVolumes', **args) + if volumes: + volume_name = self.module.params.get('name') + for v in volumes: + if volume_name.lower() == v['name'].lower(): + self.volume = v + break + return self.volume + + def get_snapshot(self, key=None): + snapshot = self.module.params.get('snapshot') + if not snapshot: + return None + + args = { + 'name': snapshot, + 'account': self.get_account('name'), + 'domainid': self.get_domain('id'), + 'projectid': self.get_project('id'), + } + snapshots = self.query_api('listSnapshots', **args) + if snapshots: + return self._get_by_key(key, snapshots['snapshot'][0]) + self.module.fail_json(msg="Snapshot with name %s not found" % snapshot) + + def present_volume(self): + volume = self.get_volume() + if volume: + volume = self.update_volume(volume) + else: + disk_offering_id = self.get_disk_offering(key='id') + snapshot_id = self.get_snapshot(key='id') + + if not disk_offering_id and not snapshot_id: + self.module.fail_json(msg="Required one of: disk_offering,snapshot") + + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'diskofferingid': disk_offering_id, + 'displayvolume': self.module.params.get('display_volume'), + 'maxiops': self.module.params.get('max_iops'), + 'miniops': self.module.params.get('min_iops'), + 'projectid': self.get_project(key='id'), + 'size': self.module.params.get('size'), + 'snapshotid': snapshot_id, + 'zoneid': self.get_zone(key='id') + } + if not self.module.check_mode: + res = self.query_api('createVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + if volume: + volume = self.ensure_tags(resource=volume, resource_type='Volume') + self.volume = volume + + return volume + + def attached_volume(self): + volume = self.present_volume() + + if volume: + if volume.get('virtualmachineid') != self.get_vm(key='id'): + self.result['changed'] = True + + if not self.module.check_mode: + volume = self.detached_volume() + + if 'attached' not in volume: + self.result['changed'] = True + + args = { + 'id': volume['id'], + 'virtualmachineid': self.get_vm(key='id'), + 'deviceid': self.module.params.get('device_id'), + } + if not self.module.check_mode: + res = self.query_api('attachVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + return volume + + def detached_volume(self): + volume = self.present_volume() + + if volume: + if 'attached' not in volume: + return volume + + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('detachVolume', id=volume['id']) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + return volume + + def absent_volume(self): + volume = self.get_volume() + + if volume: + if 'attached' in volume and not self.module.params.get('force'): + self.module.fail_json(msg="Volume '%s' is attached, use force=true for detaching and removing the volume." % volume.get('name')) + + self.result['changed'] = True + if not self.module.check_mode: + volume = self.detached_volume() + res = self.query_api('deleteVolume', id=volume['id']) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'volume') + + return volume + + def update_volume(self, volume): + args_resize = { + 'id': volume['id'], + 'diskofferingid': self.get_disk_offering(key='id'), + 'maxiops': self.module.params.get('max_iops'), + 'miniops': self.module.params.get('min_iops'), + 'size': self.module.params.get('size') + } + # change unit from bytes to giga bytes to compare with args + volume_copy = volume.copy() + volume_copy['size'] = volume_copy['size'] / (2**30) + + if self.has_changed(args_resize, volume_copy): + + self.result['changed'] = True + if not self.module.check_mode: + args_resize['shrinkok'] = self.module.params.get('shrink_ok') + res = self.query_api('resizeVolume', **args_resize) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + self.volume = volume + + return volume + + def extract_volume(self): + volume = self.get_volume() + if not volume: + self.module.fail_json(msg="Failed: volume not found") + + args = { + 'id': volume['id'], + 'url': self.module.params.get('url'), + 'mode': self.module.params.get('mode').upper(), + 'zoneid': self.get_zone(key='id') + } + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('extractVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + self.volume = volume + + return volume + + def upload_volume(self): + volume = self.get_volume() + if not volume: + disk_offering_id = self.get_disk_offering(key='id') + + self.result['changed'] = True + + args = { + 'name': self.module.params.get('name'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'format': self.module.params.get('format'), + 'url': self.module.params.get('url'), + 'diskofferingid': disk_offering_id, + } + if not self.module.check_mode: + res = self.query_api('uploadVolume', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + volume = self.poll_job(res, 'volume') + if volume: + volume = self.ensure_tags(resource=volume, resource_type='Volume') + self.volume = volume + + return volume + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + disk_offering=dict(), + display_volume=dict(type='bool'), + max_iops=dict(type='int'), + min_iops=dict(type='int'), + size=dict(type='int'), + snapshot=dict(), + vm=dict(), + device_id=dict(type='int'), + custom_id=dict(), + force=dict(type='bool', default=False), + shrink_ok=dict(type='bool', default=False), + state=dict(default='present', choices=[ + 'present', + 'absent', + 'attached', + 'detached', + 'extracted', + 'uploaded', + ]), + zone=dict(), + domain=dict(), + account=dict(), + project=dict(), + poll_async=dict(type='bool', default=True), + tags=dict(type='list', elements='dict', aliases=['tag']), + url=dict(), + mode=dict(choices=['http_download', 'ftp_upload'], default='http_download'), + format=dict(choices=['QCOW2', 'RAW', 'VHD', 'VHDX', 'OVA']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + mutually_exclusive=( + ['snapshot', 'disk_offering'], + ), + required_if=[ + ('state', 'uploaded', ['url', 'format']), + ], + supports_check_mode=True + ) + + acs_vol = AnsibleCloudStackVolume(module) + + state = module.params.get('state') + + if state in ['absent']: + volume = acs_vol.absent_volume() + elif state in ['attached']: + volume = acs_vol.attached_volume() + elif state in ['detached']: + volume = acs_vol.detached_volume() + elif state == 'extracted': + volume = acs_vol.extract_volume() + elif state == 'uploaded': + volume = acs_vol.upload_volume() + else: + volume = acs_vol.present_volume() + + result = acs_vol.get_result(volume) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py new file mode 100644 index 00000000..45837dd2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc.py @@ -0,0 +1,391 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_vpc +short_description: "Manages VPCs on Apache CloudStack based clouds." +description: + - Create, update and delete VPCs. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the VPC. + type: str + required: true + display_text: + description: + - Display text of the VPC. + - If not set, I(name) will be used for creating. + type: str + cidr: + description: + - CIDR of the VPC, e.g. 10.1.0.0/16 + - All VPC guest networks' CIDRs must be within this CIDR. + - Required on I(state=present). + type: str + network_domain: + description: + - Network domain for the VPC. + - All networks inside the VPC will belong to this domain. + - Only considered while creating the VPC, can not be changed. + type: str + vpc_offering: + description: + - Name of the VPC offering. + - If not set, default VPC offering is used. + type: str + clean_up: + description: + - Whether to redeploy a VPC router or not when I(state=restarted) + type: bool + state: + description: + - State of the VPC. + - The state C(present) creates a started VPC. + - The state C(stopped) is only considered while creating the VPC, added in version 2.6. + type: str + default: present + choices: + - present + - absent + - stopped + - restarted + domain: + description: + - Domain the VPC is related to. + type: str + account: + description: + - Account the VPC is related to. + type: str + project: + description: + - Name of the project the VPC is related to. + type: str + zone: + description: + - Name of the zone. + - If not set, default zone is used. + type: str + tags: + description: + - List of tags. Tags are a list of dictionaries having keys I(key) and I(value). + - "For deleting all tags, set an empty list e.g. I(tags: [])." + type: list + elements: dict + aliases: [ tag ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a VPC is present but not started after creating + ngine_io.cloudstack.cs_vpc: + name: my_vpc + display_text: My example VPC + cidr: 10.10.0.0/16 + state: stopped + +- name: Ensure a VPC is present and started after creating + ngine_io.cloudstack.cs_vpc: + name: my_vpc + display_text: My example VPC + cidr: 10.10.0.0/16 + +- name: Ensure a VPC is absent + ngine_io.cloudstack.cs_vpc: + name: my_vpc + state: absent + +- name: Ensure a VPC is restarted with clean up + ngine_io.cloudstack.cs_vpc: + name: my_vpc + clean_up: yes + state: restarted +''' + +RETURN = ''' +--- +id: + description: "UUID of the VPC." + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: "Name of the VPC." + returned: success + type: str + sample: my_vpc +display_text: + description: "Display text of the VPC." + returned: success + type: str + sample: My example VPC +cidr: + description: "CIDR of the VPC." + returned: success + type: str + sample: 10.10.0.0/16 +network_domain: + description: "Network domain of the VPC." + returned: success + type: str + sample: example.com +region_level_vpc: + description: "Whether the VPC is region level or not." + returned: success + type: bool + sample: true +restart_required: + description: "Whether the VPC router needs a restart or not." + returned: success + type: bool + sample: true +distributed_vpc_router: + description: "Whether the VPC uses distributed router or not." + returned: success + type: bool + sample: true +redundant_vpc_router: + description: "Whether the VPC has redundant routers or not." + returned: success + type: bool + sample: true +domain: + description: "Domain the VPC is related to." + returned: success + type: str + sample: example domain +account: + description: "Account the VPC is related to." + returned: success + type: str + sample: example account +project: + description: "Name of project the VPC is related to." + returned: success + type: str + sample: Production +zone: + description: "Name of zone the VPC is in." + returned: success + type: str + sample: ch-gva-2 +state: + description: "State of the VPC." + returned: success + type: str + sample: Enabled +tags: + description: "List of resource tags associated with the VPC." + returned: success + type: list + sample: '[ { "key": "foo", "value": "bar" } ]' +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackVpc(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVpc, self).__init__(module) + self.returns = { + 'cidr': 'cidr', + 'networkdomain': 'network_domain', + 'redundantvpcrouter': 'redundant_vpc_router', + 'distributedvpcrouter': 'distributed_vpc_router', + 'regionlevelvpc': 'region_level_vpc', + 'restartrequired': 'restart_required', + } + self.vpc = None + + def get_vpc_offering(self, key=None): + vpc_offering = self.module.params.get('vpc_offering') + args = { + 'state': 'Enabled', + } + if vpc_offering: + args['name'] = vpc_offering + fail_msg = "VPC offering not found or not enabled: %s" % vpc_offering + else: + args['isdefault'] = True + fail_msg = "No enabled default VPC offering found" + + vpc_offerings = self.query_api('listVPCOfferings', **args) + if vpc_offerings: + # The API name argument filter also matches substrings, we have to + # iterate over the results to get an exact match + for vo in vpc_offerings['vpcoffering']: + if 'name' in args: + if args['name'] == vo['name']: + return self._get_by_key(key, vo) + # Return the first offering found, if not queried for the name + else: + return self._get_by_key(key, vo) + self.module.fail_json(msg=fail_msg) + + def get_vpc(self): + if self.vpc: + return self.vpc + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'fetch_list': True, + } + vpcs = self.query_api('listVPCs', **args) + if vpcs: + vpc_name = self.module.params.get('name') + for v in vpcs: + if vpc_name in [v['name'], v['displaytext'], v['id']]: + # Fail if the identifier matches more than one VPC + if self.vpc: + self.module.fail_json(msg="More than one VPC found with the provided identifyer: %s" % vpc_name) + else: + self.vpc = v + return self.vpc + + def restart_vpc(self): + self.result['changed'] = True + vpc = self.get_vpc() + if vpc and not self.module.check_mode: + args = { + 'id': vpc['id'], + 'cleanup': self.module.params.get('clean_up'), + } + res = self.query_api('restartVPC', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'vpc') + return vpc + + def present_vpc(self): + vpc = self.get_vpc() + if not vpc: + vpc = self._create_vpc(vpc) + else: + vpc = self._update_vpc(vpc) + + if vpc: + vpc = self.ensure_tags(resource=vpc, resource_type='Vpc') + return vpc + + def _create_vpc(self, vpc): + self.result['changed'] = True + args = { + 'name': self.module.params.get('name'), + 'displaytext': self.get_or_fallback('display_text', 'name'), + 'networkdomain': self.module.params.get('network_domain'), + 'vpcofferingid': self.get_vpc_offering(key='id'), + 'cidr': self.module.params.get('cidr'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'zoneid': self.get_zone(key='id'), + 'start': self.module.params.get('state') != 'stopped' + } + self.result['diff']['after'] = args + if not self.module.check_mode: + res = self.query_api('createVPC', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + vpc = self.poll_job(res, 'vpc') + return vpc + + def _update_vpc(self, vpc): + args = { + 'id': vpc['id'], + 'displaytext': self.module.params.get('display_text'), + } + if self.has_changed(args, vpc): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateVPC', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + vpc = self.poll_job(res, 'vpc') + return vpc + + def absent_vpc(self): + vpc = self.get_vpc() + if vpc: + self.result['changed'] = True + self.result['diff']['before'] = vpc + if not self.module.check_mode: + res = self.query_api('deleteVPC', id=vpc['id']) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'vpc') + return vpc + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + cidr=dict(), + display_text=dict(), + vpc_offering=dict(), + network_domain=dict(), + clean_up=dict(type='bool'), + state=dict(choices=['present', 'absent', 'stopped', 'restarted'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + tags=dict(type='list', elements='dict', aliases=['tag']), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + required_if=[ + ('state', 'present', ['cidr']), + ], + supports_check_mode=True, + ) + + acs_vpc = AnsibleCloudStackVpc(module) + + state = module.params.get('state') + if state == 'absent': + vpc = acs_vpc.absent_vpc() + elif state == 'restarted': + vpc = acs_vpc.restart_vpc() + else: + vpc = acs_vpc.present_vpc() + + result = acs_vpc.get_result(vpc) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py new file mode 100644 index 00000000..be129a1e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpc_offering.py @@ -0,0 +1,319 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, David Passante (@dpassante) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_vpc_offering +short_description: Manages vpc offerings on Apache CloudStack based clouds. +description: + - Create, update, enable, disable and remove CloudStack VPC offerings. +author: David Passante (@dpassante) +version_added: 0.1.0 +options: + name: + description: + - The name of the vpc offering + type: str + required: true + state: + description: + - State of the vpc offering. + type: str + choices: [ enabled, present, disabled, absent ] + default: present + display_text: + description: + - Display text of the vpc offerings + type: str + service_capabilities: + description: + - Desired service capabilities as part of vpc offering. + type: list + elements: dict + aliases: [ service_capability ] + service_offering: + description: + - The name or ID of the service offering for the VPC router appliance. + type: str + supported_services: + description: + - Services supported by the vpc offering + type: list + elements: str + aliases: [ supported_service ] + service_providers: + description: + - provider to service mapping. If not specified, the provider for the service will be mapped to the default provider on the physical network + type: list + elements: dict + aliases: [ service_provider ] + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Create a vpc offering and enable it + ngine_io.cloudstack.cs_vpc_offering: + name: my_vpc_offering + display_text: vpc offering description + state: enabled + supported_services: [ Dns, Dhcp ] + service_providers: + - {service: 'dns', provider: 'VpcVirtualRouter'} + - {service: 'dhcp', provider: 'VpcVirtualRouter'} + +- name: Create a vpc offering with redundant router + ngine_io.cloudstack.cs_vpc_offering: + name: my_vpc_offering + display_text: vpc offering description + supported_services: [ Dns, Dhcp, SourceNat ] + service_providers: + - {service: 'dns', provider: 'VpcVirtualRouter'} + - {service: 'dhcp', provider: 'VpcVirtualRouter'} + - {service: 'SourceNat', provider: 'VpcVirtualRouter'} + service_capabilities: + - {service: 'SourceNat', capabilitytype: 'RedundantRouter', capabilityvalue: true} + +- name: Create a region level vpc offering with distributed router + ngine_io.cloudstack.cs_vpc_offering: + name: my_vpc_offering + display_text: vpc offering description + state: present + supported_services: [ Dns, Dhcp, SourceNat ] + service_providers: + - {service: 'dns', provider: 'VpcVirtualRouter'} + - {service: 'dhcp', provider: 'VpcVirtualRouter'} + - {service: 'SourceNat', provider: 'VpcVirtualRouter'} + service_capabilities: + - {service: 'Connectivity', capabilitytype: 'DistributedRouter', capabilityvalue: true} + - {service: 'Connectivity', capabilitytype: 'RegionLevelVPC', capabilityvalue: true} + +- name: Remove a vpc offering + ngine_io.cloudstack.cs_vpc_offering: + name: my_vpc_offering + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the vpc offering. + returned: success + type: str + sample: a6f7a5fc-43f8-11e5-a151-feff819cdc9f +name: + description: The name of the vpc offering + returned: success + type: str + sample: MyCustomVPCOffering +display_text: + description: The display text of the vpc offering + returned: success + type: str + sample: My vpc offering +state: + description: The state of the vpc offering + returned: success + type: str + sample: Enabled +service_offering_id: + description: The service offering ID. + returned: success + type: str + sample: c5f7a5fc-43f8-11e5-a151-feff819cdc9f +is_default: + description: Whether VPC offering is the default offering or not. + returned: success + type: bool + sample: false +region_level: + description: Indicated if the offering can support region level vpc. + returned: success + type: bool + sample: false +distributed: + description: Indicates if the vpc offering supports distributed router for one-hop forwarding. + returned: success + type: bool + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackVPCOffering(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVPCOffering, self).__init__(module) + self.returns = { + 'serviceofferingid': 'service_offering_id', + 'isdefault': 'is_default', + 'distributedvpcrouter': 'distributed', + 'supportsregionLevelvpc': 'region_level', + } + self.vpc_offering = None + + def get_vpc_offering(self): + if self.vpc_offering: + return self.vpc_offering + + args = { + 'name': self.module.params.get('name'), + } + vo = self.query_api('listVPCOfferings', **args) + + if vo: + for vpc_offer in vo['vpcoffering']: + if args['name'] == vpc_offer['name']: + self.vpc_offering = vpc_offer + + return self.vpc_offering + + def get_service_offering_id(self): + service_offering = self.module.params.get('service_offering') + if not service_offering: + return None + + args = { + 'issystem': True + } + + service_offerings = self.query_api('listServiceOfferings', **args) + if service_offerings: + for s in service_offerings['serviceoffering']: + if service_offering in [s['name'], s['id']]: + return s['id'] + self.fail_json(msg="Service offering '%s' not found" % service_offering) + + def create_or_update(self): + vpc_offering = self.get_vpc_offering() + + if not vpc_offering: + vpc_offering = self.create_vpc_offering() + + return self.update_vpc_offering(vpc_offering) + + def create_vpc_offering(self): + vpc_offering = None + self.result['changed'] = True + args = { + 'name': self.module.params.get('name'), + 'state': self.module.params.get('state'), + 'displaytext': self.module.params.get('display_text'), + 'supportedservices': self.module.params.get('supported_services'), + 'serviceproviderlist': self.module.params.get('service_providers'), + 'serviceofferingid': self.get_service_offering_id(), + 'servicecapabilitylist': self.module.params.get('service_capabilities'), + } + + required_params = [ + 'display_text', + 'supported_services', + ] + self.module.fail_on_missing_params(required_params=required_params) + + if not self.module.check_mode: + res = self.query_api('createVPCOffering', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpc_offering = self.poll_job(res, 'vpcoffering') + + return vpc_offering + + def delete_vpc_offering(self): + vpc_offering = self.get_vpc_offering() + + if vpc_offering: + self.result['changed'] = True + + args = { + 'id': vpc_offering['id'], + } + + if not self.module.check_mode: + res = self.query_api('deleteVPCOffering', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpc_offering = self.poll_job(res, 'vpcoffering') + + return vpc_offering + + def update_vpc_offering(self, vpc_offering): + if not vpc_offering: + return vpc_offering + + args = { + 'id': vpc_offering['id'], + 'state': self.module.params.get('state'), + 'name': self.module.params.get('name'), + 'displaytext': self.module.params.get('display_text'), + } + + if args['state'] in ['enabled', 'disabled']: + args['state'] = args['state'].title() + else: + del args['state'] + + if self.has_changed(args, vpc_offering): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateVPCOffering', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpc_offering = self.poll_job(res, 'vpcoffering') + + return vpc_offering + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + display_text=dict(), + state=dict(choices=['enabled', 'present', 'disabled', 'absent'], default='present'), + service_capabilities=dict(type='list', elements='dict', aliases=['service_capability']), + service_offering=dict(), + supported_services=dict(type='list', elements='str', aliases=['supported_service']), + service_providers=dict(type='list', elements='dict', aliases=['service_provider']), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_vpc_offering = AnsibleCloudStackVPCOffering(module) + + state = module.params.get('state') + if state in ['absent']: + vpc_offering = acs_vpc_offering.delete_vpc_offering() + else: + vpc_offering = acs_vpc_offering.create_or_update() + + result = acs_vpc_offering.get_result(vpc_offering) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py new file mode 100644 index 00000000..4f77b561 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_connection.py @@ -0,0 +1,349 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: cs_vpn_connection +short_description: Manages site-to-site VPN connections on Apache CloudStack based clouds. +description: + - Create and remove VPN connections. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + vpc: + description: + - Name of the VPC the VPN connection is related to. + type: str + required: true + vpn_customer_gateway: + description: + - Name of the VPN customer gateway. + type: str + required: true + passive: + description: + - State of the VPN connection. + - Only considered when I(state=present). + default: no + type: bool + force: + description: + - Activate the VPN gateway if not already activated on I(state=present). + - Also see M(cs_vpn_gateway). + default: no + type: bool + state: + description: + - State of the VPN connection. + type: str + default: present + choices: [ present, absent ] + zone: + description: + - Name of the zone the VPC is related to. + - If not set, default zone is used. + type: str + domain: + description: + - Domain the VPN connection is related to. + type: str + account: + description: + - Account the VPN connection is related to. + type: str + project: + description: + - Name of the project the VPN connection is related to. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = r''' +- name: Create a VPN connection with activated VPN gateway + ngine_io.cloudstack.cs_vpn_connection: + vpn_customer_gateway: my vpn connection + vpc: my vpc + +- name: Create a VPN connection and force VPN gateway activation + ngine_io.cloudstack.cs_vpn_connection: + vpn_customer_gateway: my vpn connection + vpc: my vpc + force: yes + +- name: Remove a vpn connection + ngine_io.cloudstack.cs_vpn_connection: + vpn_customer_gateway: my vpn connection + vpc: my vpc + state: absent +''' + +RETURN = r''' +--- +id: + description: UUID of the VPN connection. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +vpn_gateway_id: + description: UUID of the VPN gateway. + returned: success + type: str + sample: 04589590-ac63-93f5-4ffc-b698b8ac38b6 +domain: + description: Domain the VPN connection is related to. + returned: success + type: str + sample: example domain +account: + description: Account the VPN connection is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the VPN connection is related to. + returned: success + type: str + sample: Production +created: + description: Date the connection was created. + returned: success + type: str + sample: 2014-12-01T14:57:57+0100 +dpd: + description: Whether dead pear detection is enabled or not. + returned: success + type: bool + sample: true +esp_lifetime: + description: Lifetime in seconds of phase 2 VPN connection. + returned: success + type: int + sample: 86400 +esp_policy: + description: IKE policy of the VPN connection. + returned: success + type: str + sample: aes256-sha1;modp1536 +force_encap: + description: Whether encapsulation for NAT traversal is enforced or not. + returned: success + type: bool + sample: true +ike_lifetime: + description: Lifetime in seconds of phase 1 VPN connection. + returned: success + type: int + sample: 86400 +ike_policy: + description: ESP policy of the VPN connection. + returned: success + type: str + sample: aes256-sha1;modp1536 +cidrs: + description: List of CIDRs of the customer gateway. + returned: success + type: list + sample: [ 10.10.10.0/24 ] +passive: + description: Whether the connection is passive or not. + returned: success + type: bool + sample: false +public_ip: + description: IP address of the VPN gateway. + returned: success + type: str + sample: 10.100.212.10 +gateway: + description: IP address of the VPN customer gateway. + returned: success + type: str + sample: 10.101.214.10 +state: + description: State of the VPN connection. + returned: success + type: str + sample: Connected +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackVpnConnection(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVpnConnection, self).__init__(module) + self.returns = { + 'dpd': 'dpd', + 'esplifetime': 'esp_lifetime', + 'esppolicy': 'esp_policy', + 'gateway': 'gateway', + 'ikepolicy': 'ike_policy', + 'ikelifetime': 'ike_lifetime', + 'publicip': 'public_ip', + 'passive': 'passive', + 's2svpngatewayid': 'vpn_gateway_id', + } + self.vpn_customer_gateway = None + + def get_vpn_customer_gateway(self, key=None, identifier=None, refresh=False): + if not refresh and self.vpn_customer_gateway: + return self._get_by_key(key, self.vpn_customer_gateway) + + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'fetch_list': True, + } + + vpn_customer_gateway = identifier or self.module.params.get('vpn_customer_gateway') + vcgws = self.query_api('listVpnCustomerGateways', **args) + if vcgws: + for vcgw in vcgws: + if vpn_customer_gateway.lower() in [vcgw['id'], vcgw['name'].lower()]: + self.vpn_customer_gateway = vcgw + return self._get_by_key(key, self.vpn_customer_gateway) + self.fail_json(msg="VPN customer gateway not found: %s" % vpn_customer_gateway) + + def get_vpn_gateway(self, key=None): + args = { + 'vpcid': self.get_vpc(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + } + vpn_gateways = self.query_api('listVpnGateways', **args) + if vpn_gateways: + return self._get_by_key(key, vpn_gateways['vpngateway'][0]) + + elif self.module.params.get('force'): + if self.module.check_mode: + return {} + res = self.query_api('createVpnGateway', **args) + vpn_gateway = self.poll_job(res, 'vpngateway') + return self._get_by_key(key, vpn_gateway) + + self.fail_json(msg="VPN gateway not found and not forced to create one") + + def get_vpn_connection(self): + args = { + 'vpcid': self.get_vpc(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + } + + vpn_conns = self.query_api('listVpnConnections', **args) + if vpn_conns: + for vpn_conn in vpn_conns['vpnconnection']: + if self.get_vpn_customer_gateway(key='id') == vpn_conn['s2scustomergatewayid']: + return vpn_conn + + def present_vpn_connection(self): + vpn_conn = self.get_vpn_connection() + + args = { + 's2scustomergatewayid': self.get_vpn_customer_gateway(key='id'), + 's2svpngatewayid': self.get_vpn_gateway(key='id'), + 'passive': self.module.params.get('passive'), + } + + if not vpn_conn: + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('createVpnConnection', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpn_conn = self.poll_job(res, 'vpnconnection') + + return vpn_conn + + def absent_vpn_connection(self): + vpn_conn = self.get_vpn_connection() + + if vpn_conn: + self.result['changed'] = True + + args = { + 'id': vpn_conn['id'] + } + + if not self.module.check_mode: + res = self.query_api('deleteVpnConnection', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'vpnconnection') + + return vpn_conn + + def get_result(self, vpn_conn): + super(AnsibleCloudStackVpnConnection, self).get_result(vpn_conn) + if vpn_conn: + if 'cidrlist' in vpn_conn: + self.result['cidrs'] = vpn_conn['cidrlist'].split(',') or [vpn_conn['cidrlist']] + # Ensure we return a bool + self.result['force_encap'] = True if vpn_conn.get('forceencap') else False + args = { + 'key': 'name', + 'identifier': vpn_conn['s2scustomergatewayid'], + 'refresh': True, + } + self.result['vpn_customer_gateway'] = self.get_vpn_customer_gateway(**args) + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + vpn_customer_gateway=dict(required=True), + vpc=dict(required=True), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + passive=dict(type='bool', default=False), + force=dict(type='bool', default=False), + state=dict(choices=['present', 'absent'], default='present'), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_vpn_conn = AnsibleCloudStackVpnConnection(module) + + state = module.params.get('state') + if state == "absent": + vpn_conn = acs_vpn_conn.absent_vpn_connection() + else: + vpn_conn = acs_vpn_conn.present_vpn_connection() + + result = acs_vpn_conn.get_result(vpn_conn) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py new file mode 100644 index 00000000..915784cc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_customer_gateway.py @@ -0,0 +1,343 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: cs_vpn_customer_gateway +short_description: Manages site-to-site VPN customer gateway configurations on Apache CloudStack based clouds. +description: + - Create, update and remove VPN customer gateways. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the gateway. + type: str + required: true + cidrs: + description: + - List of guest CIDRs behind the gateway. + - Required if I(state=present). + type: list + elements: str + aliases: [ cidr ] + gateway: + description: + - Public IP address of the gateway. + - Required if I(state=present). + type: str + esp_policy: + description: + - ESP policy in the format e.g. C(aes256-sha1;modp1536). + - Required if I(state=present). + type: str + ike_policy: + description: + - IKE policy in the format e.g. C(aes256-sha1;modp1536). + - Required if I(state=present). + type: str + ipsec_psk: + description: + - IPsec Preshared-Key. + - Cannot contain newline or double quotes. + - Required if I(state=present). + type: str + ike_lifetime: + description: + - Lifetime in seconds of phase 1 VPN connection. + - Defaulted to 86400 by the API on creation if not set. + type: int + esp_lifetime: + description: + - Lifetime in seconds of phase 2 VPN connection. + - Defaulted to 3600 by the API on creation if not set. + type: int + dpd: + description: + - Enable Dead Peer Detection. + - Disabled per default by the API on creation if not set. + type: bool + force_encap: + description: + - Force encapsulation for NAT traversal. + - Disabled per default by the API on creation if not set. + type: bool + state: + description: + - State of the VPN customer gateway. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the VPN customer gateway is related to. + type: str + account: + description: + - Account the VPN customer gateway is related to. + type: str + project: + description: + - Name of the project the VPN gateway is related to. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + default: yes + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = r''' +- name: Create a vpn customer gateway + ngine_io.cloudstack.cs_vpn_customer_gateway: + name: my vpn customer gateway + cidrs: + - 192.168.123.0/24 + - 192.168.124.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.1.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: "S3cr3Tk3Y" + +- name: Remove a vpn customer gateway + ngine_io.cloudstack.cs_vpn_customer_gateway: + name: my vpn customer gateway + state: absent +''' + +RETURN = r''' +--- +id: + description: UUID of the VPN customer gateway. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +gateway: + description: IP address of the VPN customer gateway. + returned: success + type: str + sample: 10.100.212.10 +domain: + description: Domain the VPN customer gateway is related to. + returned: success + type: str + sample: example domain +account: + description: Account the VPN customer gateway is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the VPN customer gateway is related to. + returned: success + type: str + sample: Production +dpd: + description: Whether dead pear detection is enabled or not. + returned: success + type: bool + sample: true +esp_lifetime: + description: Lifetime in seconds of phase 2 VPN connection. + returned: success + type: int + sample: 86400 +esp_policy: + description: IKE policy of the VPN customer gateway. + returned: success + type: str + sample: aes256-sha1;modp1536 +force_encap: + description: Whether encapsulation for NAT traversal is enforced or not. + returned: success + type: bool + sample: true +ike_lifetime: + description: Lifetime in seconds of phase 1 VPN connection. + returned: success + type: int + sample: 86400 +ike_policy: + description: ESP policy of the VPN customer gateway. + returned: success + type: str + sample: aes256-sha1;modp1536 +name: + description: Name of this customer gateway. + returned: success + type: str + sample: my vpn customer gateway +cidrs: + description: List of CIDRs of this customer gateway. + returned: success + type: list + sample: [ 10.10.10.0/24 ] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackVpnCustomerGateway(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVpnCustomerGateway, self).__init__(module) + self.returns = { + 'dpd': 'dpd', + 'esplifetime': 'esp_lifetime', + 'esppolicy': 'esp_policy', + 'gateway': 'gateway', + 'ikepolicy': 'ike_policy', + 'ikelifetime': 'ike_lifetime', + 'ipaddress': 'ip_address', + } + + def _common_args(self): + return { + 'name': self.module.params.get('name'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'cidrlist': ','.join(self.module.params.get('cidrs')) if self.module.params.get('cidrs') is not None else None, + 'esppolicy': self.module.params.get('esp_policy'), + 'esplifetime': self.module.params.get('esp_lifetime'), + 'ikepolicy': self.module.params.get('ike_policy'), + 'ikelifetime': self.module.params.get('ike_lifetime'), + 'ipsecpsk': self.module.params.get('ipsec_psk'), + 'dpd': self.module.params.get('dpd'), + 'forceencap': self.module.params.get('force_encap'), + 'gateway': self.module.params.get('gateway'), + } + + def get_vpn_customer_gateway(self): + args = { + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id'), + 'fetch_list': True, + } + vpn_customer_gateway = self.module.params.get('name') + vpn_customer_gateways = self.query_api('listVpnCustomerGateways', **args) + if vpn_customer_gateways: + for vgw in vpn_customer_gateways: + if vpn_customer_gateway.lower() in [vgw['id'], vgw['name'].lower()]: + return vgw + + def present_vpn_customer_gateway(self): + vpn_customer_gateway = self.get_vpn_customer_gateway() + required_params = [ + 'cidrs', + 'esp_policy', + 'gateway', + 'ike_policy', + 'ipsec_psk', + ] + self.module.fail_on_missing_params(required_params=required_params) + + if not vpn_customer_gateway: + vpn_customer_gateway = self._create_vpn_customer_gateway(vpn_customer_gateway) + else: + vpn_customer_gateway = self._update_vpn_customer_gateway(vpn_customer_gateway) + + return vpn_customer_gateway + + def _create_vpn_customer_gateway(self, vpn_customer_gateway): + self.result['changed'] = True + args = self._common_args() + if not self.module.check_mode: + res = self.query_api('createVpnCustomerGateway', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpn_customer_gateway = self.poll_job(res, 'vpncustomergateway') + return vpn_customer_gateway + + def _update_vpn_customer_gateway(self, vpn_customer_gateway): + args = self._common_args() + args.update({'id': vpn_customer_gateway['id']}) + if self.has_changed(args, vpn_customer_gateway, skip_diff_for_keys=['ipsecpsk']): + self.result['changed'] = True + if not self.module.check_mode: + res = self.query_api('updateVpnCustomerGateway', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + vpn_customer_gateway = self.poll_job(res, 'vpncustomergateway') + return vpn_customer_gateway + + def absent_vpn_customer_gateway(self): + vpn_customer_gateway = self.get_vpn_customer_gateway() + if vpn_customer_gateway: + self.result['changed'] = True + args = { + 'id': vpn_customer_gateway['id'] + } + if not self.module.check_mode: + res = self.query_api('deleteVpnCustomerGateway', **args) + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'vpncustomergateway') + + return vpn_customer_gateway + + def get_result(self, vpn_customer_gateway): + super(AnsibleCloudStackVpnCustomerGateway, self).get_result(vpn_customer_gateway) + if vpn_customer_gateway: + if 'cidrlist' in vpn_customer_gateway: + self.result['cidrs'] = vpn_customer_gateway['cidrlist'].split(',') or [vpn_customer_gateway['cidrlist']] + # Ensure we return a bool + self.result['force_encap'] = True if vpn_customer_gateway.get('forceencap') else False + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + name=dict(required=True), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + cidrs=dict(type='list', elements='str', aliases=['cidr']), + esp_policy=dict(), + esp_lifetime=dict(type='int'), + gateway=dict(), + ike_policy=dict(), + ike_lifetime=dict(type='int'), + ipsec_psk=dict(no_log=True), + dpd=dict(type='bool'), + force_encap=dict(type='bool'), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_vpn_cgw = AnsibleCloudStackVpnCustomerGateway(module) + + state = module.params.get('state') + if state == "absent": + vpn_customer_gateway = acs_vpn_cgw.absent_vpn_customer_gateway() + else: + vpn_customer_gateway = acs_vpn_cgw.present_vpn_customer_gateway() + + result = acs_vpn_cgw.get_result(vpn_customer_gateway) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py new file mode 100644 index 00000000..7bc3ab0b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_vpn_gateway.py @@ -0,0 +1,204 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_vpn_gateway +short_description: Manages site-to-site VPN gateways on Apache CloudStack based clouds. +description: + - Creates and removes VPN site-to-site gateways. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + vpc: + description: + - Name of the VPC. + type: str + required: true + state: + description: + - State of the VPN gateway. + type: str + default: present + choices: [ present, absent ] + domain: + description: + - Domain the VPN gateway is related to. + type: str + account: + description: + - Account the VPN gateway is related to. + type: str + project: + description: + - Name of the project the VPN gateway is related to. + type: str + zone: + description: + - Name of the zone the VPC is related to. + - If not set, default zone is used. + type: str + poll_async: + description: + - Poll async jobs until job has finished. + type: bool + default: yes +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a vpn gateway is present + ngine_io.cloudstack.cs_vpn_gateway: + vpc: my VPC + +- name: Ensure a vpn gateway is absent + ngine_io.cloudstack.cs_vpn_gateway: + vpc: my VPC + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the VPN site-to-site gateway. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +public_ip: + description: IP address of the VPN site-to-site gateway. + returned: success + type: str + sample: 10.100.212.10 +vpc: + description: Name of the VPC. + returned: success + type: str + sample: My VPC +domain: + description: Domain the VPN site-to-site gateway is related to. + returned: success + type: str + sample: example domain +account: + description: Account the VPN site-to-site gateway is related to. + returned: success + type: str + sample: example account +project: + description: Name of project the VPN site-to-site gateway is related to. + returned: success + type: str + sample: Production +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together +) + + +class AnsibleCloudStackVpnGateway(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackVpnGateway, self).__init__(module) + self.returns = { + 'publicip': 'public_ip' + } + + def get_vpn_gateway(self): + args = { + 'vpcid': self.get_vpc(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id') + } + vpn_gateways = self.query_api('listVpnGateways', **args) + if vpn_gateways: + return vpn_gateways['vpngateway'][0] + return None + + def present_vpn_gateway(self): + vpn_gateway = self.get_vpn_gateway() + if not vpn_gateway: + self.result['changed'] = True + args = { + 'vpcid': self.get_vpc(key='id'), + 'account': self.get_account(key='name'), + 'domainid': self.get_domain(key='id'), + 'projectid': self.get_project(key='id') + } + if not self.module.check_mode: + res = self.query_api('createVpnGateway', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + vpn_gateway = self.poll_job(res, 'vpngateway') + + return vpn_gateway + + def absent_vpn_gateway(self): + vpn_gateway = self.get_vpn_gateway() + if vpn_gateway: + self.result['changed'] = True + args = { + 'id': vpn_gateway['id'] + } + if not self.module.check_mode: + res = self.query_api('deleteVpnGateway', **args) + + poll_async = self.module.params.get('poll_async') + if poll_async: + self.poll_job(res, 'vpngateway') + + return vpn_gateway + + def get_result(self, vpn_gateway): + super(AnsibleCloudStackVpnGateway, self).get_result(vpn_gateway) + if vpn_gateway: + self.result['vpc'] = self.get_vpc(key='name') + return self.result + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + vpc=dict(required=True), + state=dict(choices=['present', 'absent'], default='present'), + domain=dict(), + account=dict(), + project=dict(), + zone=dict(), + poll_async=dict(type='bool', default=True), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_vpn_gw = AnsibleCloudStackVpnGateway(module) + + state = module.params.get('state') + if state == "absent": + vpn_gateway = acs_vpn_gw.absent_vpn_gateway() + else: + vpn_gateway = acs_vpn_gw.present_vpn_gateway() + + result = acs_vpn_gw.get_result(vpn_gateway) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py new file mode 100644 index 00000000..51348086 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone.py @@ -0,0 +1,377 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_zone +short_description: Manages zones on Apache CloudStack based clouds. +description: + - Create, update and remove zones. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + name: + description: + - Name of the zone. + type: str + required: true + id: + description: + - uuid of the existing zone. + type: str + state: + description: + - State of the zone. + type: str + default: present + choices: [ present, enabled, disabled, absent ] + domain: + description: + - Domain the zone is related to. + - Zone is a public zone if not set. + type: str + network_domain: + description: + - Network domain for the zone. + type: str + network_type: + description: + - Network type of the zone. + type: str + default: Basic + choices: [ Basic, Advanced ] + dns1: + description: + - First DNS for the zone. + - Required if I(state=present) + type: str + dns2: + description: + - Second DNS for the zone. + type: str + internal_dns1: + description: + - First internal DNS for the zone. + - If not set I(dns1) will be used on I(state=present). + type: str + internal_dns2: + description: + - Second internal DNS for the zone. + type: str + dns1_ipv6: + description: + - First DNS for IPv6 for the zone. + type: str + dns2_ipv6: + description: + - Second DNS for IPv6 for the zone. + type: str + guest_cidr_address: + description: + - Guest CIDR address for the zone. + type: str + dhcp_provider: + description: + - DHCP provider for the Zone. + type: str + local_storage_enabled: + description: + - Whether to enable local storage for the zone or not.. + type: bool + securitygroups_enabled: + description: + - Whether the zone is security group enabled or not. + type: bool +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Ensure a zone is present + ngine_io.cloudstack.cs_zone: + name: ch-zrh-ix-01 + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: basic + +- name: Ensure a zone is disabled + ngine_io.cloudstack.cs_zone: + name: ch-zrh-ix-01 + state: disabled + +- name: Ensure a zone is enabled + ngine_io.cloudstack.cs_zone: + name: ch-zrh-ix-01 + state: enabled + +- name: Ensure a zone is absent + ngine_io.cloudstack.cs_zone: + name: ch-zrh-ix-01 + state: absent +''' + +RETURN = ''' +--- +id: + description: UUID of the zone. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 +name: + description: Name of the zone. + returned: success + type: str + sample: zone01 +dns1: + description: First DNS for the zone. + returned: success + type: str + sample: 8.8.8.8 +dns2: + description: Second DNS for the zone. + returned: success + type: str + sample: 8.8.4.4 +internal_dns1: + description: First internal DNS for the zone. + returned: success + type: str + sample: 8.8.8.8 +internal_dns2: + description: Second internal DNS for the zone. + returned: success + type: str + sample: 8.8.4.4 +dns1_ipv6: + description: First IPv6 DNS for the zone. + returned: success + type: str + sample: "2001:4860:4860::8888" +dns2_ipv6: + description: Second IPv6 DNS for the zone. + returned: success + type: str + sample: "2001:4860:4860::8844" +allocation_state: + description: State of the zone. + returned: success + type: str + sample: Enabled +domain: + description: Domain the zone is related to. + returned: success + type: str + sample: ROOT +network_domain: + description: Network domain for the zone. + returned: success + type: str + sample: example.com +network_type: + description: Network type for the zone. + returned: success + type: str + sample: basic +local_storage_enabled: + description: Local storage offering enabled. + returned: success + type: bool + sample: false +securitygroups_enabled: + description: Security groups support is enabled. + returned: success + type: bool + sample: false +guest_cidr_address: + description: Guest CIDR address for the zone + returned: success + type: str + sample: 10.1.1.0/24 +dhcp_provider: + description: DHCP provider for the zone + returned: success + type: str + sample: VirtualRouter +zone_token: + description: Zone token + returned: success + type: str + sample: ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7 +tags: + description: List of resource tags associated with the zone. + returned: success + type: list + sample: [ { "key": "foo", "value": "bar" } ] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, + cs_required_together, +) + + +class AnsibleCloudStackZone(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackZone, self).__init__(module) + self.returns = { + 'dns1': 'dns1', + 'dns2': 'dns2', + 'internaldns1': 'internal_dns1', + 'internaldns2': 'internal_dns2', + 'ipv6dns1': 'dns1_ipv6', + 'ipv6dns2': 'dns2_ipv6', + 'domain': 'network_domain', + 'networktype': 'network_type', + 'securitygroupsenabled': 'securitygroups_enabled', + 'localstorageenabled': 'local_storage_enabled', + 'guestcidraddress': 'guest_cidr_address', + 'dhcpprovider': 'dhcp_provider', + 'allocationstate': 'allocation_state', + 'zonetoken': 'zone_token', + } + self.zone = None + + def _get_common_zone_args(self): + args = { + 'name': self.module.params.get('name'), + 'dns1': self.module.params.get('dns1'), + 'dns2': self.module.params.get('dns2'), + 'internaldns1': self.get_or_fallback('internal_dns1', 'dns1'), + 'internaldns2': self.get_or_fallback('internal_dns2', 'dns2'), + 'ipv6dns1': self.module.params.get('dns1_ipv6'), + 'ipv6dns2': self.module.params.get('dns2_ipv6'), + 'networktype': self.module.params.get('network_type'), + 'domain': self.module.params.get('network_domain'), + 'localstorageenabled': self.module.params.get('local_storage_enabled'), + 'guestcidraddress': self.module.params.get('guest_cidr_address'), + 'dhcpprovider': self.module.params.get('dhcp_provider'), + } + state = self.module.params.get('state') + if state in ['enabled', 'disabled']: + args['allocationstate'] = state.capitalize() + return args + + def get_zone(self): + if not self.zone: + args = {} + + uuid = self.module.params.get('id') + if uuid: + args['id'] = uuid + zones = self.query_api('listZones', **args) + if zones: + self.zone = zones['zone'][0] + return self.zone + + args['name'] = self.module.params.get('name') + zones = self.query_api('listZones', **args) + if zones: + self.zone = zones['zone'][0] + return self.zone + + def present_zone(self): + zone = self.get_zone() + if zone: + zone = self._update_zone() + else: + zone = self._create_zone() + return zone + + def _create_zone(self): + required_params = [ + 'dns1', + ] + self.module.fail_on_missing_params(required_params=required_params) + + self.result['changed'] = True + + args = self._get_common_zone_args() + args['domainid'] = self.get_domain(key='id') + args['securitygroupenabled'] = self.module.params.get('securitygroups_enabled') + + zone = None + if not self.module.check_mode: + res = self.query_api('createZone', **args) + zone = res['zone'] + return zone + + def _update_zone(self): + zone = self.get_zone() + + args = self._get_common_zone_args() + args['id'] = zone['id'] + + if self.has_changed(args, zone): + self.result['changed'] = True + + if not self.module.check_mode: + res = self.query_api('updateZone', **args) + zone = res['zone'] + return zone + + def absent_zone(self): + zone = self.get_zone() + if zone: + self.result['changed'] = True + + args = { + 'id': zone['id'] + } + if not self.module.check_mode: + self.query_api('deleteZone', **args) + + return zone + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + id=dict(), + name=dict(required=True), + dns1=dict(), + dns2=dict(), + internal_dns1=dict(), + internal_dns2=dict(), + dns1_ipv6=dict(), + dns2_ipv6=dict(), + network_type=dict(default='Basic', choices=['Basic', 'Advanced']), + network_domain=dict(), + guest_cidr_address=dict(), + dhcp_provider=dict(), + local_storage_enabled=dict(type='bool'), + securitygroups_enabled=dict(type='bool'), + state=dict(choices=['present', 'enabled', 'disabled', 'absent'], default='present'), + domain=dict(), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=cs_required_together(), + supports_check_mode=True + ) + + acs_zone = AnsibleCloudStackZone(module) + + state = module.params.get('state') + if state in ['absent']: + zone = acs_zone.absent_zone() + else: + zone = acs_zone.present_zone() + + result = acs_zone.get_result(zone) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py new file mode 100644 index 00000000..1581cdbf --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/plugins/modules/cs_zone_info.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: cs_zone_info +short_description: Gathering information about zones from Apache CloudStack based clouds. +description: + - Gathering information from the API of a zone. +author: René Moser (@resmo) +version_added: 0.1.0 +options: + zone: + description: + - Name of the zone. + - If not specified, all zones are returned + type: str + aliases: [ name ] +extends_documentation_fragment: +- ngine_io.cloudstack.cloudstack +''' + +EXAMPLES = ''' +- name: Gather information from a zone + ngine_io.cloudstack.cs_zone_info: + zone: ch-gva-1 + register: zone + +- name: Show the returned results of the registered variable + debug: + msg: "{{ zone }}" + +- name: Gather information from all zones + ngine_io.cloudstack.cs_zone_info: + register: zones + +- name: Show information on all zones + debug: + msg: "{{ zones }}" +''' + +RETURN = ''' +--- +zones: + description: A list of matching zones. + type: list + returned: success + contains: + id: + description: UUID of the zone. + returned: success + type: str + sample: 04589590-ac63-4ffc-93f5-b698b8ac38b6 + name: + description: Name of the zone. + returned: success + type: str + sample: zone01 + dns1: + description: First DNS for the zone. + returned: success + type: str + sample: 8.8.8.8 + dns2: + description: Second DNS for the zone. + returned: success + type: str + sample: 8.8.4.4 + internal_dns1: + description: First internal DNS for the zone. + returned: success + type: str + sample: 8.8.8.8 + internal_dns2: + description: Second internal DNS for the zone. + returned: success + type: str + sample: 8.8.4.4 + dns1_ipv6: + description: First IPv6 DNS for the zone. + returned: success + type: str + sample: "2001:4860:4860::8888" + dns2_ipv6: + description: Second IPv6 DNS for the zone. + returned: success + type: str + sample: "2001:4860:4860::8844" + allocation_state: + description: State of the zone. + returned: success + type: str + sample: Enabled + domain: + description: Domain the zone is related to. + returned: success + type: str + sample: ROOT + network_domain: + description: Network domain for the zone. + returned: success + type: str + sample: example.com + network_type: + description: Network type for the zone. + returned: success + type: str + sample: basic + local_storage_enabled: + description: Local storage offering enabled. + returned: success + type: bool + sample: false + securitygroups_enabled: + description: Security groups support is enabled. + returned: success + type: bool + sample: false + guest_cidr_address: + description: Guest CIDR address for the zone + returned: success + type: str + sample: 10.1.1.0/24 + dhcp_provider: + description: DHCP provider for the zone + returned: success + type: str + sample: VirtualRouter + zone_token: + description: Zone token + returned: success + type: str + sample: ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7 + tags: + description: List of resource tags associated with the zone. + returned: success + type: list + sample: [ { "key": "foo", "value": "bar" } ] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.cloudstack import ( + AnsibleCloudStack, + cs_argument_spec, +) + + +class AnsibleCloudStackZoneInfo(AnsibleCloudStack): + + def __init__(self, module): + super(AnsibleCloudStackZoneInfo, self).__init__(module) + self.returns = { + 'dns1': 'dns1', + 'dns2': 'dns2', + 'internaldns1': 'internal_dns1', + 'internaldns2': 'internal_dns2', + 'ipv6dns1': 'dns1_ipv6', + 'ipv6dns2': 'dns2_ipv6', + 'domain': 'network_domain', + 'networktype': 'network_type', + 'securitygroupsenabled': 'securitygroups_enabled', + 'localstorageenabled': 'local_storage_enabled', + 'guestcidraddress': 'guest_cidr_address', + 'dhcpprovider': 'dhcp_provider', + 'allocationstate': 'allocation_state', + 'zonetoken': 'zone_token', + } + + def get_zone(self): + if self.module.params['zone']: + zones = [super(AnsibleCloudStackZoneInfo, self).get_zone()] + else: + zones = self.query_api('listZones') + if zones: + zones = zones['zone'] + else: + zones = [] + return { + 'zones': [self.update_result(resource) for resource in zones] + } + + +def main(): + argument_spec = cs_argument_spec() + argument_spec.update(dict( + zone=dict(type='str', aliases=['name']), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + acs_zone_info = AnsibleCloudStackZoneInfo(module=module) + result = acs_zone_info.get_zone() + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt new file mode 100644 index 00000000..231d91a9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/requirements.txt @@ -0,0 +1 @@ +cs>=0.9.0 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini new file mode 100644 index 00000000..43777b59 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.ini @@ -0,0 +1,5 @@ +[cloudstack] +#endpoint = https://api.exoscale.ch/compute +endpoint = https://cloud.example.com/client/api +key = cloudstack api key +secret = cloudstack api secret diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py new file mode 100755 index 00000000..db0322cf --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/scripts/inventory/cloudstack.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# (c) 2015, René Moser <mail@renemoser.net> +# +# This file is part of Ansible, +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +###################################################################### + +""" +Ansible CloudStack external inventory script. +============================================= + +Generates Ansible inventory from CloudStack. Configuration is read from +'cloudstack.ini'. If you need to pass the project, write a simple wrapper +script, e.g. project_cloudstack.sh: + + #!/bin/bash + cloudstack.py --project <your_project> $@ + + +When run against a specific host, this script returns the following attributes +based on the data obtained from CloudStack API: + + "web01": { + "cpu_number": 2, + "nic": [ + { + "ip": "10.102.76.98", + "mac": "02:00:50:99:00:01", + "type": "Isolated", + "netmask": "255.255.255.0", + "gateway": "10.102.76.1" + }, + { + "ip": "10.102.138.63", + "mac": "06:b7:5a:00:14:84", + "type": "Shared", + "netmask": "255.255.255.0", + "gateway": "10.102.138.1" + } + ], + "default_ip": "10.102.76.98", + "zone": "ZUERICH", + "created": "2014-07-02T07:53:50+0200", + "hypervisor": "VMware", + "memory": 2048, + "state": "Running", + "tags": [], + "cpu_speed": 1800, + "affinity_group": [], + "service_offering": "Small", + "cpu_used": "62%" + } + + +usage: cloudstack.py [--list] [--host HOST] [--project PROJECT] [--domain DOMAIN] +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import sys +import argparse +import json + +try: + from cs import CloudStack, CloudStackException, read_config +except ImportError: + print("Error: CloudStack library must be installed: pip install cs.", + file=sys.stderr) + sys.exit(1) + + +class CloudStackInventory(object): + def __init__(self): + + parser = argparse.ArgumentParser() + parser.add_argument('--host') + parser.add_argument('--list', action='store_true') + parser.add_argument('--tag', help="Filter machines by a tag. Should be in the form key=value.") + parser.add_argument('--project') + parser.add_argument('--domain') + + options = parser.parse_args() + try: + self.cs = CloudStack(**read_config()) + except CloudStackException: + print("Error: Could not connect to CloudStack API", file=sys.stderr) + + domain_id = None + if options.domain: + domain_id = self.get_domain_id(options.domain) + + project_id = None + if options.project: + project_id = self.get_project_id(options.project, domain_id) + + if options.host: + data = self.get_host(options.host, project_id, domain_id) + print(json.dumps(data, indent=2)) + + elif options.list: + tags = dict() + if options.tag: + tags['tags[0].key'], tags['tags[0].value'] = options.tag.split('=') + data = self.get_list(project_id, domain_id, **tags) + print(json.dumps(data, indent=2)) + else: + print("usage: --list [--tag <tag>] | --host <hostname> [--project <project>] [--domain <domain_path>]", + file=sys.stderr) + sys.exit(1) + + def get_domain_id(self, domain): + domains = self.cs.listDomains(listall=True) + if domains: + for d in domains['domain']: + if d['path'].lower() == domain.lower(): + return d['id'] + print("Error: Domain %s not found." % domain, file=sys.stderr) + sys.exit(1) + + def get_project_id(self, project, domain_id=None): + projects = self.cs.listProjects(domainid=domain_id) + if projects: + for p in projects['project']: + if p['name'] == project or p['id'] == project: + return p['id'] + print("Error: Project %s not found." % project, file=sys.stderr) + sys.exit(1) + + def get_host(self, name, project_id=None, domain_id=None, **kwargs): + hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs) + data = {} + if not hosts: + return data + for host in hosts: + host_name = host['displayname'] + if name == host_name: + data['zone'] = host['zonename'] + if 'group' in host: + data['group'] = host['group'] + data['state'] = host['state'] + data['service_offering'] = host['serviceofferingname'] + data['affinity_group'] = host['affinitygroup'] + data['security_group'] = host['securitygroup'] + data['cpu_number'] = host['cpunumber'] + if 'cpu_speed' in host: + data['cpu_speed'] = host['cpuspeed'] + if 'cpuused' in host: + data['cpu_used'] = host['cpuused'] + data['memory'] = host['memory'] + data['tags'] = host['tags'] + if 'hypervisor' in host: + data['hypervisor'] = host['hypervisor'] + data['created'] = host['created'] + data['nic'] = [] + for nic in host['nic']: + nicdata = { + 'ip': nic['ipaddress'], + 'mac': nic['macaddress'], + 'netmask': nic['netmask'], + 'gateway': nic['gateway'], + 'type': nic['type'], + } + if 'ip6address' in nic: + nicdata['ip6'] = nic['ip6address'] + if 'gateway' in nic: + nicdata['gateway'] = nic['gateway'] + if 'netmask' in nic: + nicdata['netmask'] = nic['netmask'] + data['nic'].append(nicdata) + if nic['isdefault']: + data['default_ip'] = nic['ipaddress'] + if 'ip6address' in nic: + data['default_ip6'] = nic['ip6address'] + break + return data + + def get_list(self, project_id=None, domain_id=None, **kwargs): + data = { + 'all': { + 'hosts': [], + }, + '_meta': { + 'hostvars': {}, + }, + } + + groups = self.cs.listInstanceGroups(projectid=project_id, domainid=domain_id) + if groups: + for group in groups['instancegroup']: + group_name = group['name'] + if group_name and group_name not in data: + data[group_name] = { + 'hosts': [] + } + + hosts = self.cs.listVirtualMachines(projectid=project_id, domainid=domain_id, fetch_list=True, **kwargs) + if not hosts: + return data + for host in hosts: + host_name = host['displayname'] + data['all']['hosts'].append(host_name) + data['_meta']['hostvars'][host_name] = {} + + # Make a group per zone + data['_meta']['hostvars'][host_name]['zone'] = host['zonename'] + group_name = host['zonename'] + if group_name not in data: + data[group_name] = { + 'hosts': [] + } + data[group_name]['hosts'].append(host_name) + + if 'group' in host: + data['_meta']['hostvars'][host_name]['group'] = host['group'] + data['_meta']['hostvars'][host_name]['state'] = host['state'] + data['_meta']['hostvars'][host_name]['service_offering'] = host['serviceofferingname'] + data['_meta']['hostvars'][host_name]['affinity_group'] = host['affinitygroup'] + data['_meta']['hostvars'][host_name]['security_group'] = host['securitygroup'] + data['_meta']['hostvars'][host_name]['cpu_number'] = host['cpunumber'] + if 'cpuspeed' in host: + data['_meta']['hostvars'][host_name]['cpu_speed'] = host['cpuspeed'] + if 'cpuused' in host: + data['_meta']['hostvars'][host_name]['cpu_used'] = host['cpuused'] + data['_meta']['hostvars'][host_name]['created'] = host['created'] + data['_meta']['hostvars'][host_name]['memory'] = host['memory'] + data['_meta']['hostvars'][host_name]['tags'] = host['tags'] + if 'hypervisor' in host: + data['_meta']['hostvars'][host_name]['hypervisor'] = host['hypervisor'] + data['_meta']['hostvars'][host_name]['created'] = host['created'] + data['_meta']['hostvars'][host_name]['nic'] = [] + for nic in host['nic']: + nicdata = { + 'ip': nic['ipaddress'], + 'mac': nic['macaddress'], + 'netmask': nic['netmask'], + 'gateway': nic['gateway'], + 'type': nic['type'], + } + if 'ip6address' in nic: + nicdata['ip6'] = nic['ip6address'] + if 'gateway' in nic: + nicdata['gateway'] = nic['gateway'] + if 'netmask' in nic: + nicdata['netmask'] = nic['netmask'] + data['_meta']['hostvars'][host_name]['nic'].append(nicdata) + if nic['isdefault']: + data['_meta']['hostvars'][host_name]['default_ip'] = nic['ipaddress'] + if 'ip6address' in nic: + data['_meta']['hostvars'][host_name]['default_ip6'] = nic['ip6address'] + + group_name = '' + if 'group' in host: + group_name = host['group'] + + if group_name and group_name in data: + data[group_name]['hosts'].append(host_name) + return data + + +if __name__ == '__main__': + CloudStackInventory() diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml new file mode 100644 index 00000000..5bbe54be --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_account/tasks/main.yml @@ -0,0 +1,416 @@ +--- +- name: setup + cs_account: + name: "{{ cs_resource_prefix }}_username" + state: absent + register: acc + +- name: test fail if missing name + action: cs_account + register: acc + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - acc is failed + - 'acc.msg == "missing required arguments: name"' + +- name: test fail if missing params if state=present + cs_account: + name: "{{ cs_resource_prefix }}_user" + register: acc + ignore_errors: true +- name: verify results of fail if missing params if state=present + assert: + that: + - acc is failed + - 'acc.msg == "missing required arguments: email, username, password, first_name, last_name"' + +- name: test create user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + register: acc + check_mode: true +- name: verify results of create account in check mode + assert: + that: + - acc is changed + +- name: test create user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + register: acc +- name: verify results of create account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test create user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + register: acc +- name: verify results of create account idempotence + assert: + that: + - acc is not changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test lock user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc + check_mode: true +- name: verify results of lock user account in check mode + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test lock user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc +- name: verify results of lock user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test lock user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc +- name: verify results of lock user account idempotence + assert: + that: + - acc is not changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test disable user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: disabled + register: acc + check_mode: true +- name: verify results of disable user account in check mode + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test disable user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: disabled + register: acc +- name: verify results of disable user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "disabled" + - acc.domain == "ROOT" + +- name: test disable user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: disabled + register: acc +- name: verify results of disable user account idempotence + assert: + that: + - acc is not changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "disabled" + - acc.domain == "ROOT" + +- name: test lock disabled user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc + check_mode: true +- name: verify results of lock disabled user account in check mode + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "disabled" + - acc.domain == "ROOT" + +- name: test lock disabled user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc +- name: verify results of lock disabled user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test lock disabled user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: locked + register: acc +- name: verify results of lock disabled user account idempotence + assert: + that: + - acc is not changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test enable user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: enabled + register: acc + check_mode: true +- name: verify results of enable user account in check mode + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test enable user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: enabled + register: acc +- name: verify results of enable user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test enable user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: enabled + register: acc +- name: verify results of enable user account idempotence + assert: + that: + - acc is not changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test remove user account in check mode + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc + check_mode: true +- name: verify results of remove user account in check mode + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test remove user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc +- name: verify results of remove user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test remove user account idempotence + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc +- name: verify results of remove user account idempotence + assert: + that: + - acc is not changed + +- name: test create user disabled account + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + state: disabled + register: acc +- name: verify results of create disabled account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "disabled" + - acc.domain == "ROOT" + +- name: test remove disabled user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc +- name: verify results of remove disabled user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "disabled" + - acc.domain == "ROOT" + +- name: test create user locked account + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + state: locked + register: acc +- name: verify results of create locked account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test remove locked user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc +- name: verify results of remove locked user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "locked" + - acc.domain == "ROOT" + +- name: test create user unlocked/enabled account + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + state: unlocked + register: acc +- name: verify results of create unlocked/enabled account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + +- name: test remove unlocked/enabled user account + cs_account: + name: "{{ cs_resource_prefix }}_user" + state: absent + register: acc +- name: verify results of remove unlocked/enabled user account + assert: + that: + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_user" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml new file mode 100644 index 00000000..994f21a1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_affinitygroup/tasks/main.yml @@ -0,0 +1,93 @@ +--- +- name: setup + cs_affinitygroup: + name: "{{ cs_resource_prefix }}_ag" + state: absent + register: ag +- name: verify setup + assert: + that: + - ag is successful + +- name: test fail if missing name + cs_affinitygroup: + register: ag + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - ag is failed + - "ag.msg == 'missing required arguments: name'" + +- name: test fail unknown affinity type + cs_affinitygroup: + name: "{{ cs_resource_prefix }}_ag" + affinity_type: unexistent affinity type + register: ag + ignore_errors: true +- name: verify test fail unknown affinity type + assert: + that: + - ag is failed + - "ag.msg == 'affinity group type not found: unexistent affinity type'" + +- name: test present affinity group in check mode + cs_affinitygroup: name={{ cs_resource_prefix }}_ag + register: ag + check_mode: true +- name: verify results of create affinity group in check mode + assert: + that: + - ag is successful + - ag is changed + +- name: test present affinity group + cs_affinitygroup: name={{ cs_resource_prefix }}_ag + register: ag +- name: verify results of create affinity group + assert: + that: + - ag is successful + - ag is changed + - ag.name == "{{ cs_resource_prefix }}_ag" + +- name: test present affinity group is idempotence + cs_affinitygroup: name={{ cs_resource_prefix }}_ag + register: ag +- name: verify results present affinity group is idempotence + assert: + that: + - ag is successful + - ag is not changed + - ag.name == "{{ cs_resource_prefix }}_ag" + +- name: test absent affinity group in check mode + cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent + register: ag + check_mode: true +- name: verify results of absent affinity group in check mode + assert: + that: + - ag is successful + - ag is changed + - ag.name == "{{ cs_resource_prefix }}_ag" + +- name: test absent affinity group + cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent + register: ag +- name: verify results of absent affinity group + assert: + that: + - ag is successful + - ag is changed + - ag.name == "{{ cs_resource_prefix }}_ag" + +- name: test absent affinity group is idempotence + cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent + register: ag +- name: verify results of absent affinity group is idempotence + assert: + that: + - ag is successful + - ag is not changed + - ag.name is undefined diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml new file mode 100644 index 00000000..f911a7be --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_cluster/tasks/main.yml @@ -0,0 +1,317 @@ +--- +- name: setup cluster is absent + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: cluster +- name: verify setup cluster is absent + assert: + that: + - cluster is successful + +- name: setup zone is present + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone +- name: verify setup zone is present + assert: + that: + - zone is successful + +- name: setup pod is present + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + start_ip: 10.100.10.101 + gateway: 10.100.10.1 + netmask: 255.255.255.0 + register: pod +- name: verify setup pod is present + assert: + that: + - pod is successful + +- name: test fail if missing name + cs_cluster: + zone: "{{ cs_resource_prefix }}-zone" + register: cluster + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - cluster is failed + - "cluster.msg == 'missing required arguments: name'" + +- name: test fail if pod not found + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + hypervisor: Simulator + cluster_type: CloudManaged + pod: unexistent + register: cluster + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - cluster is failed + - "cluster.msg == 'Pod unexistent not found in zone {{ cs_resource_prefix }}-zone'" + +- name: test create cluster in check mode + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + pod: "{{ cs_resource_prefix }}-pod" + hypervisor: Simulator + cluster_type: CloudManaged + register: cluster_origin + check_mode: true + tags: disable +- name: verify test create cluster in check mode + assert: + that: + - cluster_origin is changed + +- name: test create cluster + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + pod: "{{ cs_resource_prefix }}-pod" + hypervisor: Simulator + cluster_type: CloudManaged + register: cluster_origin + tags: disable +- name: verify test create cluster + assert: + that: + - cluster_origin is changed + - cluster_origin.name == "{{ cs_resource_prefix }}-cluster" + - cluster_origin.zone == "{{ cs_resource_prefix }}-zone" + - cluster_origin.allocation_state == "Enabled" + - cluster_origin.hypervisor == "Simulator" + - cluster_origin.cluster_type == "CloudManaged" + +- name: test create cluster idempotence + cs_cluster: + name: "{{ cs_resource_prefix }}-Cluster" + zone: "{{ cs_resource_prefix }}-Zone" + pod: "{{ cs_resource_prefix }}-pod" + hypervisor: Simulator + cluster_type: CloudManaged + register: cluster +- name: verify test create cluster idempotence + assert: + that: + - cluster.id == cluster_origin.id + - cluster is not changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster_origin.hypervisor == "Simulator" + - cluster.cluster_type == "CloudManaged" + +- name: test update cluster in check mode + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + hypervisor: Simulator + cluster_type: ExternalManaged + register: cluster + check_mode: true +- name: verify test update cluster in check mode + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "CloudManaged" + - cluster.id == cluster_origin.id + +- name: test update cluster + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + hypervisor: Simulator + cluster_type: ExternalManaged + register: cluster +- name: verify test update cluster + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test update cluster idempotence + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + hypervisor: Simulator + cluster_type: ExternalManaged + register: cluster +- name: verify test update cluster idempotence + assert: + that: + - cluster is not changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test disable cluster in check mode + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: cluster + check_mode: true +- name: verify test disable cluster in check mode + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test disable cluster + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: cluster +- name: verify test disable cluster + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Disabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test disable cluster idempotence + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: cluster +- name: verify test disable cluster idempotence + assert: + that: + - cluster is not changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Disabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + +- name: test enable cluster in check mode + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: cluster + check_mode: true +- name: verify test enable cluster in check mode + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Disabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test enable cluster + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: cluster +- name: verify test enable cluster + assert: + that: + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test enable cluster idempotence + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: cluster +- name: verify test enable cluster idempotence + assert: + that: + - cluster is not changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster.hypervisor == "Simulator" + - cluster.cluster_type == "ExternalManaged" + - cluster.id == cluster_origin.id + +- name: test remove cluster in check mode + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: cluster + check_mode: true +- name: verify test remove cluster in check mode + assert: + that: + - cluster.id == cluster_origin.id + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster_origin.hypervisor == "Simulator" + +- name: test remove cluster + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: cluster +- name: verify test remove cluster + assert: + that: + - cluster.id == cluster_origin.id + - cluster is changed + - cluster.name == "{{ cs_resource_prefix }}-cluster" + - cluster.zone == "{{ cs_resource_prefix }}-zone" + - cluster.allocation_state == "Enabled" + - cluster_origin.hypervisor == "Simulator" + +- name: test remove cluster idempotence + cs_cluster: + name: "{{ cs_resource_prefix }}-cluster" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: cluster +- name: verify test remove cluster idempotence + assert: + that: + - cluster is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases new file mode 100644 index 00000000..136c05e0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/aliases @@ -0,0 +1 @@ +hidden diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml new file mode 100644 index 00000000..942316bd --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/defaults/main.yml @@ -0,0 +1,6 @@ +--- +cs_resource_prefix: "cs-{{ (ansible_date_time.iso8601_micro | to_uuid).split('-')[0] }}" +cs_common_template: CentOS 5.6 (64-bit) no GUI (Simulator) +cs_common_service_offering: Small Instance +cs_common_zone_adv: Sandbox-simulator-advanced +cs_common_zone_basic: Sandbox-simulator-basic diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml new file mode 100644 index 00000000..1b206a07 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_common/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: wait for system template available + cs_template: + name: "{{ cs_common_template }}" + state: absent + cross_zones: yes + template_filter: all + register: template + check_mode: true + until: template is changed + retries: 20 + delay: 5 + +- name: smoke test instance + cs_instance: + name: smoke-test-vm + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + register: instance + until: instance is successful + retries: 20 + delay: 5 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml new file mode 100644 index 00000000..3cf304ca --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/defaults/main.yml @@ -0,0 +1,5 @@ +--- +test_cs_configuration_storage: PS0-adv +test_cs_configuration_cluster: C0-basic +test_cs_configuration_account: admin +test_cs_configuration_zone: Sandbox-simulator-basic diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml new file mode 100644 index 00000000..8b20918f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/account.yml @@ -0,0 +1,76 @@ +--- +- name: test configuration account + cs_configuration: + name: allow.public.user.templates + account: "{{ test_cs_configuration_account }}" + value: true + register: config +- name: verify test configuration storage + assert: + that: + - config is successful + +- name: test update configuration account in check mode + cs_configuration: + name: allow.public.user.templates + account: "{{ test_cs_configuration_account }}" + value: false + register: config + check_mode: true +- name: verify update configuration account in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "true" + - config.name == "allow.public.user.templates" + - config.scope == "account" + - config.account == "{{ test_cs_configuration_account }}" + +- name: test update configuration account + cs_configuration: + name: allow.public.user.templates + account: "{{ test_cs_configuration_account }}" + value: false + register: config +- name: verify update configuration account + assert: + that: + - config is successful + - config is changed + - config.value == "false" + - config.name == "allow.public.user.templates" + - config.scope == "account" + - config.account == "{{ test_cs_configuration_account }}" + +- name: test update configuration account idempotence + cs_configuration: + name: allow.public.user.templates + account: "{{ test_cs_configuration_account }}" + value: false + register: config +- name: verify update configuration account idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "false" + - config.name == "allow.public.user.templates" + - config.scope == "account" + - config.account == "{{ test_cs_configuration_account }}" + +- name: test reset configuration account + cs_configuration: + name: allow.public.user.templates + account: "{{ test_cs_configuration_account }}" + value: true + register: config +- name: verify update configuration account + assert: + that: + - config is successful + - config is changed + - config.value == "true" + - config.name == "allow.public.user.templates" + - config.scope == "account" + - config.account == "{{ test_cs_configuration_account }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml new file mode 100644 index 00000000..b8cb2b94 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/cluster.yml @@ -0,0 +1,76 @@ +--- +- name: test configuration cluster + cs_configuration: + name: cpu.overprovisioning.factor + cluster: "{{ test_cs_configuration_cluster }}" + value: 1.0 + register: config +- name: verify test configuration cluster + assert: + that: + - config is successful + +- name: test update configuration cluster in check mode + cs_configuration: + name: cpu.overprovisioning.factor + cluster: "{{ test_cs_configuration_cluster }}" + value: 2.0 + register: config + check_mode: true +- name: verify update configuration cluster in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "1.0" + - config.name == "cpu.overprovisioning.factor" + - config.scope == "cluster" + - config.cluster == "{{ test_cs_configuration_cluster }}" + +- name: test update configuration cluster + cs_configuration: + name: cpu.overprovisioning.factor + cluster: "{{ test_cs_configuration_cluster }}" + value: 2.0 + register: config +- name: verify update configuration cluster + assert: + that: + - config is successful + - config is changed + - config.value == "2.0" + - config.name == "cpu.overprovisioning.factor" + - config.scope == "cluster" + - config.cluster == "{{ test_cs_configuration_cluster }}" + +- name: test update configuration cluster idempotence + cs_configuration: + name: cpu.overprovisioning.factor + cluster: "{{ test_cs_configuration_cluster }}" + value: 2.0 + register: config +- name: verify update configuration cluster idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "2.0" + - config.name == "cpu.overprovisioning.factor" + - config.scope == "cluster" + - config.cluster == "{{ test_cs_configuration_cluster }}" + +- name: test reset configuration cluster + cs_configuration: + name: cpu.overprovisioning.factor + cluster: "{{ test_cs_configuration_cluster }}" + value: 1.0 + register: config +- name: verify reset configuration cluster + assert: + that: + - config is successful + - config is changed + - config.value == "1.0" + - config.name == "cpu.overprovisioning.factor" + - config.scope == "cluster" + - config.cluster == "{{ test_cs_configuration_cluster }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml new file mode 100644 index 00000000..e80c85f9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/main.yml @@ -0,0 +1,204 @@ +--- +- name: test fail if missing name + cs_configuration: + register: config + ignore_errors: true +- name: verify results of fail if missing arguments + assert: + that: + - config is failed + - "config.msg.startswith('missing required arguments: ')" + +- name: test configuration + cs_configuration: + name: network.loadbalancer.haproxy.stats.visibility + value: global + register: config +- name: verify test configuration + assert: + that: + - config is successful + +- name: test update configuration string in check mode + cs_configuration: + name: network.loadbalancer.haproxy.stats.visibility + value: all + register: config + check_mode: true +- name: verify test update configuration string in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "global" + - config.name == "network.loadbalancer.haproxy.stats.visibility" + +- name: test update configuration string + cs_configuration: + name: network.loadbalancer.haproxy.stats.visibility + value: all + register: config +- name: verify test update configuration string + assert: + that: + - config is successful + - config is changed + - config.value == "all" + - config.name == "network.loadbalancer.haproxy.stats.visibility" + +- name: test update configuration string idempotence + cs_configuration: + name: network.loadbalancer.haproxy.stats.visibility + value: all + register: config +- name: verify test update configuration string idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "all" + - config.name == "network.loadbalancer.haproxy.stats.visibility" + +- name: test reset configuration string + cs_configuration: + name: network.loadbalancer.haproxy.stats.visibility + value: global + register: config +- name: verify test reset configuration string + assert: + that: + - config is successful + - config is changed + - config.value == "global" + - config.name == "network.loadbalancer.haproxy.stats.visibility" + +- name: test configuration + cs_configuration: + name: vmware.recycle.hung.wokervm + value: false + register: config +- name: verify test configuration + assert: + that: + - config is successful + +- name: test update configuration bool in check mode + cs_configuration: + name: vmware.recycle.hung.wokervm + value: true + register: config + check_mode: true +- name: verify test update configuration bool in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "false" + - config.name == "vmware.recycle.hung.wokervm" + +- name: test update configuration bool + cs_configuration: + name: vmware.recycle.hung.wokervm + value: true + register: config +- name: verify test update configuration bool + assert: + that: + - config is successful + - config is changed + - config.value == "true" + - config.name == "vmware.recycle.hung.wokervm" + +- name: test update configuration bool idempotence + cs_configuration: + name: vmware.recycle.hung.wokervm + value: true + register: config +- name: verify test update configuration bool idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "true" + - config.name == "vmware.recycle.hung.wokervm" + +- name: test reset configuration bool + cs_configuration: + name: vmware.recycle.hung.wokervm + value: false + register: config +- name: verify test reset configuration bool + assert: + that: + - config is successful + - config is changed + - config.value == "false" + - config.name == "vmware.recycle.hung.wokervm" + +- name: test configuration + cs_configuration: + name: agent.load.threshold + value: 0.7 + register: config +- name: verify test configuration + assert: + that: + - config is successful + +- name: test update configuration float in check mode + cs_configuration: + name: agent.load.threshold + value: 0.81 + register: config + check_mode: true +- name: verify update configuration float in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "0.7" + - config.name == "agent.load.threshold" + +- name: test update configuration float + cs_configuration: + name: agent.load.threshold + value: 0.81 + register: config +- name: verify update configuration float + assert: + that: + - config is successful + - config is changed + - config.value == "0.81" + - config.name == "agent.load.threshold" + +- name: test update configuration float idempotence + cs_configuration: + name: agent.load.threshold + value: 0.81 + register: config +- name: verify update configuration float idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "0.81" + - config.name == "agent.load.threshold" + +- name: reset configuration float + cs_configuration: + name: agent.load.threshold + value: 0.7 + register: config +- name: verify reset configuration float + assert: + that: + - config is successful + - config is changed + - config.value == "0.7" + - config.name == "agent.load.threshold" + +- include: storage.yml +- include: account.yml +- include: zone.yml +- include: cluster.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml new file mode 100644 index 00000000..e376dcf1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/storage.yml @@ -0,0 +1,76 @@ +--- +- name: test configuration storage + cs_configuration: + name: storage.overprovisioning.factor + storage: "{{ test_cs_configuration_storage }}" + value: 2.0 + register: config +- name: verify test configuration storage + assert: + that: + - config is successful + +- name: test update configuration storage in check mode + cs_configuration: + name: storage.overprovisioning.factor + storage: "{{ test_cs_configuration_storage }}" + value: 3.0 + register: config + check_mode: true +- name: verify update configuration storage in check mode + assert: + that: + - config is successful + - config is changed + - config.value == "2.0" + - config.name == "storage.overprovisioning.factor" + - config.scope == "storagepool" + - config.storage == "{{ test_cs_configuration_storage }}" + +- name: test update configuration storage + cs_configuration: + name: storage.overprovisioning.factor + storage: "{{ test_cs_configuration_storage }}" + value: 3.0 + register: config +- name: verify update configuration storage + assert: + that: + - config is successful + - config is changed + - config.value == "3.0" + - config.name == "storage.overprovisioning.factor" + - config.scope == "storagepool" + - config.storage == "{{ test_cs_configuration_storage }}" + +- name: test update configuration storage idempotence + cs_configuration: + name: storage.overprovisioning.factor + storage: "{{ test_cs_configuration_storage }}" + value: 3.0 + register: config +- name: verify update configuration storage idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "3.0" + - config.name == "storage.overprovisioning.factor" + - config.scope == "storagepool" + - config.storage == "{{ test_cs_configuration_storage }}" + +- name: test reset configuration storage + cs_configuration: + name: storage.overprovisioning.factor + storage: "{{ test_cs_configuration_storage }}" + value: 2.0 + register: config +- name: verify reset configuration storage + assert: + that: + - config is successful + - config is changed + - config.value == "2.0" + - config.name == "storage.overprovisioning.factor" + - config.scope == "storagepool" + - config.storage == "{{ test_cs_configuration_storage }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml new file mode 100644 index 00000000..cd9333fa --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_configuration/tasks/zone.yml @@ -0,0 +1,59 @@ +--- +- name: test configuration zone + cs_configuration: + name: use.external.dns + zone: "{{ test_cs_configuration_zone }}" + value: false + register: config +- name: verify test configuration zone + assert: + that: + - config is successful + +- name: test update configuration zone + cs_configuration: + name: use.external.dns + zone: "{{ test_cs_configuration_zone }}" + value: true + register: config +- name: verify update configuration zone + assert: + that: + - config is successful + - config is changed + - config.value == "true" + - config.name == "use.external.dns" + - config.scope == "zone" + - config.zone == "{{ test_cs_configuration_zone }}" + +- name: test update configuration zone idempotence + cs_configuration: + name: use.external.dns + zone: "{{ test_cs_configuration_zone }}" + value: true + register: config +- name: verify update configuration zone idempotence + assert: + that: + - config is successful + - config is not changed + - config.value == "true" + - config.name == "use.external.dns" + - config.scope == "zone" + - config.zone == "{{ test_cs_configuration_zone }}" + +- name: test reset configuration zone + cs_configuration: + name: use.external.dns + zone: "{{ test_cs_configuration_zone }}" + value: false + register: config +- name: verify reset configuration zone + assert: + that: + - config is successful + - config is changed + - config.value == "false" + - config.name == "use.external.dns" + - config.scope == "zone" + - config.zone == "{{ test_cs_configuration_zone }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml new file mode 100644 index 00000000..fd55788c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_disk_offering/tasks/main.yml @@ -0,0 +1,143 @@ +--- +- name: setup disk offering + cs_disk_offering: + name: Small + state: absent + register: do +- name: verify setup disk offering + assert: + that: + - do is successful + +- name: create disk offering in check mode + cs_disk_offering: + name: Small + disk_size: 10 + storage_tags: + - eco + - backup + storage_type: local + register: do + check_mode: true +- name: verify create disk offering in check mode + assert: + that: + - do is changed + +- name: create disk offering + cs_disk_offering: + name: Small + disk_size: 10 + storage_tags: + - eco + - backup + storage_type: local + register: do +- name: verify create disk offering + assert: + that: + - do is changed + - do.name == "Small" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: create disk offering idempotence + cs_disk_offering: + name: Small + disk_size: 10 + storage_tags: + - eco + - backup + storage_type: local + register: do +- name: verify create disk offering idempotence + assert: + that: + - do is not changed + - do.name == "Small" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: update disk offering in check mode + cs_disk_offering: + name: Small + disk_size: 10 + display_text: Small 10GB + register: do + check_mode: true +- name: verify create update offering in check mode + assert: + that: + - do is changed + - do.name == "Small" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: update disk offering + cs_disk_offering: + name: Small + disk_size: 10 + display_text: Small 10GB + register: do +- name: verify update disk offerin + assert: + that: + - do is changed + - do.name == "Small" + - do.display_text == "Small 10GB" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: update disk offering idempotence + cs_disk_offering: + name: Small + disk_size: 10 + display_text: Small 10GB + register: do +- name: verify update disk offering idempotence + assert: + that: + - do is not changed + - do.name == "Small" + - do.display_text == "Small 10GB" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: remove disk offering in check mode + cs_disk_offering: + name: Small + state: absent + check_mode: true + register: do +- name: verify remove disk offering in check mode + assert: + that: + - do is changed + - do.name == "Small" + - do.display_text == "Small 10GB" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: remove disk offering + cs_disk_offering: + name: Small + state: absent + register: do +- name: verify remove disk offering + assert: + that: + - do is changed + - do.name == "Small" + - do.display_text == "Small 10GB" + - do.storage_tags == ['eco', 'backup'] + - do.storage_type == "local" + +- name: remove disk offering idempotence + cs_disk_offering: + name: Small + state: absent + register: do +- name: verify remove disk offering idempotence + assert: + that: + - do is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml new file mode 100644 index 00000000..e51ca0d4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_domain/tasks/main.yml @@ -0,0 +1,241 @@ +--- +- name: setup + cs_domain: + path: "{{ cs_resource_prefix }}_domain" + state: absent + register: dom +- name: verify setup + assert: + that: + - dom is successful + +- name: test fail if missing name + action: cs_domain + register: dom + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - dom is failed + - 'dom.msg == "missing required arguments: path"' + +- name: test fail if ends with / + cs_domain: + path: "{{ cs_resource_prefix }}_domain/" + register: dom + ignore_errors: true +- name: verify results of fail if ends with / + assert: + that: + - dom is failed + - dom.msg == "Path '{{ cs_resource_prefix }}_domain/' must not end with /" + +- name: test create a domain in check mode + cs_domain: + path: "{{ cs_resource_prefix }}_domain" + register: dom + check_mode: true +- name: verify results of test create a domain in check mode + assert: + that: + - dom is changed + +- name: test create a domain + cs_domain: + path: "{{ cs_resource_prefix }}_domain" + register: dom +- name: verify results of test create a domain + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain" + - dom.name == "{{ cs_resource_prefix }}_domain" + +- name: test create a domain idempotence + cs_domain: + path: "{{ cs_resource_prefix }}_domain" + register: dom +- name: verify results of test create a domain idempotence + assert: + that: + - dom is not changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain" + - dom.name == "{{ cs_resource_prefix }}_domain" + +- name: test create a domain idempotence2 + cs_domain: + path: "/{{ cs_resource_prefix }}_domain" + register: dom +- name: verify results of test create a domain idempotence2 + assert: + that: + - dom is not changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain" + - dom.name == "{{ cs_resource_prefix }}_domain" + +- name: test fail to create a subdomain for inexistent domain + cs_domain: + path: ROOT/inexistent/{{ cs_resource_prefix }}_subdomain + register: dom + ignore_errors: true +- name: test fail to create a subdomain for inexistent domain + assert: + that: + - dom is failed + - dom.msg == "Parent domain path ROOT/inexistent does not exist" + +- name: test create a subdomain in check mode + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + register: dom + check_mode: true +- name: verify results of test create a domain in check mode + assert: + that: + - dom is changed + +- name: test create a subdomain + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + register: dom +- name: verify results of test create a domain + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test create a subdomain idempotence + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + register: dom +- name: verify results of test create a subdomain idempotence + assert: + that: + - dom is not changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test update a subdomain in check mode + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + network_domain: domain.example.com + register: dom + check_mode: true +- name: verify results of test update a subdomain in check mode + assert: + that: + - dom is changed + - dom.network_domain is undefined + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test update a subdomain + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + network_domain: domain.example.com + register: dom +- name: verify results of test update a subdomain + assert: + that: + - dom is changed + - dom.network_domain == "domain.example.com" + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test update a subdomain idempotence + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + network_domain: domain.example.com + register: dom +- name: verify results of test update a subdomain idempotence + assert: + that: + - dom is not changed + - dom.network_domain == "domain.example.com" + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test delete a subdomain in check mode + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + state: absent + register: dom + check_mode: true +- name: verify results of test delete a subdomain in check mode + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test delete a subdomain + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + state: absent + register: dom +- name: verify results of test delete a subdomain + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test delete a subdomain idempotence + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + state: absent + register: dom +- name: verify results of test delete a subdomain idempotence + assert: + that: + - dom is not changed + +- name: test create a subdomain 2 + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain + register: dom +- name: verify results of test create a subdomain 2 + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain/{{ cs_resource_prefix }}_subdomain" + - dom.name == "{{ cs_resource_prefix }}_subdomain" + +- name: test delete a domain with clean up in check mode + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain + state: absent + clean_up: true + register: dom + check_mode: true +- name: verify results of test delete a domain with clean up in check mode + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain" + - dom.name == "{{ cs_resource_prefix }}_domain" + +- name: test delete a domain with clean up + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain + state: absent + clean_up: true + register: dom +- name: verify results of test delete a domain with clean up + assert: + that: + - dom is changed + - dom.path == "ROOT/{{ cs_resource_prefix }}_domain" + - dom.name == "{{ cs_resource_prefix }}_domain" + +- name: test delete a domain with clean up idempotence + cs_domain: + path: ROOT/{{ cs_resource_prefix }}_domain + state: absent + clean_up: true + register: dom +- name: verify results of test delete a domain with clean up idempotence + assert: + that: + - dom is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml new file mode 100644 index 00000000..f5999305 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/defaults/main.yml @@ -0,0 +1,3 @@ +--- +cs_firewall_ip_address: 10.100.212.5 +cs_firewall_network: ansible test diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml new file mode 100644 index 00000000..5061ef89 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_firewall/tasks/main.yml @@ -0,0 +1,447 @@ +--- +- name: network setup + cs_network: + name: "{{ cs_firewall_network }}" + network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService + network_domain: example.com + zone: "{{ cs_common_zone_adv }}" + register: net + +- name: setup instance to get network in implementation state + cs_instance: + name: "{{ cs_resource_prefix }}-vm-cs-firewall" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + networks: + - "{{ net.name }}" + register: instance + until: instance is success + retries: 20 + delay: 5 +- name: verify instance setup + assert: + that: + - instance is successful + +- name: public ip address setup + cs_ip_address: + network: ansible test + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify public ip address setup + assert: + that: + - ip_address is successful + +- name: set ip address as fact + set_fact: + cs_firewall_ip_address: "{{ ip_address.ip_address }}" + +- name: setup 80 + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + state: absent + +- name: setup 5300 + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + state: absent + +- name: setup all + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + zone: "{{ cs_common_zone_adv }}" + state: absent + +- name: test fail if missing params + action: cs_firewall + register: fw + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - fw is failed + - "fw.msg == 'one of the following is required: ip_address, network'" + +- name: test fail if missing params + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + register: fw + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - fw is failed + - "fw.msg == \"missing required argument for protocol 'tcp': start_port or end_port\"" + +- name: test fail if missing params network egress + cs_firewall: + type: egress + zone: "{{ cs_common_zone_adv }}" + register: fw + ignore_errors: true +- name: verify results of fail if missing params ip_address + assert: + that: + - fw is failed + - "fw.msg == 'one of the following is required: ip_address, network'" + +- name: test present firewall rule ingress 80 in check mode + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + register: fw + check_mode: true +- name: verify results of present firewall rule ingress 80 in check mode + assert: + that: + - fw is changed + +- name: test present firewall rule ingress 80 + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule ingress 80 + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" + - fw.cidrs == [ '0.0.0.0/0' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "tcp" + - fw.start_port == 80 + - fw.end_port == 80 + - fw.type == "ingress" + +- name: test present firewall rule ingress 80 idempotence + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule ingress 80 idempotence + assert: + that: + - fw is not changed + - fw.cidr == "0.0.0.0/0" + - fw.cidrs == [ '0.0.0.0/0' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "tcp" + - fw.start_port == 80 + - fw.end_port == 80 + - fw.type == "ingress" + +- name: test present firewall rule ingress 5300 in check mode + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + register: fw + check_mode: true +- name: verify results of present firewall rule ingress 5300 in check mode + assert: + that: + - fw is changed + +- name: test present firewall rule ingress 5300 + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule ingress 5300 + assert: + that: + - fw is changed + - fw.cidr == "1.2.3.0/24,4.5.6.0/24" + - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "udp" + - fw.start_port == 5300 + - fw.end_port == 5333 + - fw.type == "ingress" + +- name: test present firewall rule ingress 5300 idempotence + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule ingress 5300 idempotence + assert: + that: + - fw is not changed + - fw.cidr == "1.2.3.0/24,4.5.6.0/24" + - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "udp" + - fw.start_port == 5300 + - fw.end_port == 5333 + - fw.type == "ingress" + +- name: test present firewall rule egress all in check mode + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + zone: "{{ cs_common_zone_adv }}" + register: fw + check_mode: true +- name: verify results of present firewall rule egress all in check mode + assert: + that: + - fw is changed + +- name: test present firewall rule egress all + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule egress all + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24" + - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ] + - fw.network == "{{ cs_firewall_network }}" + - fw.protocol == "all" + - fw.type == "egress" + +- name: test present firewall rule egress all idempotence + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of present firewall rule egress all idempotence + assert: + that: + - fw is not changed + - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24" + - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ] + - fw.network == "{{ cs_firewall_network }}" + - fw.protocol == "all" + - fw.type == "egress" + +- name: test absent firewall rule ingress 80 in check mode + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw + check_mode: true +- name: verify results of absent firewall rule ingress 80 in check mode + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" + - fw.cidrs == [ '0.0.0.0/0' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "tcp" + - fw.start_port == 80 + - fw.end_port == 80 + - fw.type == "ingress" + +- name: test absent firewall rule ingress 80 + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw +- name: verify results of absent firewall rule ingress 80 + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" + - fw.cidrs == [ '0.0.0.0/0' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "tcp" + - fw.start_port == 80 + - fw.end_port == 80 + - fw.type == "ingress" + +- name: test absent firewall rule ingress 80 idempotence + cs_firewall: + port: 80 + ip_address: "{{ cs_firewall_ip_address }}" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw +- name: verify results of absent firewall rule ingress 80 idempotence + assert: + that: + - fw is not changed + +- name: test absent firewall rule ingress 5300 in check mode + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw + check_mode: true +- name: verify results of absent firewall rule ingress 5300 in check mode + assert: + that: + - fw is changed + - fw.cidr == "1.2.3.0/24,4.5.6.0/24" + - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "udp" + - fw.start_port == 5300 + - fw.end_port == 5333 + - fw.type == "ingress" + +- name: test absent firewall rule ingress 5300 + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw +- name: verify results of absent firewall rule ingress 5300 + assert: + that: + - fw is changed + - fw.cidr == "1.2.3.0/24,4.5.6.0/24" + - fw.cidrs == [ '1.2.3.0/24', '4.5.6.0/24' ] + - fw.ip_address == "{{ cs_firewall_ip_address }}" + - fw.protocol == "udp" + - fw.start_port == 5300 + - fw.end_port == 5333 + - fw.type == "ingress" + +- name: test absent firewall rule ingress 5300 idempotence + cs_firewall: + ip_address: "{{ cs_firewall_ip_address }}" + protocol: udp + start_port: 5300 + end_port: 5333 + cidrs: + - 1.2.3.0/24 + - 4.5.6.0/24 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw +- name: verify results of absent firewall rule ingress 5300 idempotence + assert: + that: + - fw is not changed + +- name: test absent firewall rule egress all in check mode + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + state: absent + zone: "{{ cs_common_zone_adv }}" + register: fw + check_mode: true +- name: verify results of absent firewall rule egress all in check mode + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24" + - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ] + - fw.network == "{{ cs_firewall_network }}" + - fw.protocol == "all" + - fw.type == "egress" + +- name: test absent firewall rule egress all + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + state: absent + zone: "{{ cs_common_zone_adv }}" + register: fw +- name: verify results of absent firewall rule egress all + assert: + that: + - fw is changed + - fw.cidr == "0.0.0.0/0" or fw.cidr == "10.1.1.0/24" + - fw.cidrs == [ '0.0.0.0/0' ] or fw.cidrs == [ '10.1.1.0/24' ] + - fw.network == "{{ cs_firewall_network }}" + - fw.protocol == "all" + - fw.type == "egress" + +- name: test absent firewall rule egress all idempotence + cs_firewall: + network: "{{ cs_firewall_network }}" + protocol: all + type: egress + zone: "{{ cs_common_zone_adv }}" + state: absent + register: fw +- name: verify results of absent firewall rule egress all idempotence + assert: + that: + - fw is not changed + +- name: cleanup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-cs-firewall" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify instance cleanup + assert: + that: + - instance is successful + +- name: network cleanup + cs_network: + name: "{{ cs_firewall_network }}" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify network cleanup + assert: + that: + - net is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml new file mode 100644 index 00000000..c47d006d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_host/tasks/main.yml @@ -0,0 +1,438 @@ +--- +- name: test fail missing params + cs_host: + zone: "{{ cs_common_zone_basic }}" + register: host + ignore_errors: true +- name: verify test fail missing url if host is not existent + assert: + that: + - host is failed + - 'host.msg == "missing required arguments: name"' + +- name: test fail missing params if host is not existent + cs_host: + name: sim + zone: "{{ cs_common_zone_basic }}" + register: host + ignore_errors: true +- name: verify test fail missing params if host is not existent + assert: + that: + - host is failed + - 'host.msg == "missing required arguments: password, username, hypervisor, pod"' + +- name: test create a host in check mode + cs_host: + name: sim + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: root + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + register: host + check_mode: true +- name: verify test create a host in check mode + assert: + that: + - host is changed + +- name: test create a host + cs_host: + name: sim + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: root + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + register: host +- name: verify test create a host + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - "host.name.startswith('SimulatedAgent.')" + - host.host_tags == ['perf', 'gpu'] + +# This is special in simulator mode, we can not predict the full hostname. +# That is why we gather the infos from the returns and use a fact. +- name: assume the sim would resolve to the IP address + set_fact: + host_hostname: "{{ host.name }}" + host_ip_address: "{{ host.ip_address }}" + +- name: test create a host idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + register: host +- name: verify test create a host idempotence + assert: + that: + - host is not changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu'] + +- name: test update host in check mode + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + - x2 + register: host + check_mode: true +- name: verify test update a host in check mode + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu'] + +- name: test update host + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + - x2 + register: host +- name: verify test update a host in check mode + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test update host idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: + - perf + - gpu + - x2 + register: host +- name: verify test update a host idempotence + assert: + that: + - host is not changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +# FIXME: Removing by empty list seems to be an issue in the used lib cs underneath, disabled +- name: test update host remove host_tags + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: [] + register: host + when: false +- name: verify test update host remove host_tags + assert: + that: + - host is changed + - host.host_tags|length == 0 + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + when: false + +# FIXME: Removing by empty list seems to be an issue in the used lib cs underneath, disabled +- name: test update host remove host_tags idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + url: "http://sim/c0-basic/h2" + cluster: C0-basic + pod: POD0-basic + username: admin + password: password + hypervisor: Simulator + allocation_state: enabled + host_tags: [] + register: host + when: false +- name: verify test update host remove host_tags idempotence + assert: + that: + - host is not changed + - len(host.host_tags) == 0 + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + when: false + + +- name: test put host in maintenance in check mode + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: maintenance + check_mode: true + register: host +- name: verify test put host in maintenance in check mode + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test put host in maintenance + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: maintenance + register: host +- name: verify test put host in maintenance + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'maintenance' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test put host in maintenance idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: maintenance + register: host +- name: verify test put host in maintenance idempotence + assert: + that: + - host is not changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'maintenance' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test put host out of maintenance in check mode + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: enabled + check_mode: true + register: host +- name: verify test put host out of maintenance in check mode + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'maintenance' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test put host out of maintenance + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: enabled + register: host +- name: verify test put host out of maintenance + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test put host out of maintenance idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + allocation_state: enabled + register: host +- name: verify test put host out of maintenance idempotence + assert: + that: + - host is not changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test remove host in check mode + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + state: absent + check_mode: true + register: host +- name: verify test remove a host in check mode + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test remove host + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + state: absent + register: host +- name: verify test remove a host + assert: + that: + - host is changed + - host.cluster == 'C0-basic' + - host.pod == 'POD0-basic' + - host.hypervisor == 'Simulator' + - host.allocation_state == 'enabled' + - host.zone == 'Sandbox-simulator-basic' + - host.state == 'Up' + - host.name == '{{ host_hostname }}' + - host.host_tags == ['perf', 'gpu', 'x2'] + +- name: test remove host idempotence + cs_host: + name: "{{ host_hostname }}" + zone: "{{ cs_common_zone_basic }}" + cluster: C0-basic + pod: POD0-basic + state: absent + register: host +- name: verify test remove a host idempotenc + assert: + that: + - host is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml new file mode 100644 index 00000000..8d1eaa07 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_image_store/tasks/main.yml @@ -0,0 +1,166 @@ +--- +- name: setup image store is absent + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify setup image store is absent + assert: + that: + - sp is successful + +- name: test fail if missing params + cs_image_store: + register: ss + ignore_errors: true +- name: verify test fail if missing params + assert: + that: + - ss is failed + - "'name' in ss.msg" + - "'zone' in ss.msg" + - "'missing required arguments: ' in ss.msg" + +- name: setup image store with wrong parameters + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: present + ignore_errors: true + register: ss +- name: verify setup image store with wrong parameters + assert: + that: + - ss is failed + - "ss.msg == 'state is present but all of the following are missing: url, provider'" + +- name: setup image store in check mode + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + url: "nfs://nfs-mount.domain/share/images/" + provider: "NFS" + state: present + check_mode: true + register: ss +- name: verify setup image store in check mode + assert: + that: + - ss is successful + - ss is changed + +- name: setup image store + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + url: "nfs://nfs-mount.domain/share/images/" + provider: "NFS" + state: present + register: ss +- name: verify setup image store + assert: + that: + - ss is successful + - ss is changed + - "ss.url == 'nfs://nfs-mount.domain/share/images/'" + - "ss.provider_name == 'NFS'" + - "ss.zone == cs_common_zone_adv" + - "ss.protocol == 'nfs'" + +- name: setup image store idempotence + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + url: "nfs://nfs-mount.domain/share/images/" + provider: "NFS" + state: present + register: ss +- name: verify setup image store idempotence + assert: + that: + - ss is successful + - ss is not changed + - "ss.url == 'nfs://nfs-mount.domain/share/images/'" + - "ss.provider_name == 'NFS'" + - "ss.zone == cs_common_zone_adv" + - "ss.protocol == 'nfs'" + - "ss.name == 'storage_pool_adv'" + +- name: image store not recreated + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + url: "nfs://nfs-mount.domain/share2/images/" + provider: "NFS" + state: present + register: ss +- name: verify image store not recreated + assert: + that: + - ss is successful + - ss is not changed + - "ss.url == 'nfs://nfs-mount.domain/share/images/'" + - "ss.name == 'storage_pool_adv'" + - "ss.zone == cs_common_zone_adv" + +- name: recreate image store + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + url: "nfs://nfs-mount.domain/share2/images/" + provider: "NFS" + force_recreate: yes + state: present + register: ss +- name: verify setup image store idempotence + assert: + that: + - ss is successful + - ss is changed + - "ss.url == 'nfs://nfs-mount.domain/share2/images/'" + - "ss.name == 'storage_pool_adv'" + - "ss.zone == cs_common_zone_adv" + +- name: delete the image store in check_mode + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ss + check_mode: yes +- name: verify results for delete the image store in check_mode + assert: + that: + - ss is successful + - ss is changed + - "ss.name == 'storage_pool_adv'" + - "ss.zone == cs_common_zone_adv" + +- name: delete the image store + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ss +- name: verify results for delete the image store + assert: + that: + - ss is successful + - ss is changed + - "ss.name == 'storage_pool_adv'" + - "ss.zone == cs_common_zone_adv" + +- name: delete the image store idempotence + cs_image_store: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ss +- name: verify delete the image store idempotence + assert: + that: + - ss is successful + - ss is not changed + - ss.name is undefined + - "ss.zone == cs_common_zone_adv"
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml new file mode 100644 index 00000000..4db5c7c9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/defaults/main.yml @@ -0,0 +1,5 @@ +--- +instance_number: 1 +test_cs_instance_template: "{{ cs_common_template }}" +test_cs_instance_offering_1: Small Instance +test_cs_instance_offering_2: Medium Instance diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml new file mode 100644 index 00000000..ea94b4d8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent.yml @@ -0,0 +1,124 @@ +--- +- name: test destroy instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance + check_mode: true +- name: verify destroy instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.state != "Destroyed" + +- name: test destroy instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify destroy instance + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Destroyed" + +- name: test destroy instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify destroy instance idempotence + assert: + that: + - instance is successful + - instance is not changed + +- name: test recover to stopped state and update a deleted instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance + check_mode: true +- name: verify test recover to stopped state and update a deleted instance in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test recover to stopped state and update a deleted instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance +- name: verify test recover to stopped state and update a deleted instance + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test recover to stopped state and update a deleted instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance +- name: verify test recover to stopped state and update a deleted instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance + check_mode: true +- name: verify test expunge instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify test expunge instance + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify test expunge instance idempotence + assert: + that: + - instance is successful + - instance is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml new file mode 100644 index 00000000..8bea0ae4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/absent_display_name.yml @@ -0,0 +1,47 @@ +--- +- name: test destroy instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify destroy instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Destroyed" + +- name: test destroy instance with display_name idempotence + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify destroy instance with display_name idempotence + assert: + that: + - instance is successful + - instance is not changed + +- name: test recover to stopped state and update a deleted instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance +- name: verify test recover to stopped state and update a deleted instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +# force expunge, only works with admin permissions +- cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + failed_when: false diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml new file mode 100644 index 00000000..655aab60 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/cleanup.yml @@ -0,0 +1,36 @@ +--- +- name: cleanup ssh key + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey" + state: absent + register: sshkey +- name: verify cleanup ssh key + assert: + that: + - sshkey is successful + +- name: cleanup affinity group + cs_affinitygroup: + name: "{{ cs_resource_prefix }}-ag" + state: absent + register: ag + until: ag is successful + retries: 20 + delay: 5 +- name: verify cleanup affinity group + assert: + that: + - ag is successful + +- name: cleanup security group ...take a while unless instance is expunged + cs_securitygroup: + name: "{{ cs_resource_prefix }}-sg" + state: absent + register: sg + until: sg is successful + retries: 100 + delay: 10 +- name: verify cleanup security group + assert: + that: + - sg is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml new file mode 100644 index 00000000..5d4a89c2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/host.yml @@ -0,0 +1,143 @@ +--- +- name: setup ensure running instance to get host infos + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: started + register: running_instance + +- name: setup ensure stopped instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + +- name: setup zone facts + cs_zone_info: + name: "{{ cs_common_zone_basic }}" + register: zone_info + +- name: setup find the host name + shell: cs listHosts type=routing zoneid="{{ zone_info.zones[0].id }}" + args: + chdir: "{{ playbook_dir }}" + register: host + +- name: host convert from json + set_fact: + host_json: "{{ host.stdout | from_json }}" + +- name: select a host on which the instance was not running on + set_fact: + host: "{{ host_json | json_query('host[?name!=`' + running_instance.host + '`] | [0]') }}" + +- debug: + msg: "from current host {{ running_instance.host }} to new host {{ host.name }}" + +- name: test starting instance on new host in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + state: started + register: instance + check_mode: true +- name: verify test starting instance on new host in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.host is not defined + - instance.state == "Stopped" + +- name: test starting instance on new host + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + state: started + register: instance +- name: verify test starting instance on new host + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.host == "{{ host.name }}" + - instance.state == "Running" + +- name: test starting instance on new host idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + state: started + register: instance +- name: verify test starting instance on new host idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.host == "{{ host.name }}" + - instance.state == "Running" + +- name: select a host on which the instance is not running on + set_fact: + host: "{{ host_json | json_query('host[?name!=`' + instance.host + '`] | [0]') }}" + +- debug: + msg: "from current host {{ instance.host }} to new host {{ host.name }}" + +- name: test force update running instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + force: true + register: instance + check_mode: true +- name: verify force update running instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.host != "{{ host.name }}" + - instance.state == "Running" + +- name: test force update running instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + force: true + register: instance +- name: verify force update running instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.host == "{{ host.name }}" + - instance.state == "Running" + +- name: test force update running instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + host: "{{ host.name }}" + force: true + register: instance +- name: verify force update running instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.host == "{{ host.name }}" + - instance.state == "Running" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml new file mode 100644 index 00000000..681e60ab --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- import_tasks: setup.yml + +- import_tasks: present.yml +- import_tasks: tags.yml +- import_tasks: absent.yml + +- import_tasks: present_display_name.yml +- import_tasks: absent_display_name.yml + +# TODO: These tests randomly fail in all kinds of unexpected states. +# This needs to be verified by the cloudstack community. +# - import_tasks: host.yml + +- import_tasks: sshkeys.yml + +- import_tasks: project.yml + +- import_tasks: cleanup.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml new file mode 100644 index 00000000..b800945f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present.yml @@ -0,0 +1,342 @@ +--- +- name: setup instance to be absent + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify instance to be absent + assert: + that: + - instance is successful + +- name: test create instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + user_data: | + #cloud-config + package_upgrade: true + packages: + - tmux + tags: [] + register: instance + check_mode: true +- name: verify create instance in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test create instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + user_data: | + #cloud-config + package_upgrade: true + packages: + - tmux + tags: [] + register: instance +- name: verify create instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + - not instance.tags + +- name: test create instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + user_data: | + #cloud-config + package_upgrade: true + packages: + - tmux + tags: [] + register: instance +- name: verify create instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + - not instance.tags + +- name: gather host infos of running instance + cs_instance_info: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + +- name: test running instance not updated in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance + check_mode: true +- name: verify running instance not updated in check mode + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test running instance not updated + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify running instance not updated + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test stopping instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + register: instance + check_mode: true +- name: verify stopping instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test stopping instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + register: instance +- name: verify stopping instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Stopped" + +- name: test stopping instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + register: instance +- name: verify stopping instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.state == "Stopped" + +- name: test updating stopped instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance + check_mode: true +- name: verify updating stopped instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Stopped" + +- name: test updating stopped instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify updating stopped instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test updating stopped instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify updating stopped instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test starting instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: started + register: instance +- name: verify starting instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test starting instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: started + register: instance +- name: verify starting instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test force update running instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + force: true + register: instance + check_mode: true +- name: verify force update running instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test force update running instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + force: true + register: instance +- name: verify force update running instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test force update running instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + force: true + register: instance +- name: verify force update running instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test restore instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + state: restored + register: instance + check_mode: true +- name: verify restore instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test restore instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + state: restored + register: instance +- name: verify restore instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml new file mode 100644 index 00000000..1daa4c7f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/present_display_name.yml @@ -0,0 +1,190 @@ +--- +- name: setup instance with display_name to be absent + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify instance with display_name to be absent + assert: + that: + - instance is successful + +- name: test create instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + tags: [] + register: instance +- name: verify create instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + - not instance.tags + +- name: test create instance with display_name idempotence + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + tags: [] + register: instance +- name: verify create instance with display_name idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + - not instance.tags + +- name: test running instance with display_name not updated + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify running instance with display_name not updated + assert: + that: + - instance is successful + - instance is not changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test stopping instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + register: instance +- name: verify stopping instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Stopped" + +- name: test stopping instance with display_name idempotence + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: stopped + register: instance +- name: verify stopping instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.state == "Stopped" + +- name: test updating stopped instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify updating stopped instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test starting instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: started + register: instance +- name: verify starting instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test starting instance with display_name idempotence + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + state: started + register: instance +- name: verify starting instance with display_name idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test force update running instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + force: true + register: instance +- name: verify force update running instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test force update running instance with display_name idempotence + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + force: true + register: instance +- name: verify force update running instance with display_name idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test restore instance with display_name + cs_instance: + display_name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + state: restored + register: instance +- name: verify restore instance with display_name + assert: + that: + - instance is successful + - instance is changed + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml new file mode 100644 index 00000000..edb5abf5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/project.yml @@ -0,0 +1,589 @@ +--- +- name: setup create project + cs_project: + name: "{{ cs_resource_prefix }}-prj" + register: prj +- name: verify test create project + assert: + that: + - prj is successful + +- name: setup instance in project to be absent + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: instance +- name: verify instance in project to be absent + assert: + that: + - instance is successful + +- name: setup ssh key in project + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey-prj" + project: "{{ cs_resource_prefix }}-prj" + register: sshkey +- name: verify setup ssh key in project + assert: + that: + - sshkey is successful + +- name: setup affinity group in project + cs_affinitygroup: + name: "{{ cs_resource_prefix }}-ag-prj" + project: "{{ cs_resource_prefix }}-prj" + register: ag +- name: verify setup affinity group in project + assert: + that: + - ag is successful + +- name: setup security group in project + cs_securitygroup: + name: "{{ cs_resource_prefix }}-sg-prj" + project: "{{ cs_resource_prefix }}-prj" + register: sg +- name: verify setup security group in project + assert: + that: + - sg is successful + +- name: test create instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag-prj" + security_group: "{{ cs_resource_prefix }}-sg-prj" + project: "{{ cs_resource_prefix }}-prj" + ssh_key: "{{ cs_resource_prefix }}-sshkey-prj" + tags: [] + register: instance + check_mode: true +- name: verify create instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test create instance in project + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag-prj" + security_group: "{{ cs_resource_prefix }}-sg-prj" + project: "{{ cs_resource_prefix }}-prj" + ssh_key: "{{ cs_resource_prefix }}-sshkey-prj" + tags: [] + register: instance +- name: verify create instance in project + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey-prj" + - not instance.tags + +- name: test create instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag-prj" + security_group: "{{ cs_resource_prefix }}-sg-prj" + project: "{{ cs_resource_prefix }}-prj" + ssh_key: "{{ cs_resource_prefix }}-sshkey-prj" + tags: [] + register: instance +- name: verify create instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey-prj" + - not instance.tags + +- name: test running instance in project not updated in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + project: "{{ cs_resource_prefix }}-prj" + register: instance + check_mode: true +- name: verify running instance in project not updated in check mode + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + + +- name: test running instance in project not updated + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_2 }}" + project: "{{ cs_resource_prefix }}-prj" + register: instance +- name: verify running instance in project not updated + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test stopping instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: stopped + register: instance + check_mode: true +- name: verify stopping instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test stopping instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: stopped + register: instance +- name: verify stopping instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Stopped" + +- name: test stopping instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: stopped + register: instance +- name: verify stopping instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.state == "Stopped" + +- name: test updating stopped instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance + check_mode: true +- name: verify updating stopped instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Stopped" + +- name: test updating stopped instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify updating stopped instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test updating stopped instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_2 }}" + register: instance +- name: verify updating stopped instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test starting instance in project in check mdoe + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: started + register: instance + check_mode: true +- name: verify starting instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Stopped" + +- name: test starting instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: started + register: instance +- name: verify starting instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test starting instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: started + register: instance +- name: verify starting instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test force update running instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + project: "{{ cs_resource_prefix }}-prj" + force: true + register: instance + check_mode: true +- name: verify force update running instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_2 }}" + - instance.state == "Running" + +- name: test force update running instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + project: "{{ cs_resource_prefix }}-prj" + force: true + register: instance +- name: verify force update running instance + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test force update running instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + project: "{{ cs_resource_prefix }}-prj" + force: true + register: instance +- name: verify force update running instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + - instance.state == "Running" + +- name: test restore instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + project: "{{ cs_resource_prefix }}-prj" + state: restored + register: instance + check_mode: true +- name: verify restore instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test restore instance in project + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + project: "{{ cs_resource_prefix }}-prj" + state: restored + register: instance +- name: verify restore instance in project + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + - instance.project == "{{ cs_resource_prefix }}-prj" + - instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test destroy instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: instance + check_mode: true +- name: verify destroy instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.state != "Destroyed" + +- name: test destroy instance in project + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: instance +- name: verify destroy instance in project + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Destroyed" + +- name: test destroy instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: instance +- name: verify destroy instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + +- name: test recover in project to stopped state and update a deleted instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance + check_mode: true +- name: verify test recover to stopped state and update a deleted instance in project in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test recover to stopped state and update a deleted instance in project + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance +- name: verify test recover to stopped state and update a deleted instance in project + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test recover to stopped state and update a deleted instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + service_offering: "{{ test_cs_instance_offering_1 }}" + state: stopped + register: instance +- name: verify test recover to stopped state and update a deleted instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance in project in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: expunged + register: instance + check_mode: true +- name: verify test expunge instance in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance in project + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: expunged + register: instance +- name: verify test expunge instance in project + assert: + that: + - instance is successful + - instance is changed + - instance.state == "Stopped" + - instance.service_offering == "{{ test_cs_instance_offering_1 }}" + +- name: test expunge instance in project idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + project: "{{ cs_resource_prefix }}-prj" + state: expunged + register: instance +- name: verify test expunge instance in project idempotence + assert: + that: + - instance is successful + - instance is not changed + +- name: cleanup ssh key in project + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey-prj" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: sshkey +- name: verify cleanup ssh key in project + assert: + that: + - sshkey is successful + +- name: cleanup affinity group in project + cs_affinitygroup: + name: "{{ cs_resource_prefix }}-ag-prj" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: ag + until: ag is successful + retries: 20 + delay: 5 +- name: verify cleanup affinity group in project + assert: + that: + - ag is successful + +- name: cleanup security group in project ...take a while unless instance in project is expunged + cs_securitygroup: + name: "{{ cs_resource_prefix }}-sg-prj" + project: "{{ cs_resource_prefix }}-prj" + state: absent + register: sg + until: sg is successful + retries: 100 + delay: 10 +- name: verify cleanup security group in project + assert: + that: + - sg is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml new file mode 100644 index 00000000..6600f0f9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/setup.yml @@ -0,0 +1,27 @@ +--- +- name: setup ssh key + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey" + register: sshkey +- name: verify setup ssh key + assert: + that: + - sshkey is successful + +- name: setup affinity group + cs_affinitygroup: + name: "{{ cs_resource_prefix }}-ag" + register: ag +- name: verify setup affinity group + assert: + that: + - ag is successful + +- name: setup security group + cs_securitygroup: + name: "{{ cs_resource_prefix }}-sg" + register: sg +- name: verify setup security group + assert: + that: + - sg is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml new file mode 100644 index 00000000..89202773 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/sshkeys.yml @@ -0,0 +1,181 @@ +--- +- name: test update instance ssh key non existent + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey-does-not-exist" + template: "{{ test_cs_instance_template }}" + force: true + register: instance + ignore_errors: true +- name: verify update instance ssh key non existent + assert: + that: + - instance is failed + - 'instance.msg == "SSH key not found: {{ cs_resource_prefix }}-sshkey-does-not-exist"' + +- name: test create instance without keypair in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + check_mode: true + register: instance +- name: verify create instance without keypair in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test create instance without keypair + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + register: instance +- name: verify create instance without keypair + assert: + that: + - instance is successful + - instance is changed + - instance.ssh_key is not defined + +- name: test create instance without keypair idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + register: instance +- name: verify create instance without keypair idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.ssh_key is not defined + +- name: setup ssh key2 + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey2" + register: sshkey +- name: verify setup ssh key2 + assert: + that: + - sshkey is successful + +- name: test update instance ssh key2 in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey2" + force: true + check_mode: true + register: instance +- name: verify update instance ssh key2 in check mode + assert: + that: + - instance is changed + - instance.ssh_key is not defined + +- name: test update instance ssh key2 + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey2" + force: true + register: instance +- name: verify update instance ssh key2 + assert: + that: + - instance is changed + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey2" + +- name: test update instance ssh key2 idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey2" + force: true + register: instance +- name: verify update instance ssh key2 idempotence + assert: + that: + - instance is not changed + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey2" + +- name: cleanup ssh key2 + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey2" + state: absent + register: sshkey2 +- name: verify cleanup ssh key2 + assert: + that: + - sshkey2 is successful + +- name: test update instance ssh key2 idempotence2 + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey2" + force: true + register: instance + ignore_errors: true +- name: verify update instance ssh key2 idempotence2 + assert: + that: + - instance is failed + - 'instance.msg == "SSH key not found: {{ cs_resource_prefix }}-sshkey2"' + +- name: test update instance ssh key in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + force: true + check_mode: true + register: instance +- name: verify update instance ssh key in check mode + assert: + that: + - instance is changed + - instance.ssh_key is not defined + +- name: test update instance ssh key + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + force: true + register: instance +- name: verify update instance ssh key + assert: + that: + - instance is changed + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + +- name: test update instance ssh key idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + force: true + register: instance +- name: verify update instance ssh key idempotence + assert: + that: + - instance is not changed + - instance.ssh_key == "{{ cs_resource_prefix }}-sshkey" + +- name: cleanup expunge instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-sshkey" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify cleanup expunge instance + assert: + that: + - instance is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml new file mode 100644 index 00000000..667e5a8b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance/tasks/tags.yml @@ -0,0 +1,140 @@ +--- +- name: test add tags to instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + tags: + - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" } + - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" } + register: instance + check_mode: true +- name: verify add tags to instance in check mode + assert: + that: + - instance is successful + - instance is changed + - not instance.tags + +- name: test add tags to instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + tags: + - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" } + - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" } + register: instance +- name: verify add tags to instance + assert: + that: + - instance is successful + - instance is changed + - instance.tags|length == 2 + - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + +- name: test tags to instance idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + tags: + - { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" } + - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" } + register: instance +- name: verify tags to instance idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.tags|length == 2 + - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + +- name: test change tags of instance in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + tags: + - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" } + - { key: "{{ cs_resource_prefix }}-tag3", value: "{{ cs_resource_prefix }}-value3" } + register: instance + check_mode: true +- name: verify tags to instance idempotence in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.tags|length == 2 + - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag1' ]" + - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value1' ]" + +- name: test change tags of instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + tags: + - { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" } + - { key: "{{ cs_resource_prefix }}-tag3", value: "{{ cs_resource_prefix }}-value3" } + register: instance +- name: verify tags to instance idempotence + assert: + that: + - instance is successful + - instance is changed + - instance.tags|length == 2 + - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]" + - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]" + - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]" + - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]" + +- name: test not touch tags of instance if no param tags + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + register: instance +- name: verify not touch tags of instance if no param tags + assert: + that: + - instance is successful + - instance is not changed + - instance.tags|length == 2 + - "instance.tags[0]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]" + - "instance.tags[1]['key'] in [ '{{ cs_resource_prefix }}-tag2', '{{ cs_resource_prefix }}-tag3' ]" + - "instance.tags[0]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]" + - "instance.tags[1]['value'] in [ '{{ cs_resource_prefix }}-value2', '{{ cs_resource_prefix }}-value3' ]" + +- name: test remove tags in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + tags: [] + register: instance + check_mode: true +- name: verify remove tags in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.tags|length != 0 + +- name: test remove tags + cs_instance: + name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}" + zone: "{{ cs_common_zone_basic }}" + tags: [] + register: instance +- name: verify remove tags + assert: + that: + - instance is successful + - instance is changed + - instance.tags|length == 0 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml new file mode 100644 index 00000000..490c6c14 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/defaults/main.yml @@ -0,0 +1,3 @@ +--- +test_cs_instance_template: "{{ cs_common_template }}" +test_cs_instance_offering_1: Small Instance diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml new file mode 100644 index 00000000..c56caf5a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_info/tasks/main.yml @@ -0,0 +1,80 @@ +--- +- name: setup ssh key + cs_sshkeypair: + name: "{{ cs_resource_prefix }}-sshkey" + register: sshkey + +- name: setup affinity group + cs_affinitygroup: + name: "{{ cs_resource_prefix }}-ag" + +- name: setup security group + cs_securitygroup: + name: "{{ cs_resource_prefix }}-sg" + +- name: setup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + affinity_group: "{{ cs_resource_prefix }}-ag" + security_group: "{{ cs_resource_prefix }}-sg" + ssh_key: "{{ cs_resource_prefix }}-sshkey" + tags: [] + zone: "{{ cs_common_zone_basic }}" + register: instance + until: instance is successful + retries: 20 + delay: 5 + +- name: test instance info in check mode + cs_instance_info: + name: "{{ cs_resource_prefix }}-vm" + register: instance_info + check_mode: true +- name: verify test instance info in check mode + assert: + that: + - instance_info is successful + - instance_info is not changed + - instance_info.instances[0].id == instance.id + - instance_info.instances[0].domain == instance.domain + - instance_info.instances[0].account == instance.account + - instance_info.instances[0].zone == instance.zone + - instance_info.instances[0].name == instance.name + - instance_info.instances[0].service_offering == instance.service_offering + - instance_info.instances[0].host != "" + +- name: test instance info + cs_instance_info: + name: "{{ cs_resource_prefix }}-vm" + register: instance_info +- name: verify test instance info + assert: + that: + - instance_info is successful + - instance_info is not changed + - instance_info.instances[0].id == instance.id + - instance_info.instances[0].domain == instance.domain + - instance_info.instances[0].account == instance.account + - instance_info.instances[0].zone == instance.zone + - instance_info.instances[0].name == instance.name + - instance_info.instances[0].service_offering == instance.service_offering + - instance_info.instances[0].host != "" + +- name: test instance info for all instances + cs_instance_info: + register: instance_info +- name: verify test instance info + assert: + that: + - instance_info is successful + - instance_info is not changed + - instance_info.instances | length > 0 + - '"id" in instance_info.instances[0]' + - '"domain" in instance_info.instances[0]' + - '"account" in instance_info.instances[0]' + - '"zone" in instance_info.instances[0]' + - '"name" in instance_info.instances[0]' + - '"service_offering" in instance_info.instances[0]' + - '"host" in instance_info.instances[0]' diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml new file mode 100644 index 00000000..83b564e1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic/tasks/main.yml @@ -0,0 +1,306 @@ +--- +- name: setup network + cs_network: + name: "net_nic" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + network_domain: example.com + vlan: 1234 + start_ip: 10.100.123.11 + end_ip: 10.100.123.250 + gateway: 10.100.123.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network + assert: + that: + - net is successful + - net.name == "net_nic" + +- name: setup instance + cs_instance: + name: "instance-nic-vm" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "net_nic" + state: stopped + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + - instance.name == "instance-nic-vm" + - instance.state == "Stopped" + +- name: setup network 2 + cs_network: + name: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + network_domain: example.com + vlan: 1235 + start_ip: 10.100.124.11 + end_ip: 10.100.124.250 + gateway: 10.100.124.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network 2 + assert: + that: + - net is successful + - net.name == "net_nic2" + +- name: setup absent nic + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: nic +- name: verify setup absent nic + assert: + that: + - nic is successful + +- name: test fail missing params + cs_instance_nic: + ignore_errors: true + register: nic +- name: verify test fail missing params + assert: + that: + - nic is failed + - "nic.msg.startswith('missing required arguments: ')" + +- name: test create nic in check mode + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + check_mode: yes + register: nic +- name: verify test create nic in check mode + assert: + that: + - nic is successful + - nic is changed + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + +- name: test create nic + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.42 + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test create nic + assert: + that: + - nic is successful + - nic is changed + - nic.ip_address == "10.100.124.42" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test create nic idempotence + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.42 + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test create nic idempotence + assert: + that: + - nic is successful + - nic is not changed + - nic.ip_address == "10.100.124.42" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test create nic without ip address idempotence + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test create nic without ip address idempotence + assert: + that: + - nic is successful + - nic is not changed + - nic.ip_address == "10.100.124.42" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test update nic in check mode + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.23 + zone: "{{ cs_common_zone_adv }}" + check_mode: yes + register: nic +- name: verify test update nic in check mode + assert: + that: + - nic is successful + - nic is changed + - nic.ip_address == "10.100.124.42" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test update nic + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.23 + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test update nic + assert: + that: + - nic is successful + - nic is changed + - nic.ip_address == "10.100.124.23" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test update nic idempotence + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.23 + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test update nic idempotence + assert: + that: + - nic is successful + - nic is not changed + - nic.ip_address == "10.100.124.23" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test update nic without ip address idempotence + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test update nic without ip address idempotence + assert: + that: + - nic is successful + - nic is not changed + - nic.ip_address == "10.100.124.23" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test remove nic in check mode + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + check_mode: yes + register: nic +- name: verify test remove nic in check mode + assert: + that: + - nic is successful + - nic is changed + - nic.ip_address == "10.100.124.23" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test remove nic + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: nic +- name: verify test remove nic + assert: + that: + - nic is successful + - nic is changed + - nic.ip_address == "10.100.124.23" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: test remove nic idempotence + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: nic +- name: verify test remove nic idempotence + assert: + that: + - nic is successful + - nic is not changed + +- name: cleanup instance + cs_instance: + name: "instance-nic-vm" + state: expunged + register: instance +- name: verify cleanup instance + assert: + that: + - instance is successful + +- name: cleanup network + cs_network: + name: "net_nic" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify cleanup network + assert: + that: + - net is successful + +- name: cleanup network 2 + cs_network: + name: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify cleanup network 2 + assert: + that: + - net is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml new file mode 100644 index 00000000..22241e64 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_nic_secondaryip/tasks/main.yml @@ -0,0 +1,221 @@ +--- +- name: setup network + cs_network: + name: "net_nic" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + network_domain: example.com + vlan: "1234" + start_ip: 10.100.123.11 + end_ip: 10.100.123.250 + gateway: 10.100.123.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network + assert: + that: + - net is successful + - net.name == "net_nic" + +- name: setup instance + cs_instance: + name: "instance-nic-vm" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "net_nic" + state: stopped + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + - instance.name == "instance-nic-vm" + - instance.state == "Stopped" + +- name: setup network 2 + cs_network: + name: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + network_domain: example.com + vlan: "1235" + start_ip: 10.100.124.11 + end_ip: 10.100.124.250 + gateway: 10.100.124.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network 2 + assert: + that: + - net is successful + - net.name == "net_nic2" + +- name: setup nic + cs_instance_nic: + vm: "instance-nic-vm" + network: "net_nic2" + ip_address: 10.100.124.42 + zone: "{{ cs_common_zone_adv }}" + register: nic +- name: verify test create nic + assert: + that: + - nic is successful + - nic.ip_address == "10.100.124.42" + - nic.netmask == "255.255.255.0" + - nic.network == "net_nic2" + - nic.vm == "instance-nic-vm" + - nic.zone == "{{ cs_common_zone_adv }}" + - nic.mac_address is defined + +- name: setup remove secondary ip + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sip +- name: verify setup remove secondary ip + assert: + that: + - sip is successful + +- name: test add secondary ip in check mode + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + check_mode: true + register: sip +- name: verify test add secondary ip in check mode + assert: + that: + - sip is successful + - sip is changed + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: test add secondary ip + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + register: sip +- name: verify test add secondary ip + assert: + that: + - sip is successful + - sip is changed + - sip.vm_guest_ip == "10.100.124.43" + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: test add secondary ip idempotence + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + register: sip +- name: verify test add secondary ip idempotence + assert: + that: + - sip is successful + - sip is not changed + - sip.vm_guest_ip == "10.100.124.43" + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: test remove secondary ip in check mode + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + state: absent + check_mode: true + register: sip +- name: verify test remove secondary ip in check mode + assert: + that: + - sip is successful + - sip is changed + - sip.vm_guest_ip == "10.100.124.43" + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: test remove secondary ip + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sip +- name: verify test remove secondary ip + assert: + that: + - sip is successful + - sip is changed + - sip.vm_guest_ip == "10.100.124.43" + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: test remove secondary ip idempotence + cs_instance_nic_secondaryip: + vm: "instance-nic-vm" + network: "net_nic2" + vm_guest_ip: 10.100.124.43 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sip +- name: verify test remove secondary ip idempotence + assert: + that: + - sip is successful + - sip is not changed + - sip.network == "net_nic2" + - sip.vm == "instance-nic-vm" + - sip.zone == "{{ cs_common_zone_adv }}" + +- name: cleanup instance + cs_instance: + name: "instance-nic-vm" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify cleanup instance + assert: + that: + - instance is successful + +- name: cleanup network + cs_network: + name: "net_nic" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify cleanup network + assert: + that: + - net is successful + +- name: cleanup network 2 + cs_network: + name: "net_nic2" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify cleanup network 2 + assert: + that: + - net is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml new file mode 100644 index 00000000..8a9155b0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instance_password_reset/tasks/main.yml @@ -0,0 +1,94 @@ +--- +- name: reset without giving a VM + action: cs_instance_password_reset + ignore_errors: yes + register: reset1 +- name: verify that the argument was missing + assert: + that: + - reset1 is failed + - "reset1.msg == 'missing required arguments: vm'" + +- name: disable password_enabled on default template + cs_template: + name: "{{ cs_common_template }}" + template_filter: all + password_enabled: no + zone: "{{ cs_common_zone_adv }}" + +- name: cleanup test VM + cs_instance: + name: test-nopassword + zone: "{{ cs_common_zone_adv }}" + state: expunged + +- name: create test VM + cs_instance: + name: test-nopassword + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + state: started + register: testvm_nopass + until: testvm_nopass is success + retries: 12 + delay: 10 + +- name: stop test VM + cs_instance: + name: test-nopassword + zone: "{{ cs_common_zone_adv }}" + state: stopped + +- name: reset nopassword + cs_instance_password_reset: + vm: test-nopassword + zone: "{{ cs_common_zone_adv }}" + ignore_errors: yes + register: reset2 +- name: verify that template was not pw enabled + assert: + that: + - reset2 is failed + - reset2.msg.endswith("the template is not password enabled'") + +- name: enable password_enabled on default template + cs_template: + name: "{{ cs_common_template }}" + template_filter: all + password_enabled: yes + zone: "{{ cs_common_zone_adv }}" + +- name: cleanup test VM + cs_instance: + name: test-password + zone: "{{ cs_common_zone_adv }}" + state: expunged + +- name: create test VM + cs_instance: + name: test-password + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + state: started + +- name: stop test VM + cs_instance: + name: test-password + zone: "{{ cs_common_zone_adv }}" + state: stopped + +- name: reset password + cs_instance_password_reset: + vm: test-password + zone: "{{ cs_common_zone_adv }}" + register: reset3 +- name: verify that a password was set + assert: + that: + - reset3 is success + - reset3.password != '' + +- debug: + var: reset3.password diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml new file mode 100644 index 00000000..6ba31751 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_instancegroup/tasks/main.yml @@ -0,0 +1,79 @@ +--- +- name: setup + cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent + register: ig +- name: verify setup + assert: + that: + - ig is successful + +- name: test fail if missing name + action: cs_instancegroup + register: ig + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - ig is failed + - "ig.msg == 'missing required arguments: name'" + +- name: test present instance group in check mode + cs_instancegroup: name={{ cs_resource_prefix }}_ig + register: ig + check_mode: true +- name: verify results of create instance group in check mode + assert: + that: + - ig is successful + - ig is changed + +- name: test present instance group + cs_instancegroup: name={{ cs_resource_prefix }}_ig + register: ig +- name: verify results of create instance group + assert: + that: + - ig is successful + - ig is changed + - ig.name == "{{ cs_resource_prefix }}_ig" + +- name: test present instance group is idempotence + cs_instancegroup: name={{ cs_resource_prefix }}_ig + register: ig +- name: verify results present instance group is idempotence + assert: + that: + - ig is successful + - ig is not changed + - ig.name == "{{ cs_resource_prefix }}_ig" + +- name: test absent instance group in check mode + cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent + register: ig + check_mode: true +- name: verify results of absent instance group in check mode + assert: + that: + - ig is successful + - ig is changed + - ig.name == "{{ cs_resource_prefix }}_ig" + +- name: test absent instance group + cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent + register: ig +- name: verify results of absent instance group + assert: + that: + - ig is successful + - ig is changed + - ig.name == "{{ cs_resource_prefix }}_ig" + +- name: test absent instance group is idempotence + cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent + register: ig +- name: verify results of absent instance group is idempotence + assert: + that: + - ig is successful + - ig is not changed + - ig.name is undefined diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml new file mode 100644 index 00000000..48ccd023 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- name: test fail vpc and network mutually exclusive + cs_ip_address: + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "foobar" + zone: "{{ cs_common_zone_adv }}" + ignore_errors: yes + register: ip_address +- name: verify test fail vpc and network mutually exclusive + assert: + that: + - ip_address is failed + - 'ip_address.msg == "parameters are mutually exclusive: vpc|network"' + +- name: run test for network setup + import_tasks: network.yml + +- name: run test for vpc setup + import_tasks: vpc.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml new file mode 100644 index 00000000..e87ff972 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/network.yml @@ -0,0 +1,240 @@ +--- +- name: setup ensure the test network is absent + cs_network: + name: ipaddr_test_network + state: absent + zone: "{{ cs_common_zone_adv }}" + +- name: setup create the test network + cs_network: + name: ipaddr_test_network + network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService + state: present + zone: "{{ cs_common_zone_adv }}" + register: base_network +- name: setup verify create the test network + assert: + that: + - base_network is successful + +- name: setup instance to get network in implementation state + cs_instance: + name: "{{ cs_resource_prefix }}-vm-cs-ip-address" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + networks: + - "{{ base_network.name }}" + register: instance + until: instance is success + retries: 20 + delay: 5 +- name: verify instance setup + assert: + that: + - instance is successful + +- name: setup clean ip_address with tags + cs_ip_address: + state: absent + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + +- name: setup associate ip_address for SNAT + cs_ip_address: + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address_snat + +- name: test associate ip_address in check mode + cs_ip_address: + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + check_mode: true + register: ip_address +- name: verify test associate ip_address in check mode + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test associate ip_address + cs_ip_address: + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test associate ip_address + assert: + that: + - ip_address is successful + - ip_address is changed + - ip_address.ip_address is defined + +- name: test associate ip_address with tags in check mode + cs_ip_address: + network: ipaddr_test_network + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag + check_mode: true +- name: verify test associate ip_address with tags in check mode + assert: + that: + - ip_address_tag is successful + - ip_address_tag is changed + +- name: test associate ip_address with tags + cs_ip_address: + network: ipaddr_test_network + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag +- name: verify test associate ip_address with tags + assert: + that: + - ip_address_tag is successful + - ip_address_tag is changed + - ip_address_tag.ip_address is defined + - ip_address_tag.tags.0.key == "unique_id" + - ip_address_tag.tags.0.value == "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + +- name: test associate ip_address with tags idempotence + cs_ip_address: + network: ipaddr_test_network + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag +- name: verify test associate ip_address with tags idempotence + assert: + that: + - ip_address_tag is successful + - ip_address_tag is not changed + - ip_address_tag.ip_address is defined + - ip_address_tag.state == "Allocated" + - ip_address_tag.tags.0.key == "unique_id" + - ip_address_tag.tags.0.value == "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + +- name: test disassiociate ip_address with missing param ip_address + cs_ip_address: + state: absent + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: ip_address_err +- name: verify test disassiociate ip_address with missing param ip_address + assert: + that: + - ip_address_err is failed + - 'ip_address_err.msg == "state is absent but any of the following are missing: ip_address, tags"' + +- name: test disassociate ip_address in check mode + cs_ip_address: + state: absent + ip_address: "{{ ip_address.ip_address }}" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + check_mode: true + register: ip_address +- name: verify test disassociate ip_address in check mode + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address + cs_ip_address: + state: absent + ip_address: "{{ ip_address.ip_address }}" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address idempotence + cs_ip_address: + state: absent + ip_address: "{{ ip_address.ip_address }}" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address idempotence + assert: + that: + - ip_address is successful + - ip_address is not changed + +- name: test disassociate ip_address with tags with check mode + cs_ip_address: + state: absent + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + check_mode: true + register: ip_address +- name: verify test disassociate ip_address with tags in check mode + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address with tags + cs_ip_address: + state: absent + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address with tags + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address with tags idempotence + cs_ip_address: + state: absent + tags: + - key: unique_id + value: "adacd65e-7868-5ebf-9f8b-e6e0ea779861" + network: ipaddr_test_network + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address with tags idempotence + assert: + that: + - ip_address is successful + - ip_address is not changed + +- name: cleanup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-cs-ip-address" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify instance cleanup + assert: + that: + - instance is successful + +- name: clean the test network + cs_network: + name: ipaddr_test_network + state: absent + zone: "{{ cs_common_zone_adv }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml new file mode 100644 index 00000000..3a089ebd --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_ip_address/tasks/vpc.yml @@ -0,0 +1,121 @@ +--- +- name: setup vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_ip_address" + cidr: 10.10.111.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup clean ip_address with tags + cs_ip_address: + state: absent + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + tags: + - key: unique_id + value: "86cdce4c-dce7-11e8-8394-00262df3bf70" + zone: "{{ cs_common_zone_adv }}" + +- name: test associate ip_address in vpc with tags in check mode + cs_ip_address: + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + tags: + - key: unique_id + value: "86cdce4c-dce7-11e8-8394-00262df3bf70" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag + check_mode: yes +- name: verify test associate ip_address in vpc with tags in check mode + assert: + that: + - ip_address_tag is successful + - ip_address_tag is changed + +- name: test associate ip_address in vpc with tags + cs_ip_address: + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + tags: + - key: unique_id + value: "86cdce4c-dce7-11e8-8394-00262df3bf70" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag +- name: verify test associate ip_address in vpc with tags + assert: + that: + - ip_address_tag is successful + - ip_address_tag is changed + - ip_address_tag.ip_address is defined + - ip_address_tag.tags.0.key == "unique_id" + - ip_address_tag.tags.0.value == "86cdce4c-dce7-11e8-8394-00262df3bf70" + +- name: test associate ip_address in vpc with tags idempotence + cs_ip_address: + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + tags: + - key: unique_id + value: "86cdce4c-dce7-11e8-8394-00262df3bf70" + zone: "{{ cs_common_zone_adv }}" + register: ip_address_tag +- name: verify test associate ip_address in vpc with tags idempotence + assert: + that: + - ip_address_tag is successful + - ip_address_tag is not changed + - ip_address_tag.ip_address is defined + - ip_address_tag.state == "Allocated" + - ip_address_tag.tags.0.key == "unique_id" + - ip_address_tag.tags.0.value == "86cdce4c-dce7-11e8-8394-00262df3bf70" + +- name: test disassociate ip_address in vpc in check mode + cs_ip_address: + state: absent + ip_address: "{{ ip_address_tag.ip_address }}" + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + zone: "{{ cs_common_zone_adv }}" + check_mode: true + register: ip_address +- name: verify test disassociate ip_address in vpc in check mode + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address in vpc + cs_ip_address: + state: absent + ip_address: "{{ ip_address_tag.ip_address }}" + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address in vpc + assert: + that: + - ip_address is successful + - ip_address is changed + +- name: test disassociate ip_address in vpc idempotence + cs_ip_address: + state: absent + ip_address: "{{ ip_address_tag.ip_address }}" + vpc: "{{ cs_resource_prefix }}_vpc_ip_address" + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify test disassociate ip_address in vpc idempotence + assert: + that: + - ip_address is successful + - ip_address is not changed + +- name: cleanup vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_ip_address" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpc +- name: verify cleanup vpc + assert: + that: + - vpc is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml new file mode 100644 index 00000000..de279224 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/tasks/main.yml @@ -0,0 +1,143 @@ +--- +- name: setup iso + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + cross_zones: true + state: absent + register: iso +- name: verify setup iso + assert: + that: + - iso is successful + +- name: test download iso in check mode + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + url: "{{ cs_iso_url }}" + os_type: Debian GNU/Linux 7(64-bit) + cross_zones: true + register: iso + check_mode: true +- name: verify test download iso in check mode + assert: + that: + - iso is changed + +- name: test download iso + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + url: "{{ cs_iso_url }}" + os_type: Debian GNU/Linux 7(64-bit) + cross_zones: true + register: iso +- name: verify test download iso + assert: + that: + - iso is changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso" + - iso.cross_zones == true + +- name: test download iso idempotence + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + url: "{{ cs_iso_url }}" + os_type: Debian GNU/Linux 7(64-bit) + cross_zones: true + register: iso +- name: verify test download iso idempotence + assert: + that: + - iso is not changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso" + - iso.cross_zones == true + +- name: test update iso in check mdoe + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + display_text: "{{ cs_resource_prefix }}-iso display_text" + url: "{{ cs_iso_url }}" + os_type: CentOS 7 + cross_zones: true + register: iso + check_mode: true +- name: verify test update iso in check mode + assert: + that: + - iso is changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso" + - iso.cross_zones == true + +- name: test update iso + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + display_text: "{{ cs_resource_prefix }}-iso display_text" + url: "{{ cs_iso_url }}" + os_type: CentOS 7 + cross_zones: true + register: iso +- name: verify test update iso + assert: + that: + - iso is changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso display_text" + - iso.cross_zones == true + +- name: test update iso idempotence + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + display_text: "{{ cs_resource_prefix }}-iso display_text" + url: "{{ cs_iso_url }}" + os_type: CentOS 7 + cross_zones: true + register: iso +- name: verify test update iso idempotence + assert: + that: + - iso is not changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso display_text" + - iso.cross_zones == true + +- name: test remove iso in check mode + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + state: absent + cross_zones: true + register: iso + check_mode: true +- name: verify test remove iso in check mode + assert: + that: + - iso is changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso display_text" + - iso.cross_zones == true + +- name: test remove iso + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + state: absent + cross_zones: true + register: iso +- name: verify test remove iso + assert: + that: + - iso is changed + - iso.name == "{{ cs_resource_prefix }}-iso" + - iso.display_text == "{{ cs_resource_prefix }}-iso display_text" + - iso.cross_zones == true + +- name: test remove iso idempotence + cs_iso: + name: "{{ cs_resource_prefix }}-iso" + state: absent + cross_zones: true + register: iso +- name: verify test remove iso idempotence + assert: + that: + - iso is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main new file mode 100644 index 00000000..1670b14c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_iso/vars/main @@ -0,0 +1,2 @@ +--- +cs_iso_url: https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-10.6.0-amd64-netinst.iso diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml new file mode 100644 index 00000000..13d2f005 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_loadbalancer_rule/tasks/main.yml @@ -0,0 +1,392 @@ +--- +- name: ensure instance is expunged + cs_instance: + name: "{{ cs_resource_prefix }}-vm-lb" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify ensure instance is expunged + assert: + that: + - instance is successful + +- name: ensure network is absent + cs_network: + name: "{{ cs_resource_prefix }}_net_lb" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: lb_net +- name: verify ensure network is absent + assert: + that: + - lb_net is successful + +- name: test create network for lb + cs_network: + name: "{{ cs_resource_prefix }}_net_lb" + zone: "{{ cs_common_zone_adv }}" + network_offering: Offering for Isolated networks with Source Nat service enabled + register: lb_net +- name: verify test create network for lb + assert: + that: + - lb_net is successful + - lb_net is changed + - lb_net.name == "{{ cs_resource_prefix }}_net_lb" + +- name: setup instance in lb + cs_instance: + name: "{{ cs_resource_prefix }}-vm-lb" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "{{ cs_resource_prefix }}_net_lb" + register: instance + until: instance is success + retries: 20 + delay: 5 +- name: verify setup instance in lb + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-lb" + - instance.state == "Running" + +- name: setup get ip address for lb + cs_ip_address: + network: "{{ cs_resource_prefix }}_net_lb" + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify setup get ip address in lb + assert: + that: + - ip_address is successful + +- name: setup lb rule absent + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + state: absent + register: lb +- name: verify setup lb rule absent + assert: + that: + - lb is successful + +- name: test rule requires params + cs_loadbalancer_rule: + ignore_errors: true + register: lb +- name: verify test rule requires params + assert: + that: + - lb is failed + - "lb.msg.startswith('missing required arguments: ')" + + +- name: test create rule in check mode + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: roundrobin + public_port: 80 + private_port: 8080 + register: lb + check_mode: true +- name: verify test create rule in check mode + assert: + that: + - lb is successful + - lb is changed + +- name: test create rule + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: roundrobin + public_port: 80 + private_port: 8080 + register: lb +- name: verify test create rule + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "roundrobin" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test create rule idempotence + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: roundrobin + public_port: 80 + private_port: 8080 + register: lb +- name: verify test create rule idempotence + assert: + that: + - lb is successful + - lb is not changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "roundrobin" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test update rule in check mode + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: source + public_port: 80 + private_port: 8080 + register: lb + check_mode: true +- name: verify test update rule in check mode + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "roundrobin" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test update rule + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: source + public_port: 80 + private_port: 8080 + register: lb +- name: verify test update rule + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test update rule idempotence + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + algorithm: source + public_port: 80 + private_port: 8080 + register: lb +- name: verify test update rule idempotence + assert: + that: + - lb is successful + - lb is not changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test rule member requires params + cs_loadbalancer_rule_member: + ignore_errors: true + register: lb +- name: verify test rule requires params + assert: + that: + - lb is failed + - "lb.msg.startswith('missing required arguments: ')" + +- name: test add members to rule in check mode + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + register: lb + check_mode: true +- name: verify add members to rule in check mode + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + - "'{{ cs_resource_prefix }}-vm-lb' not in lb.vms" + +- name: test add members to rule + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + register: lb +- name: verify add members to rule + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms" + +- name: test add members to rule idempotence + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + register: lb +- name: verify add members to rule idempotence + assert: + that: + - lb is successful + - lb is not changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms" + +- name: test remove members to rule in check mode + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + state: absent + register: lb + check_mode: true +- name: verify remove members to rule in check mode + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + - "'{{ cs_resource_prefix }}-vm-lb' in lb.vms" + +- name: test remove members to rule + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + state: absent + register: lb +- name: verify remove members to rule + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + - "'{{ cs_resource_prefix }}-vm-lb' not in lb.vms" + +- name: test remove members to rule idempotence + cs_loadbalancer_rule_member: + name: "{{ cs_resource_prefix }}_lb" + vm: "{{ cs_resource_prefix }}-vm-lb" + state: absent + register: lb +- name: verify remove members to rule + assert: + that: + - lb is successful + - lb is not changed + +- name: test remove rule in check mode + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + state: absent + register: lb + check_mode: true +- name: verify remove rule in check mode + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test remove rule + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + state: absent + register: lb +- name: verify remove rule + assert: + that: + - lb is successful + - lb is changed + - lb.name == "{{ cs_resource_prefix }}_lb" + - lb.algorithm == "source" + - lb.public_ip == "{{ ip_address.ip_address }}" + - lb.public_port == 80 + - lb.private_port == 8080 + +- name: test remove rule idempotence + cs_loadbalancer_rule: + name: "{{ cs_resource_prefix }}_lb" + public_ip: "{{ ip_address.ip_address }}" + state: absent + register: lb +- name: verify remove rule idempotence + assert: + that: + - lb is successful + - lb is not changed + +- name: cleanup ip address + cs_ip_address: + network: "{{ cs_resource_prefix }}_net_lb" + zone: "{{ cs_common_zone_adv }}" + ip_address: "{{ ip_address.ip_address }}" + state: absent + register: ip_address +- name: verify cleanup ip address + assert: + that: + - ip_address is successful + - instance is changed + +- name: cleanup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-lb" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify cleanup instance + assert: + that: + - instance is successful + - instance is changed + +- name: cleanup network + cs_network: + name: "{{ cs_resource_prefix }}_net_lb" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: lb_net +- name: verify cleanup network + assert: + that: + - lb_net is successful + - lb_net is changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml new file mode 100644 index 00000000..cfe24c41 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/main.yml @@ -0,0 +1,3 @@ +--- + +- include_tasks: vpc_network_tier.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml new file mode 100644 index 00000000..4854cae9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network/tasks/vpc_network_tier.yml @@ -0,0 +1,299 @@ +--- +- name: setup cleanup vpc network tier + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + vpc: vpc_network_test + state: absent + ignore_errors: yes + +- name: setup cleanup existing vpc + cs_vpc: + name: vpc_network_test + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpc +- name: verify cleanup existing vpc + assert: + that: + - vpc is successful + +- name: setup vpc + cs_vpc: + name: vpc_network_test + cidr: 10.43.0.0/16 + zone: "{{ cs_common_zone_adv }}" + vpc_offering: Redundant VPC offering + network_domain: cs2sandbox.simulator.example.com + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup network acl + cs_network_acl: + name: my_network_acl1 + vpc: vpc_network_test + zone: "{{ cs_common_zone_adv }}" + register: acl +- name: verify setup network acl + assert: + that: + - acl is successful + +- name: setup network acl rule + cs_network_acl_rule: + network_acl: my_network_acl1 + rule_position: 1 + vpc: vpc_network_test + traffic_type: ingress + action_policy: allow + port: 80 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify setup network acl rule + assert: + that: + - acl_rule is successful + +- name: setup vpc network tier + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + vpc: vpc_network_test + state: absent + register: network +- name: verify setup vpc network tier + assert: + that: + - network is successful + +- name: test fail vpc network tier if vpc not given + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + acl: my_network_acl1 + check_mode: yes + register: network + ignore_errors: yes +- name: verify test fail vpc network tier if vpc not given + assert: + that: + - network is failed + - "network.msg == 'Missing required params: vpc'" + +- name: test create a vpc network tier in check mode + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + check_mode: yes + register: network +- name: verify test create a vpc network tier in check mode + assert: + that: + - network is changed + +- name: test create a vpc network tier + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + register: network +- name: verify test create a vpc network tier + assert: + that: + - network is changed + - network.acl_type == 'Account' + - not network.acl + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test create a vpc network tier idempotence + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + register: network +- name: verify test create a vpc network tier idempotence + assert: + that: + - network is not changed + - network.acl_type == 'Account' + - not network.acl + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test update a vpc network tier in check mode + cs_network: + name: vpc tier 1 + display_text: vpc tier 1 description + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + acl: my_network_acl1 + check_mode: yes + register: network +- name: verify test update a vpc network tier in check mode + assert: + that: + - network is changed + - network.acl_type == 'Account' + - network.acl == 'my_network_acl1' + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test update a vpc network tier + cs_network: + name: vpc tier 1 + display_text: vpc tier 1 description + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + acl: my_network_acl1 + register: network +- name: verify test update a vpc network tier + assert: + that: + - network is changed + - network.acl_type == 'Account' + - network.acl == 'my_network_acl1' + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1 description' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test update a vpc network tier idempotence + cs_network: + name: vpc tier 1 + display_text: vpc tier 1 description + zone: "{{ cs_common_zone_adv }}" + network_domain: cs2sandbox.simulator.example.com + vpc: vpc_network_test + network_offering: DefaultIsolatedNetworkOfferingForVpcNetworks + gateway: 10.43.0.1 + netmask: 255.255.255.0 + acl: my_network_acl1 + register: network +- name: verify test update a vpc network tier idempotence + assert: + that: + - network is not changed + - network.acl_type == 'Account' + - network.acl == 'my_network_acl1' + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1 description' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test absent a vpc network tier in check mode + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + vpc: vpc_network_test + state: absent + register: network + check_mode: yes +- name: verify test absent a vpc network tier in check mode + assert: + that: + - network is changed + - network.acl_type == 'Account' + - network.acl == 'my_network_acl1' + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1 description' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test absent a vpc network tier + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + vpc: vpc_network_test + state: absent + register: network +- name: verify test absent a vpc network tier + assert: + that: + - network is changed + - network.acl_type == 'Account' + - network.acl == 'my_network_acl1' + - network.broadcast_domain_type == 'Vlan' + - network.cidr == '10.43.0.0/24' + - network.gateway == '10.43.0.1' + - network.display_text == 'vpc tier 1 description' + - network.network_offering == 'DefaultIsolatedNetworkOfferingForVpcNetworks' + - network.vpc == 'vpc_network_test' + - network.network_domain == 'cs2sandbox.simulator.example.com' + +- name: test absent a vpc network tier idempotence + cs_network: + name: vpc tier 1 + zone: "{{ cs_common_zone_adv }}" + vpc: vpc_network_test + state: absent + register: network +- name: verify test absent a vpc network tier idempotence + assert: + that: + - network is not changed + +- name: cleanup vpc + cs_vpc: + name: vpc_network_test + cidr: 10.43.0.0/16 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpc +- name: verify cleanup vpc + assert: + that: + - vpc is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml new file mode 100644 index 00000000..7104a7cb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl/tasks/main.yml @@ -0,0 +1,120 @@ +--- +- name: setup vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + vpc_offering: Redundant VPC offering + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup network acl absent + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl +- name: verify setup network acl absent + assert: + that: + - acl is successful + +- name: test fail missing param name and vpc for network acl + cs_network_acl: + ignore_errors: true + register: acl +- name: verify test fail missing param name and vpc for network acl + assert: + that: + - acl is failed + - "acl.msg.startswith('missing required arguments: ')" + +- name: test create network acl in check mode + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: acl + check_mode: true +- name: verify test create network acl in check mode + assert: + that: + - acl is successful + - acl is changed + +- name: test create network acl + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: acl +- name: verify test create network acl + assert: + that: + - acl is successful + - acl is changed + - acl.vpc == "{{ cs_resource_prefix }}_vpc" + - acl.name == "{{ cs_resource_prefix }}_acl" + +- name: test create network acl idempotence + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: acl +- name: verify test create network acl idempotence + assert: + that: + - acl is successful + - acl is not changed + - acl.vpc == "{{ cs_resource_prefix }}_vpc" + - acl.name == "{{ cs_resource_prefix }}_acl" + +- name: test remove network acl in check mode + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl + check_mode: true +- name: verify test remove network acl in check mode + assert: + that: + - acl is successful + - acl is changed + - acl.vpc == "{{ cs_resource_prefix }}_vpc" + - acl.name == "{{ cs_resource_prefix }}_acl" + +- name: test remove network acl + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl +- name: verify test remove network acl + assert: + that: + - acl is successful + - acl is changed + - acl.vpc == "{{ cs_resource_prefix }}_vpc" + - acl.name == "{{ cs_resource_prefix }}_acl" + +- name: test remove network acl idempotence + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl +- name: verify test remove network acl idempotence + assert: + that: + - acl is successful + - acl is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml new file mode 100644 index 00000000..06f5f5ae --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_acl_rule/tasks/main.yml @@ -0,0 +1,548 @@ +--- +- name: setup vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup network acl + cs_network_acl: + name: "{{ cs_resource_prefix }}_acl" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: acl +- name: verify setup network acl + assert: + that: + - acl is successful + +- name: setup network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl_rule +- name: verify setup network acl rule + assert: + that: + - acl_rule is successful + +- name: test fail missing params + cs_network_acl_rule: + ignore_errors: true + register: acl_rule +- name: verify test fail missing param + assert: + that: + - acl_rule is failed + - "acl_rule.msg.startswith('missing required arguments: ')" + +- name: test fail missing params for tcp + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: acl_rule +- name: verify test fail missing param for tcp + assert: + that: + - acl_rule is failed + - "acl_rule.msg == 'protocol is tcp but the following are missing: start_port, end_port'" + +- name: test fail missing params for icmp + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + cidr: 0.0.0.0/0 + protocol: icmp + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: acl_rule +- name: verify test fail missing param for icmp + assert: + that: + - acl_rule is failed + - "acl_rule.msg == 'protocol is icmp but the following are missing: icmp_type, icmp_code'" + +- name: test fail missing params for by number + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + cidr: 0.0.0.0/0 + protocol: by_number + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: acl_rule +- name: verify test fail missing param for by number + assert: + that: + - acl_rule is failed + - "acl_rule.msg == 'protocol is by_number but the following are missing: protocol_number'" + +- name: test create network acl rule in check mode + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + port: 80 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule + check_mode: true +- name: verify test create network acl rule in check mode + assert: + that: + - acl_rule is successful + - acl_rule is changed + +- name: test create network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + port: 80 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test create network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 80 + - acl_rule.end_port == 80 + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "ingress" + - acl_rule.rule_position == 1 + +- name: test create network acl rule idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: ingress + action_policy: allow + port: 80 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test create network acl idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 80 + - acl_rule.end_port == 80 + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "ingress" + - acl_rule.rule_position == 1 + +- name: test change network acl rule in check mode + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + port: 81 + cidrs: + - 1.2.3.0/24 + - 3.2.1.0/24 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule + check_mode: true +- name: verify test change network acl rule in check mode + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 80 + - acl_rule.end_port == 80 + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.cidrs == [ "0.0.0.0/0" ] + - acl_rule.traffic_type == "ingress" + - acl_rule.rule_position == 1 + +- name: test change network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + port: 81 + protocol: udp + cidrs: + - 1.2.3.0/24 + - 3.2.1.0/24 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test change network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24" + - acl_rule.cidrs == [ "1.2.3.0/24", "3.2.1.0/24" ] + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "udp" + - acl_rule.rule_position == 1 + +- name: test change network acl rule idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + port: 81 + protocol: udp + cidrs: + - 1.2.3.0/24 + - 3.2.1.0/24 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test change network acl idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24" + - acl_rule.cidrs == [ "1.2.3.0/24", "3.2.1.0/24" ] + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "udp" + - acl_rule.rule_position == 1 + +- name: test change network acl by protocol number in check mode + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + protocol: by_number + protocol_number: 8 + port: 81 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule + check_mode: true +- name: verify test change network acl by protocol number in check mode + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "1.2.3.0/24,3.2.1.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "udp" + - acl_rule.rule_position == 1 + +- name: test change network acl by protocol number + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + protocol: by_number + protocol_number: 8 + port: 81 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test change network acl by protocol number + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "by_number" + - acl_rule.protocol_number == 8 + - acl_rule.rule_position == 1 + +- name: test change network acl by protocol number idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: deny + protocol: by_number + protocol_number: 8 + port: 81 + cidr: 0.0.0.0/0 + zone: "{{ cs_common_zone_adv }}" + register: acl_rule +- name: verify test change network acl by protocol number idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "by_number" + - acl_rule.protocol_number == 8 + - acl_rule.rule_position == 1 + + +- name: test create 2nd network acl rule in check mode + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: allow + cidr: 10.23.12.0/24 + zone: "{{ cs_common_zone_adv }}" + protocol: all + register: acl_rule + check_mode: true +- name: verify test create 2nd network acl rule in check mode + assert: + that: + - acl_rule is successful + - acl_rule is changed + +- name: test create 2nd network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: allow + cidr: 10.23.12.0/24 + zone: "{{ cs_common_zone_adv }}" + protocol: all + register: acl_rule +- name: verify test create 2nd network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "10.23.12.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "all" + - acl_rule.rule_position == 2 + +- name: test create 2nd network acl rule idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: allow + cidr: 10.23.12.0/24 + zone: "{{ cs_common_zone_adv }}" + protocol: all + register: acl_rule +- name: verify test create 2nd network acl rule idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "10.23.12.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "all" + - acl_rule.rule_position == 2 + +- name: test update 2nd network acl rule to icmp + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: allow + cidr: 10.23.12.0/24 + zone: "{{ cs_common_zone_adv }}" + protocol: icmp + icmp_type: 0 + icmp_code: 8 + register: acl_rule +- name: verify test create 2nd network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "10.23.12.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "icmp" + - acl_rule.icmp_type == 0 + - acl_rule.icmp_code == 8 + - acl_rule.rule_position == 2 + +- name: test update 2nd network acl rule to icmp idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + traffic_type: egress + action_policy: allow + cidr: 10.23.12.0/24 + zone: "{{ cs_common_zone_adv }}" + protocol: icmp + icmp_type: 0 + icmp_code: 8 + register: acl_rule +- name: verify test create 2nd network acl rule idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "10.23.12.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "icmp" + - acl_rule.icmp_type == 0 + - acl_rule.icmp_code == 8 + - acl_rule.rule_position == 2 + +- name: test absent network acl rule in check mode + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl_rule + check_mode: true +- name: verify test absent network acl rule in check mode + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "egress" + - acl_rule.rule_position == 1 + +- name: test absent network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl_rule +- name: verify test absent network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.start_port == 81 + - acl_rule.end_port == 81 + - acl_rule.action_policy == "deny" + - acl_rule.cidr == "0.0.0.0/0" + - acl_rule.traffic_type == "egress" + - acl_rule.rule_position == 1 + +- name: test absent network acl rule idempotence + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 1 + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl_rule +- name: verify test absent network acl rule idempotence + assert: + that: + - acl_rule is successful + - acl_rule is not changed + +- name: test absent 2nd network acl rule + cs_network_acl_rule: + network_acl: "{{ cs_resource_prefix }}_acl" + rule_position: 2 + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: acl_rule +- name: verify test absent 2nd network acl rule + assert: + that: + - acl_rule is successful + - acl_rule is changed + - acl_rule.vpc == "{{ cs_resource_prefix }}_vpc" + - acl_rule.network_acl == "{{ cs_resource_prefix }}_acl" + - acl_rule.action_policy == "allow" + - acl_rule.cidr == "10.23.12.0/24" + - acl_rule.traffic_type == "egress" + - acl_rule.protocol == "icmp" + - acl_rule.icmp_type == 0 + - acl_rule.icmp_code == 8 + - acl_rule.rule_position == 2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml new file mode 100644 index 00000000..62d9d3e9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_network_offering/tasks/main.yml @@ -0,0 +1,434 @@ +--- +- name: setup + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: absent + register: netoffer +- name: verify setup + assert: + that: + - netoffer is successful + +- name: test fail if missing name + action: cs_network_offering + register: netoffer + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - netoffer is failed + - 'netoffer.msg == "missing required arguments: name"' + +- name: test fail if missing params + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + register: netoffer + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - netoffer is failed + - 'netoffer.msg == "missing required arguments: display_text, guest_ip_type, supported_services, service_providers"' + +- name: test create network offer in check mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + max_connections: 300 + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: netoffer + check_mode: yes +- name: verify results of network offer in check mode + assert: + that: + - netoffer is successful + - netoffer is changed + +- name: test create network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + max_connections: 300 + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: netoffer +- name: verify results of network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test create network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + max_connections: 300 + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: netoffer +- name: verify results of create network offer idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test enabling existing network offer in check_mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: enabled + register: netoffer + check_mode: yes +- name: verify results of enabling existing network offer in check_mode + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test enabling existing network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: enabled + register: netoffer +- name: verify results of enabling existing network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" + +- name: test enabling existing network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: enabled + register: netoffer +- name: verify results of enabling existing network idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" + +- name: test disabling network offer in check_mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer + check_mode: yes +- name: verify results of disabling network offer in check_mode + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" + +- name: test disabling network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer +- name: verify results of disabling network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test disabling network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer +- name: verify results of disabling network idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test rename network offer in check_mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description renamed" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer + check_mode: yes +- name: verify results of rename network offer in check_mode + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description" + +- name: test rename network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description renamed" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer +- name: verify results of rename network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description renamed" + +- name: test rename network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description renamed" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: netoffer +- name: verify results of rename network offer idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description renamed" + +- name: test update offer with minimal params in check_mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description update" + max_connections: 400 + register: netoffer + check_mode: yes +- name: verify results of update offer with minimal params in check_mode + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description renamed" + - netoffer.max_connections == 300 + +- name: test update offer with minimal params + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description update" + max_connections: 400 + register: netoffer +- name: verify results of update offer with minimal params + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description update" + - netoffer.max_connections == 400 + +- name: test update offer with minimal params idempotency + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description update" + max_connections: 400 + register: netoffer +- name: verify results of update offer with minimal params idempotency + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description update" + - netoffer.max_connections == 400 + +- name: test remove network offer in check_mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: absent + register: netoffer + check_mode: yes +- name: verify results of rename network offer in check_mode + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description update" + +- name: test remove network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: absent + register: netoffer +- name: verify results of rename network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Disabled" + - netoffer.display_text == "network offering description update" + +- name: test remove network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: absent + register: netoffer +- name: verify results of rename network offer idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + +- name: test create enabled network offer in check mode + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: netoffer + check_mode: yes +- name: verify results of create enabled network offer in check mode + assert: + that: + - netoffer is successful + - netoffer is changed + +- name: test create enabled network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: netoffer +- name: verify results of create enabled network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" + +- name: test create enabled network offer idempotence + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + display_text: "network offering description" + guest_ip_type: Isolated + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, Firewall, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: netoffer +- name: verify results of create enabled network offer idempotence + assert: + that: + - netoffer is successful + - netoffer is not changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" + +- name: remove network offer + cs_network_offering: + name: "{{ cs_resource_prefix }}_name" + state: absent + register: netoffer +- name: verify results of remove network offer + assert: + that: + - netoffer is successful + - netoffer is changed + - netoffer.name == "{{ cs_resource_prefix }}_name" + - netoffer.guest_ip_type == "Isolated" + - netoffer.state == "Enabled" + - netoffer.display_text == "network offering description" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml new file mode 100644 index 00000000..4b986a6b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_physical_network/tasks/main.yml @@ -0,0 +1,232 @@ +--- +# Create a new zone - the default one is enabled +- name: assure zone for tests + cs_zone: + name: cs-test-zone + state: present + dns1: 8.8.8.8 + network_type: Advanced + register: cszone + +- name: ensure the zone is disabled + cs_zone: + name: "{{ cszone.name }}" + state: disabled + register: cszone + +- name: ensure a network is absent + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: absent + +- name: setup a network in check_mode + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + broadcast_domain_range: ZONE + check_mode: yes + register: pn +- name: validate setup a network + assert: + that: + - pn is changed + - pn.zone == cszone.name + +- name: setup a network + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + broadcast_domain_range: ZONE + register: pn +- name: validate setup a network + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.state == 'Disabled' + +- name: setup a network idempotence + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + broadcast_domain_range: ZONE + register: pn +- name: validate setup a network idempotence + assert: + that: + - pn is not changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.state == 'Disabled' + +- name: set a tag on a network + cs_physical_network: + name: net01 + tag: overlay + zone: "{{ cszone.name }}" + ignore_errors: true + register: pn +- name: validate set a tag on a network + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.tags == 'overlay' + - pn.state == 'Disabled' + +- name: Remove tag on a network + cs_physical_network: + name: net01 + tag: "" + zone: "{{ cszone.name }}" + register: pn +- name: validate remove tag on a network + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.tags is undefined + - pn.state == 'Disabled' + +- name: ensure a network is enabled with specific nsps enabled in check mode + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + vlan: 100-200,300-400 + broadcast_domain_range: ZONE + state: enabled + nsps_enabled: + - virtualrouter + - internallbvm + - vpcvirtualrouter + check_mode: yes + register: pn +- name: validate ensure a network is enabled with specific nsps enabled in check mode + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.zone == cszone.name + - "'internallbvm' in pn.nsps_enabled" + - "'virtualrouter' in pn.nsps_enabled" + - "'vpcvirtualrouter' in pn.nsps_enabled" + +- name: ensure a network is enabled with specific nsps enabled + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + vlan: 100-200,300-400 + broadcast_domain_range: ZONE + state: enabled + nsps_enabled: + - virtualrouter + - internallbvm + - vpcvirtualrouter + register: pn +- name: validate ensure a network is enabled with specific nsps enabled + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.vlan == '100-200,300-400' + - pn.state == 'Enabled' + - "'internallbvm' in pn.nsps_enabled" + - "'virtualrouter' in pn.nsps_enabled" + - "'vpcvirtualrouter' in pn.nsps_enabled" + +- name: ensure a network is disabled + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: disabled + register: pn +- name: validate ensure a network is disabled + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.tags is undefined + - pn.state == 'Disabled' + +- name: ensure a network is enabled + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: enabled + register: pn +- name: validate ensure a network is enabled + assert: + that: + - pn is changed + - pn.name == 'net01' + - pn.broadcast_domain_range == 'ZONE' + - pn.isolation_method == 'VLAN' + - pn.zone == cszone.name + - pn.tags is undefined + - pn.state == 'Enabled' + +- name: ensure a network is not absent in check mode + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: absent + check_mode: yes + register: pn +- name: validate ensure a network is absent + assert: + that: + - pn is changed + - pn.zone == cszone.name + +- name: ensure a network is absent + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: absent + register: pn +- name: validate ensure a network is absent + assert: + that: + - pn is changed + - pn.zone == cszone.name + - pn.name == 'net01' + +- name: ensure a network is absent idempotence + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: absent + register: pn +- name: validate ensure a network is absent idempotence + assert: + that: + - pn is not changed + - pn.zone == cszone.name + +- name: cleanup zone + cs_zone: + name: "{{ cszone.name }}" + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases new file mode 100644 index 00000000..c89c86d7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml new file mode 100644 index 00000000..600bc22b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_pod/tasks/main.yml @@ -0,0 +1,301 @@ +--- +- name: setup zone is present + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone +- name: verify setup zone is present + assert: + that: + - zone is successful + +- name: setup pod is absent + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: pod +- name: verify setup pod is absent + assert: + that: + - pod is successful + +- name: test fail if missing name + cs_pod: + register: pod + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - pod is failed + - "pod.msg == 'missing required arguments: name'" + + +- name: test create pod in check mode + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + start_ip: 10.100.10.101 + gateway: 10.100.10.1 + netmask: 255.255.255.0 + register: pod_origin + check_mode: true +- name: verify test create pod in check mode + assert: + that: + - pod_origin is changed + - pod_origin.zone == "{{ cs_resource_prefix }}-zone" + +- name: test create pod + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + start_ip: 10.100.10.101 + gateway: 10.100.10.1 + netmask: 255.255.255.0 + register: pod_origin +- name: verify test create pod + assert: + that: + - pod_origin is changed + - pod_origin.allocation_state == "Enabled" + - pod_origin.start_ip == "10.100.10.101" + - pod_origin.end_ip == "10.100.10.254" + - pod_origin.gateway == "10.100.10.1" + - pod_origin.netmask == "255.255.255.0" + - pod_origin.zone == "{{ cs_resource_prefix }}-zone" + +- name: test create pod idempotence + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + start_ip: 10.100.10.101 + gateway: 10.100.10.1 + netmask: 255.255.255.0 + register: pod +- name: verify test create pod idempotence + assert: + that: + - pod is not changed + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.1" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test update pod in check mode + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + gateway: 10.100.10.2 + netmask: 255.255.255.0 + register: pod + check_mode: true +- name: verify test update pod in check mode + assert: + that: + - pod is changed + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.1" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test update pod + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + gateway: 10.100.10.2 + netmask: 255.255.255.0 + register: pod +- name: verify test update pod + assert: + that: + - pod is changed + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test update pod idempotence + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + gateway: 10.100.10.2 + netmask: 255.255.255.0 + register: pod +- name: verify test update pod idempotence + assert: + that: + - pod is not changed + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test disable pod in check mode + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: pod + check_mode: true +- name: verify test enable pod in check mode + assert: + that: + - pod is changed + - pod.allocation_state == "Enabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test disable pod + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: pod +- name: verify test enable pod + assert: + that: + - pod is changed + - pod.allocation_state == "Disabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test disable pod idempotence + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: disabled + register: pod +- name: verify test enable pod idempotence + assert: + that: + - pod is not changed + - pod.allocation_state == "Disabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test enable pod in check mode + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: pod + check_mode: true +- name: verify test disable pod in check mode + assert: + that: + - pod is changed + - pod.allocation_state == "Disabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test enable pod + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: pod +- name: verify test disable pod + assert: + that: + - pod is changed + - pod.allocation_state == "Enabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + + +- name: test enable pod idempotence + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: enabled + register: pod +- name: verify test enabled pod idempotence + assert: + that: + - pod is not changed + - pod.allocation_state == "Enabled" + - pod.id == pod_origin.id + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test absent pod in check mode + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: pod + check_mode: true +- name: verify test create pod in check mode + assert: + that: + - pod is changed + - pod.id == pod_origin.id + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test absent pod + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: pod +- name: verify test create pod + assert: + that: + - pod is changed + - pod.id == pod_origin.id + - pod.allocation_state == "Enabled" + - pod.start_ip == "10.100.10.101" + - pod.end_ip == "10.100.10.254" + - pod.gateway == "10.100.10.2" + - pod.netmask == "255.255.255.0" + - pod.zone == "{{ cs_resource_prefix }}-zone" + +- name: test absent pod idempotence + cs_pod: + name: "{{ cs_resource_prefix }}-pod" + zone: "{{ cs_resource_prefix }}-zone" + state: absent + register: pod +- name: verify test absent pod idempotence + assert: + that: + - pod is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml new file mode 100644 index 00000000..89842c55 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/defaults/main.yml @@ -0,0 +1,3 @@ +--- +cs_portforward_public_ip: "10.100.212.5" +cs_portforward_vm: "cs-{{ cs_resource_prefix }}-pf-vm" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml new file mode 100644 index 00000000..d1b6946e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_portforward/tasks/main.yml @@ -0,0 +1,255 @@ +--- +- name: network setup + cs_network: + name: ansible test + network_offering: DefaultIsolatedNetworkOfferingWithSourceNatService + network_domain: example.com + zone: "{{ cs_common_zone_adv }}" + register: net +- name: verify network setup + assert: + that: + - net is successful + +- name: instance setup + cs_instance: + name: "{{ cs_portforward_vm }}" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "ansible test" + register: instance +- name: verify instance setup + assert: + that: + - instance is successful + +- name: public ip address setup + cs_ip_address: + network: ansible test + zone: "{{ cs_common_zone_adv }}" + register: ip_address +- name: verify public ip address setup + assert: + that: + - ip_address is successful + +- name: set ip address as fact + set_fact: + cs_portforward_public_ip: "{{ ip_address.ip_address }}" + +- name: clear existing port forwarding + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + private_port: 8080 + state: absent + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify clear existing port forwarding + assert: + that: + - pf is successful + +- name: test fail if missing params + action: cs_portforward + register: pf + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - pf is failed + - 'pf.msg.startswith("missing required arguments: ")' + +- name: test present port forwarding in check mode + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8080 + zone: "{{ cs_common_zone_adv }}" + register: pf + check_mode: true +- name: verify results of present port forwarding in check mode + assert: + that: + - pf is successful + - pf is changed + +- name: test present port forwarding + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8080 + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of present port forwarding + assert: + that: + - pf is successful + - pf is changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8080 + - pf.private_end_port == 8080 + +- name: test present port forwarding idempotence + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8080 + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of present port forwarding idempotence + assert: + that: + - pf is successful + - pf is not changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8080 + - pf.private_end_port == 8080 + +- name: test change port forwarding in check mode + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8888 + zone: "{{ cs_common_zone_adv }}" + register: pf + check_mode: true +- name: verify results of change port forwarding in check mode + assert: + that: + - pf is successful + - pf is changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8080 + - pf.private_end_port == 8080 + +- name: test change port forwarding + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8888 + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of change port forwarding + assert: + that: + - pf is successful + - pf is changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8888 + - pf.private_end_port == 8888 + +- name: test change port forwarding idempotence + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + vm: "{{ cs_portforward_vm }}" + private_port: 8888 + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of change port forwarding idempotence + assert: + that: + - pf is successful + - pf is not changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8888 + - pf.private_end_port == 8888 + +- name: test absent port forwarding in check mode + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + private_port: 8888 + state: absent + zone: "{{ cs_common_zone_adv }}" + register: pf + check_mode: true +- name: verify results of absent port forwarding in check mode + assert: + that: + - pf is successful + - pf is changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8888 + - pf.private_end_port == 8888 + +- name: test absent port forwarding + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + private_port: 8888 + state: absent + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of absent port forwarding + assert: + that: + - pf is successful + - pf is changed + - pf.vm_name == "{{ cs_portforward_vm }}" + - pf.ip_address == "{{ cs_portforward_public_ip }}" + - pf.public_port == 80 + - pf.public_end_port == 80 + - pf.private_port == 8888 + - pf.private_end_port == 8888 + +- name: test absent port forwarding idempotence + cs_portforward: + ip_address: "{{ cs_portforward_public_ip }}" + public_port: 80 + private_port: 8888 + state: absent + zone: "{{ cs_common_zone_adv }}" + register: pf +- name: verify results of absent port forwarding idempotence + assert: + that: + - pf is successful + - pf is not changed + +- name: instance cleanup + cs_instance: + name: "{{ cs_portforward_vm }}" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify instance cleanup + assert: + that: + - instance is successful + +- name: network cleanup + cs_network: + name: ansible test + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify network cleanup + assert: + that: + - net is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml new file mode 100644 index 00000000..7ece89d4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_project/tasks/main.yml @@ -0,0 +1,149 @@ +--- +- name: ensure project does not exist + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: absent + register: prj +- name: verify project did not exist + assert: + that: + - prj is successful + +- name: test create project in check mode + cs_project: + name: "{{ cs_resource_prefix }}-prj" + register: prj + check_mode: true +- name: verify test create project in check mode + assert: + that: + - prj is changed + +- name: test create project + cs_project: + name: "{{ cs_resource_prefix }}-prj" + register: prj +- name: verify test create project + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + +- name: test create project idempotence + cs_project: + name: "{{ cs_resource_prefix }}-prj" + register: prj +- name: verify test create project idempotence + assert: + that: + - prj is not changed + - prj.name == "{{ cs_resource_prefix }}-prj" + +- name: test suspend project in check mode + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: suspended + register: prj + check_mode: true +- name: verify test suspend project in check mode + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state != "Suspended" + +- name: test suspend project + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: suspended + register: prj +- name: verify test suspend project + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Suspended" + +- name: test suspend project idempotence + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: suspended + register: prj +- name: verify test suspend project idempotence + assert: + that: + - prj is not changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Suspended" + +- name: test activate project in check mode + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: active + register: prj + check_mode: true +- name: verify test activate project in check mode + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state != "Active" + +- name: test activate project + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: active + register: prj +- name: verify test activate project + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Active" + +- name: test activate project idempotence + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: active + register: prj +- name: verify test activate project idempotence + assert: + that: + - prj is not changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Active" + +- name: test delete project in check mode + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: absent + register: prj + check_mode: true +- name: verify test delete project in check mode + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Active" + +- name: test delete project + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: absent + register: prj +- name: verify test delete project + assert: + that: + - prj is changed + - prj.name == "{{ cs_resource_prefix }}-prj" + - prj.state == "Active" + +- name: test delete project idempotence + cs_project: + name: "{{ cs_resource_prefix }}-prj" + state: absent + register: prj +- name: verify test delete project idempotence + assert: + that: + - prj is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml new file mode 100644 index 00000000..d7283083 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_region/tasks/main.yml @@ -0,0 +1,154 @@ +--- +- name: setup + cs_region: + id: 2 + state: absent + register: region +- name: verify setup + assert: + that: + - region is successful + +- name: test fail if missing params + cs_region: + register: region + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - region is failed + - "region.msg.startswith('missing required arguments: ')" + +- name: test create region in check mode + cs_region: + id: 2 + name: geneva + endpoint: https://cloud.gva.example.com + register: region + check_mode: true +- name: verify test create region in check mode + assert: + that: + - region is changed + +- name: test create region in check mode + cs_region: + id: 2 + name: geneva + endpoint: https://cloud.gva.example.com + register: region +- name: verify test create region in check mode + assert: + that: + - region is changed + - region.name == 'geneva' + - region.id == 2 + - region.endpoint == 'https://cloud.gva.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test create region idempotence + cs_region: + id: 2 + name: geneva + endpoint: https://cloud.gva.example.com + register: region +- name: verify test create region idempotence + assert: + that: + - region is not changed + - region.name == 'geneva' + - region.id == 2 + - region.endpoint == 'https://cloud.gva.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test update region in check mode + cs_region: + id: 2 + name: zuerich + endpoint: https://cloud.zrh.example.com + register: region + check_mode: true +- name: verify test update region in check mode + assert: + that: + - region is changed + - region.name == 'geneva' + - region.id == 2 + - region.endpoint == 'https://cloud.gva.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test update region + cs_region: + id: 2 + name: zuerich + endpoint: https://cloud.zrh.example.com + register: region +- name: verify test update region + assert: + that: + - region is changed + - region.name == 'zuerich' + - region.id == 2 + - region.endpoint == 'https://cloud.zrh.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test update region idempotence + cs_region: + id: 2 + name: zuerich + endpoint: https://cloud.zrh.example.com + register: region +- name: verify test update region idempotence + assert: + that: + - region is not changed + - region.name == 'zuerich' + - region.id == 2 + - region.endpoint == 'https://cloud.zrh.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test remove region in check mdoe + cs_region: + id: 2 + state: absent + register: region + check_mode: true +- name: verify test remove region in check mode + assert: + that: + - region is changed + - region.name == 'zuerich' + - region.id == 2 + - region.endpoint == 'https://cloud.zrh.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test remove region + cs_region: + id: 2 + state: absent + register: region +- name: verify test remove region + assert: + that: + - region is changed + - region.name == 'zuerich' + - region.id == 2 + - region.endpoint == 'https://cloud.zrh.example.com' + - region.gslb_service_enabled == true + - region.portable_ip_service_enabled == false + +- name: test remove region idempotence + cs_region: + id: 2 + state: absent + register: region +- name: verify test remove region idempotence + assert: + that: + - region is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml new file mode 100644 index 00000000..baa736b4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/cpu.yml @@ -0,0 +1,122 @@ +--- +- name: setup cpu limits account + cs_resourcelimit: + type: cpu + limit: 20 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup cpu limits account + assert: + that: + - rl is successful + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 20 + - rl.resource_type == "cpu" + +- name: setup cpu limits for domain + cs_resourcelimit: + type: cpu + limit: -1 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup cpu limits for domain + assert: + that: + - rl is successful + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == -1 + - rl.resource_type == "cpu" + +- name: set cpu limits for domain in check mode + cs_resourcelimit: + type: cpu + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl + check_mode: true +- name: verify set cpu limits for domain in check mode + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == -1 + - rl.resource_type == "cpu" + +- name: set cpu limits for domain + cs_resourcelimit: + type: cpu + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set cpu limits for domain + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 12 + - rl.resource_type == "cpu" + +- name: set cpu limits for domain idempotence + cs_resourcelimit: + type: cpu + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set cpu limits for domain + assert: + that: + - rl is not changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 12 + - rl.resource_type == "cpu" + +- name: set cpu limits for account in check mode + cs_resourcelimit: + type: cpu + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl + check_mode: true +- name: verify set cpu limits for account in check mode + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 20 + - rl.resource_type == "cpu" + +- name: set cpu limits for account + cs_resourcelimit: + type: cpu + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set cpu limits for account + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 10 + - rl.resource_type == "cpu" + +- name: set cpu limits for account idempotence + cs_resourcelimit: + type: cpu + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set cpu limits for account idempotence + assert: + that: + - rl is not changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 10 + - rl.resource_type == "cpu" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml new file mode 100644 index 00000000..11a1fe07 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/instance.yml @@ -0,0 +1,108 @@ +--- +- name: setup instance limits account + cs_resourcelimit: + type: instance + limit: 20 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup instance limits account + assert: + that: + - rl is successful + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 20 + - rl.resource_type == "instance" + +- name: set instance limits for domain in check mode + cs_resourcelimit: + type: instance + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl + check_mode: true +- name: verify set instance limits for domain in check mode + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 20 + - rl.resource_type == "instance" + +- name: set instance limits for domain + cs_resourcelimit: + type: instance + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set instance limits for domain + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 12 + - rl.resource_type == "instance" + +- name: set instance limits for domain idempotence + cs_resourcelimit: + type: instance + limit: 12 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set instance limits for domain + assert: + that: + - rl is not changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 12 + - rl.resource_type == "instance" + +- name: set instance limits for account in check mode + cs_resourcelimit: + type: instance + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl + check_mode: true +- name: verify set instance limits for account in check mode + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit != 10 + - rl.resource_type == "instance" + +- name: set instance limits for account + cs_resourcelimit: + type: instance + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set instance limits for account + assert: + that: + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 10 + - rl.resource_type == "instance" + +- name: set instance limits for account idempotence + cs_resourcelimit: + type: instance + limit: 10 + account: "{{ cs_resource_prefix }}_user" + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify set instance limits for account idempotence + assert: + that: + - rl is not changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.account == "{{ cs_resource_prefix }}_user" + - rl.limit == 10 + - rl.resource_type == "instance" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml new file mode 100644 index 00000000..fcf9279f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_resourcelimit/tasks/main.yml @@ -0,0 +1,104 @@ +--- +- name: setup domain + cs_domain: path={{ cs_resource_prefix }}-domain + register: dom +- name: verify setup domain + assert: + that: + - dom is successful + +- name: setup account + cs_account: + name: "{{ cs_resource_prefix }}_user" + username: "{{ cs_resource_prefix }}_username" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "{{ cs_resource_prefix }}-local" + domain: "{{ cs_resource_prefix }}-domain" + register: acc +- name: verify setup account + assert: + that: + - acc is successful + +- name: test failed unkonwn type + cs_resourcelimit: + type: unkonwn + limit: 20 + domain: "{{ cs_resource_prefix }}-domain" + register: rl + ignore_errors: yes +- name: verify test failed unkonwn type + assert: + that: + - rl is failed + +- name: test failed missing type + cs_resourcelimit: + register: rl + ignore_errors: yes +- name: verify test failed missing type + assert: + that: + - rl is failed + +- name: setup resource limits domain + cs_resourcelimit: + type: instance + limit: 10 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup resource limits domain + assert: + that: + - rl is successful + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 10 + +- name: set resource limits domain to 20 in check mode + cs_resourcelimit: + type: instance + limit: 20 + domain: "{{ cs_resource_prefix }}-domain" + register: rl + check_mode: true +- name: verify setup resource limits domain to 20 in check mode + assert: + that: + - rl is successful + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 10 + +- name: set resource limits domain to 20 + cs_resourcelimit: + type: instance + limit: 20 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup resource limits domain to 20 + assert: + that: + - rl is successful + - rl is changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 20 + +- name: set resource limits domain to 20 idempotence + cs_resourcelimit: + type: instance + limit: 20 + domain: "{{ cs_resource_prefix }}-domain" + register: rl +- name: verify setup resource limits domain to 20 idempotence + assert: + that: + - rl is successful + - rl is not changed + - rl.domain == "{{ cs_resource_prefix }}-domain" + - rl.limit == 20 + +- include: instance.yml +- include: cpu.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml new file mode 100644 index 00000000..11c1653d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role/tasks/main.yml @@ -0,0 +1,130 @@ +--- +- name: setup + cs_role: + name: "{{ cs_resource_prefix }}-role" + state: absent + register: role +- name: verify setup + assert: + that: + - role is successful + +- name: test fail if missing params + cs_role: + register: role + ignore_errors: true +- name: verifytest fail if missing params + assert: + that: + - role is failed + - "role.msg.startswith('missing required arguments: ')" + +- name: test create role in check mode + cs_role: + name: "{{ cs_resource_prefix }}-role" + role_type: DomainAdmin + register: role + check_mode: true +- name: verify test create role in check mode + assert: + that: + - role is changed + +- name: test create role + cs_role: + name: "{{ cs_resource_prefix }}-role" + role_type: DomainAdmin + register: role +- name: verify test create role + assert: + that: + - role is changed + - role.name == '{{ cs_resource_prefix }}-role' + - role.role_type == 'DomainAdmin' + +- name: test create role idempotence + cs_role: + name: "{{ cs_resource_prefix }}-role" + role_type: DomainAdmin + register: role +- name: verify test create role idempotence + assert: + that: + - role is not changed + - role.name == '{{ cs_resource_prefix }}-role' + - role.role_type == 'DomainAdmin' + +- name: test update role in check mode + cs_role: + name: "{{ cs_resource_prefix }}-role" + description: "{{ cs_resource_prefix }}-role-description" + role_type: DomainAdmin + register: role + check_mode: true +- name: verify test update role in check mode + assert: + that: + - role is changed + - role.name == '{{ cs_resource_prefix }}-role' + - "role.description is not defined" + - role.role_type == 'DomainAdmin' + +- name: test update role + cs_role: + name: "{{ cs_resource_prefix }}-role" + description: "{{ cs_resource_prefix }}-role-description" + role_type: DomainAdmin + register: role +- name: verify test update role + assert: + that: + - role is changed + - role.name == '{{ cs_resource_prefix }}-role' + - role.description == '{{ cs_resource_prefix }}-role-description' + - role.role_type == 'DomainAdmin' + +- name: test update role idempotence + cs_role: + name: "{{ cs_resource_prefix }}-role" + description: "{{ cs_resource_prefix }}-role-description" + register: role +- name: verify test update role idempotence + assert: + that: + - role is not changed + - role.name == '{{ cs_resource_prefix }}-role' + - role.description == '{{ cs_resource_prefix }}-role-description' + - role.role_type == 'DomainAdmin' + +- name: test remove role in check mdoe + cs_role: + name: "{{ cs_resource_prefix }}-role" + state: absent + register: role + check_mode: true +- name: verify test remove role in check mode + assert: + that: + - role is changed + - role.name == '{{ cs_resource_prefix }}-role' + - role.role_type == 'DomainAdmin' + +- name: test remove role + cs_role: + name: "{{ cs_resource_prefix }}-role" + state: absent + register: role +- name: verify test remove role + assert: + that: + - role is changed + +- name: test remove role idempotence + cs_role: + name: "{{ cs_resource_prefix }}-role" + state: absent + register: role +- name: verify test remove role idempotence + assert: + that: + - role is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml new file mode 100644 index 00000000..95e2df84 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_role_permission/tasks/main.yml @@ -0,0 +1,303 @@ +- name: pre-setup + cs_role: + name: "testRole" + register: testRole +- name: verify pre-setup + assert: + that: + - testRole is successful + +- name: setup + cs_role_permission: + name: "fakeRolePerm" + role: "{{ testRole.id }}" + state: absent + register: roleperm +- name: verify setup + assert: + that: + - roleperm is successful + +- name: setup2 + cs_role_permission: + name: "fakeRolePerm2" + role: "{{ testRole.id }}" + state: absent + register: roleperm2 +- name: verify setup2 + assert: + that: + - roleperm2 is successful + +- name: test fail if missing name + cs_role_permission: + role: "{{ testRole.id }}" + register: roleperm + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - roleperm is failed + - 'roleperm.msg == "missing required arguments: name"' + +- name: test fail if missing role + cs_role_permission: + name: "fakeRolePerm" + register: roleperm + ignore_errors: true +- name: verify results of fail if missing role + assert: + that: + - roleperm is failed + - 'roleperm.msg == "missing required arguments: role"' + +- name: test fail if role does not exist + cs_role_permission: + name: "fakeRolePerm" + role: "testtest" + register: roleperm + ignore_errors: true +- name: verify results of fail if role does not exist + assert: + that: + - roleperm is failed + - roleperm.msg == "Role 'testtest' not found" + +- name: test fail if state is incorrcect + cs_role_permission: + state: badstate + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: allow + register: roleperm + ignore_errors: true +- name: verify results of fail if state is incorrcect + assert: + that: + - roleperm is failed + - 'roleperm.msg == "value of state must be one of: present, absent, got: badstate"' + +- name: test create role permission in check mode + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: allow + description: "fakeRolePerm description" + register: roleperm + check_mode: yes +- name: verify results of role permission in check mode + assert: + that: + - roleperm is successful + - roleperm is changed + +- name: test create role permission + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: allow + description: "fakeRolePerm description" + register: roleperm +- name: verify results of role permission + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + - roleperm.permission == "allow" + - roleperm.description == "fakeRolePerm description" + +- name: test create role permission idempotency + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: allow + description: "fakeRolePerm description" + register: roleperm +- name: verify results of role permission idempotency + assert: + that: + - roleperm is successful + - roleperm is not changed + - roleperm.name == "fakeRolePerm" + - roleperm.permission == "allow" + - roleperm.description == "fakeRolePerm description" + +- name: test update role permission in check_mode + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: deny + description: "fakeRolePerm description" + register: roleperm + check_mode: yes +- name: verify results of update role permission in check mode + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + - roleperm.permission == "allow" + - roleperm.description == "fakeRolePerm description" + +- name: test update role permission + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: deny + description: "fakeRolePerm description" + register: roleperm +- name: verify results of update role permission + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + - roleperm.permission == "deny" + - roleperm.description == "fakeRolePerm description" + +- name: test update role permission idempotency + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: deny + description: "fakeRolePerm description" + register: roleperm +- name: verify results of update role permission idempotency + assert: + that: + - roleperm is successful + - roleperm is not changed + - roleperm.name == "fakeRolePerm" + - roleperm.permission == "deny" + - roleperm.description == "fakeRolePerm description" + +- name: test create a second role permission + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm2" + permission: allow + register: roleperm2 +- name: verify results of create a second role permission + assert: + that: + - roleperm2 is successful + - roleperm2 is changed + - roleperm2.name == "fakeRolePerm2" + +- name: test update rules order in check_mode + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + parent: "{{ roleperm2.id }}" + register: roleperm + check_mode: yes +- name: verify results of update rule order check mode + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + +- name: test update rules order + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + parent: "{{ roleperm2.id }}" + register: roleperm +- name: verify results of update rule order + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + +- name: test update rules order to the top of the list + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + parent: 0 + register: roleperm +- name: verify results of update rule order to the top of the list + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + +- name: test update rules order with parent NAME + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + parent: "{{ roleperm2.name }}" + register: roleperm +- name: verify results of update rule order with parent NAME + assert: + that: + - roleperm is successful + - roleperm is changed + - roleperm.name == "fakeRolePerm" + +- name: test fail if permission AND parent args are present + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + permission: allow + parent: 0 + register: roleperm + ignore_errors: true +- name: verify results of fail if permission AND parent args are present + assert: + that: + - roleperm is failed + - 'roleperm.msg == "parameters are mutually exclusive: permission|parent"' + +- name: test fail if parent does not exist + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + parent: "badParent" + register: roleperm + ignore_errors: true +- name: verify results of fail if parent does not exist + assert: + that: + - roleperm is failed + - roleperm.msg == "Parent rule 'badParent' not found" + +- name: test remove role permission in check_mode + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + state: absent + register: roleperm + check_mode: yes +- name: verify results of rename role permission in check_mode + assert: + that: + - roleperm is successful + - roleperm is changed + +- name: test remove role permission + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm" + state: absent + register: roleperm +- name: verify results of remove role permission + assert: + that: + - roleperm is successful + - roleperm is changed + +- name: remove second role permission + cs_role_permission: + role: "{{ testRole.id }}" + name: "fakeRolePerm2" + state: absent + register: roleperm +- name: verify results of remove second role permission + assert: + that: + - roleperm is successful + - roleperm is changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml new file mode 100644 index 00000000..9adaa4de --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_router/tasks/main.yml @@ -0,0 +1,183 @@ +--- +- name: setup network + cs_network: + name: "net_router" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + network_domain: example.com + vlan: 1234 + start_ip: 10.100.12.11 + end_ip: 10.100.12.250 + gateway: 10.100.12.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network + assert: + that: + - net is successful + - net.name == "net_router" + +- name: setup instance + cs_instance: + name: "instance-vm" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "net_router" + state: started + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + - instance.name == "instance-vm" + - instance.state == "Running" + +- name: setup instance starts a router + cs_instance: + name: "instance-vm" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "net_router" + state: started + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + - instance.name == "instance-vm" + - instance.state == "Running" + +- name: setup find the routers name + shell: cs listRouters listall=true networkid="{{ net.id }}" zone="{{ cs_common_zone_adv }}" + args: + chdir: "{{ playbook_dir }}" + register: router + +- debug: + var: router.stdout + +- set_fact: + router_json: "{{ router.stdout | from_json }}" + +- set_fact: + router_name: "{{ router_json.router[0].name }}" + +- name: test router started + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: started + register: router +- name: verify test router started + assert: + that: + - router is successful + +- name: test stop router in check mode + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: stopped + check_mode: true + register: router +- name: verify test stop router in check mode + assert: + that: + - router is changed + - router.state == "Running" + - router.service_offering == "System Offering For Software Router" + +- name: test stop router + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: stopped + register: router +- name: verify test stop router + assert: + that: + - router is changed + - router.state == "Stopped" + - router.service_offering == "System Offering For Software Router" + +- name: test stop router idempotence + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: stopped + register: router +- name: verify test stop router idempotence + assert: + that: + - router is not changed + - router.state == "Stopped" + - router.service_offering == "System Offering For Software Router" + +- name: test start router in check mode + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: started + register: router + check_mode: true +- name: verify test start router in check mode + assert: + that: + - router is changed + - router.state == "Stopped" + - router.service_offering == "System Offering For Software Router" + +- name: test start router + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: started + register: router +- name: verify test start router + assert: + that: + - router is changed + - router.state == "Running" + - router.service_offering == "System Offering For Software Router" + +- name: test start router idempotence + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: started + register: router +- name: verify test start router idempotence + assert: + that: + - router is not changed + - router.state == "Running" + - router.service_offering == "System Offering For Software Router" + +- name: test restart router in check mode + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: restarted + register: router + check_mode: true +- name: verify test restart router in check mode + assert: + that: + - router is changed + - router.state == "Running" + - router.service_offering == "System Offering For Software Router" + +- name: test restart router + cs_router: + name: "{{ router_name }}" + zone: "{{ cs_common_zone_adv }}" + state: restarted + register: router +- name: verify test restart router + assert: + that: + - router is changed + - router.state == "Running" + - router.service_offering == "System Offering For Software Router" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml new file mode 100644 index 00000000..1d32d280 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup/tasks/main.yml @@ -0,0 +1,79 @@ +--- +- name: setup + cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent + register: sg +- name: verify setup + assert: + that: + - sg is successful + +- name: test fail if missing name + action: cs_securitygroup + register: sg + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - sg is failed + - "sg.msg == 'missing required arguments: name'" + +- name: test present security group in check mode + cs_securitygroup: name={{ cs_resource_prefix }}_sg + register: sg + check_mode: true +- name: verify results of create security group in check mode + assert: + that: + - sg is successful + - sg is changed + +- name: test present security group + cs_securitygroup: name={{ cs_resource_prefix }}_sg + register: sg +- name: verify results of create security group + assert: + that: + - sg is successful + - sg is changed + - sg.name == "{{ cs_resource_prefix }}_sg" + +- name: test present security group is idempotence + cs_securitygroup: name={{ cs_resource_prefix }}_sg + register: sg +- name: verify results present security group is idempotence + assert: + that: + - sg is successful + - sg is not changed + - sg.name == "{{ cs_resource_prefix }}_sg" + +- name: test absent security group in check mode + cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent + register: sg + check_mode: true +- name: verify results of absent security group in check mode + assert: + that: + - sg is successful + - sg is changed + - sg.name == "{{ cs_resource_prefix }}_sg" + +- name: test absent security group + cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent + register: sg +- name: verify results of absent security group + assert: + that: + - sg is successful + - sg is changed + - sg.name == "{{ cs_resource_prefix }}_sg" + +- name: test absent security group is idempotence + cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent + register: sg +- name: verify results of absent security group is idempotence + assert: + that: + - sg is successful + - sg is not changed + - sg.name is undefined diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml new file mode 100644 index 00000000..8f1378e6 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/absent.yml @@ -0,0 +1,171 @@ +--- +- name: test remove http range rule in check mode + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + state: absent + register: sg_rule + check_mode: true +- name: verify create http range rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'tcp' + - sg_rule.start_port == 8000 + - sg_rule.end_port == 8888 + - sg_rule.cidr == '1.2.3.4/32' + +- name: test remove http range rule + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + state: absent + register: sg_rule +- name: verify create http range rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'tcp' + - sg_rule.start_port == 8000 + - sg_rule.end_port == 8888 + - sg_rule.cidr == '1.2.3.4/32' + +- name: test remove http range rule idempotence + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + state: absent + register: sg_rule +- name: verify create http range rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed + +- name: test remove single port udp rule in check mode + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + state: absent + register: sg_rule + check_mode: true +- name: verify remove single port udp rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'egress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'udp' + - sg_rule.start_port == 5353 + - sg_rule.end_port == 5353 + - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg' + +- name: test remove single port udp rule + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + state: absent + register: sg_rule +- name: verify remove single port udp rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'egress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'udp' + - sg_rule.start_port == 5353 + - sg_rule.end_port == 5353 + - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg' + +- name: test remove single port udp rule idempotence + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + state: absent + register: sg_rule +- name: verify remove single port udp rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed + +- name: test remove icmp rule in check mode + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + state: absent + register: sg_rule + check_mode: true +- name: verify icmp rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.cidr == '0.0.0.0/0' + - sg_rule.protocol == 'icmp' + - sg_rule.icmp_code == -1 + - sg_rule.icmp_type == -1 + +- name: test remove icmp rule + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + state: absent + register: sg_rule +- name: verify icmp rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.cidr == '0.0.0.0/0' + - sg_rule.protocol == 'icmp' + - sg_rule.icmp_code == -1 + - sg_rule.icmp_type == -1 + +- name: test remove icmp rule idempotence + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + state: absent + register: sg_rule +- name: verify icmp rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml new file mode 100644 index 00000000..0fce5328 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/cleanup.yml @@ -0,0 +1,7 @@ +- name: cleanup custom security group + cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent + register: sg +- name: verify setup + assert: + that: + - sg is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml new file mode 100644 index 00000000..e76745cb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/main.yml @@ -0,0 +1,4 @@ +- include: setup.yml +- include: present.yml +- include: absent.yml +- include: cleanup.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml new file mode 100644 index 00000000..a2a4e03c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/present.yml @@ -0,0 +1,163 @@ +--- +- name: test create http range rule in check mode + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + register: sg_rule + check_mode: true +- name: verify create http range rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + +- name: test create http range rule + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + register: sg_rule +- name: verify create http range rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'tcp' + - sg_rule.start_port == 8000 + - sg_rule.end_port == 8888 + - sg_rule.cidr == '1.2.3.4/32' + +- name: test create http range rule idempotence + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + register: sg_rule +- name: verify create http range rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'tcp' + - sg_rule.start_port == 8000 + - sg_rule.end_port == 8888 + - sg_rule.cidr == '1.2.3.4/32' + +- name: test create single port udp rule in check mode + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + register: sg_rule + check_mode: true +- name: verify create single port udp rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + +- name: test create single port udp rule + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + register: sg_rule +- name: verify create single port udp rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'egress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'udp' + - sg_rule.start_port == 5353 + - sg_rule.end_port == 5353 + - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg' + + +- name: test single port udp rule idempotence + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}_sg' + register: sg_rule +- name: verify single port udp rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed + - sg_rule.type == 'egress' + - sg_rule.security_group == 'default' + - sg_rule.protocol == 'udp' + - sg_rule.start_port == 5353 + - sg_rule.end_port == 5353 + - sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg' + +- name: test icmp rule in check mode + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + register: sg_rule + check_mode: true +- name: verify icmp rule in check mode + assert: + that: + - sg_rule is successful + - sg_rule is changed + +- name: test icmp rule + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + register: sg_rule +- name: verify icmp rule + assert: + that: + - sg_rule is successful + - sg_rule is changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.cidr == '0.0.0.0/0' + - sg_rule.protocol == 'icmp' + - sg_rule.icmp_code == -1 + - sg_rule.icmp_type == -1 + +- name: test icmp rule idempotence + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + register: sg_rule +- name: verify icmp rule idempotence + assert: + that: + - sg_rule is successful + - sg_rule is not changed + - sg_rule.type == 'ingress' + - sg_rule.security_group == 'default' + - sg_rule.cidr == '0.0.0.0/0' + - sg_rule.protocol == 'icmp' + - sg_rule.icmp_code == -1 + - sg_rule.icmp_type == -1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml new file mode 100644 index 00000000..85625205 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_securitygroup_rule/tasks/setup.yml @@ -0,0 +1,56 @@ +- name: setup custom security group + cs_securitygroup: name={{ cs_resource_prefix }}_sg + register: sg +- name: verify setup + assert: + that: + - sg is successful + +- name: setup default security group + cs_securitygroup: name=default + register: sg +- name: verify setup + assert: + that: + - sg is successful + +- name: setup remove icmp rule + cs_securitygroup_rule: + security_group: default + protocol: icmp + type: ingress + icmp_type: -1 + icmp_code: -1 + state: absent + register: sg_rule +- name: verify remove icmp rule + assert: + that: + - sg_rule is successful + +- name: setup remove http range rule + cs_securitygroup_rule: + security_group: default + start_port: 8000 + end_port: 8888 + cidr: 1.2.3.4/32 + state: absent + register: sg_rule +- name: verify remove http range rule + assert: + that: + - sg_rule is successful + +- name: setup remove single port udp rule + cs_securitygroup_rule: + security_group: default + port: 5353 + protocol: udp + type: egress + user_security_group: '{{ cs_resource_prefix }}-user-sg' + state: absent + register: sg_rule +- name: verify remove single port udp rule + assert: + that: + - sg_rule is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml new file mode 100644 index 00000000..f7aee3c8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/guest_vm_service_offering.yml @@ -0,0 +1,223 @@ +--- +- name: setup service offering + cs_service_offering: + name: Micro + state: absent + register: so +- name: verify setup service offering + assert: + that: + - so is successful + +- name: create service offering in check mode + cs_service_offering: + name: Micro + display_text: Micro 512mb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 512 + host_tags: eco + storage_tags: + - eco + - backup + storage_type: local + register: so + check_mode: true +- name: verify create service offering in check mode + assert: + that: + - so is changed + +- name: create service offering + cs_service_offering: + name: Micro + display_text: Micro 512mb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 512 + host_tags: eco + storage_tags: + - eco + - backup + storage_type: local + register: so +- name: verify create service offering + assert: + that: + - so is changed + - so.name == "Micro" + - so.display_text == "Micro 512mb 1cpu" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: create service offering idempotence + cs_service_offering: + name: Micro + display_text: Micro 512mb 1cpu + cpu_number: 1 + cpu_speed: 2198 + memory: 512 + host_tags: eco + storage_tags: + - eco + - backup + storage_type: local + register: so +- name: verify create service offering idempotence + assert: + that: + - so is not changed + - so.name == "Micro" + - so.display_text == "Micro 512mb 1cpu" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: update service offering in check mode + cs_service_offering: + name: Micro + display_text: Micro RAM 512MB 1vCPU + register: so + check_mode: true +- name: verify create update offering in check mode + assert: + that: + - so is changed + - so.name == "Micro" + - so.display_text == "Micro 512mb 1cpu" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: update service offering + cs_service_offering: + name: Micro + display_text: Micro RAM 512MB 1vCPU + register: so +- name: verify update service offerin + assert: + that: + - so is changed + - so.name == "Micro" + - so.display_text == "Micro RAM 512MB 1vCPU" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: update service offering idempotence + cs_service_offering: + name: Micro + display_text: Micro RAM 512MB 1vCPU + register: so +- name: verify update service offering idempotence + assert: + that: + - so is not changed + - so.name == "Micro" + - so.display_text == "Micro RAM 512MB 1vCPU" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: remove service offering in check mode + cs_service_offering: + name: Micro + state: absent + check_mode: true + register: so +- name: verify remove service offering in check mode + assert: + that: + - so is changed + - so.name == "Micro" + - so.display_text == "Micro RAM 512MB 1vCPU" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: remove service offering + cs_service_offering: + name: Micro + state: absent + register: so +- name: verify remove service offering + assert: + that: + - so is changed + - so.name == "Micro" + - so.display_text == "Micro RAM 512MB 1vCPU" + - so.cpu_number == 1 + - so.cpu_speed == 2198 + - so.memory == 512 + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: remove service offering idempotence + cs_service_offering: + name: Micro + state: absent + register: so +- name: verify remove service offering idempotence + assert: + that: + - so is not changed + +- name: create custom service offering + cs_service_offering: + name: custom + display_text: custom offer + is_customized: yes + host_tags: eco + storage_tags: + - eco + - backup + storage_type: local + register: so +- name: verify create custom service offering + assert: + that: + - so is changed + - so.name == "custom" + - so.display_text == "custom offer" + - so.is_customized == True + - so.cpu_number is not defined + - so.cpu_speed is not defined + - so.memory is not defined + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" + +- name: remove custom service offering + cs_service_offering: + name: custom + state: absent + register: so +- name: verify remove service offering + assert: + that: + - so is changed + - so.name == "custom" + - so.display_text == "custom offer" + - so.host_tags == ['eco'] + - so.storage_tags == ['eco', 'backup'] + - so.storage_type == "local" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml new file mode 100644 index 00000000..581f7d74 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: guest_vm_service_offering.yml +- import_tasks: system_vm_service_offering.yml
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml new file mode 100644 index 00000000..4c63a4b9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_service_offering/tasks/system_vm_service_offering.yml @@ -0,0 +1,151 @@ +--- +- name: setup system offering + cs_service_offering: + name: System Offering for Ansible + is_system: true + state: absent + register: so +- name: verify setup system offering + assert: + that: + - so is successful + +- name: fail missing storage type and is_system + cs_service_offering: + name: System Offering for Ansible + cpu_number: 1 + cpu_speed: 500 + memory: 512 + host_tag: perf + storage_tag: perf + storage_type: shared + offer_ha: true + limit_cpu_usage: false + is_system: true + register: so + ignore_errors: true +- name: verify create system service offering in check mode + assert: + that: + - so is failed + - so.msg.startswith('missing required arguments:') + +- name: create system service offering in check mode + cs_service_offering: + name: System Offering for Ansible + cpu_number: 1 + cpu_speed: 500 + memory: 512 + host_tag: perf + storage_tag: perf + storage_type: shared + offer_ha: true + limit_cpu_usage: false + system_vm_type: domainrouter + is_system: true + register: so + check_mode: true +- name: verify create system service offering in check mode + assert: + that: + - so is changed + +- name: create system service offering + cs_service_offering: + name: System Offering for Ansible + cpu_number: 1 + cpu_speed: 500 + memory: 512 + host_tag: perf + storage_tag: perf + storage_type: shared + offer_ha: true + limit_cpu_usage: false + system_vm_type: domainrouter + is_system: true + register: so +- name: verify create system service offering + assert: + that: + - so is changed + - so.name == "System Offering for Ansible" + - so.display_text == "System Offering for Ansible" + - so.cpu_number == 1 + - so.cpu_speed == 500 + - so.memory == 512 + - so.host_tags == ['perf'] + - so.storage_tags == ['perf'] + - so.storage_type == "shared" + - so.offer_ha == true + - so.limit_cpu_usage == false + - so.system_vm_type == "domainrouter" + - so.is_system == true + +- name: create system service offering idempotence + cs_service_offering: + name: System Offering for Ansible + cpu_number: 1 + cpu_speed: 500 + memory: 512 + host_tag: perf + storage_tag: perf + storage_type: shared + offer_ha: true + limit_cpu_usage: false + system_vm_type: domainrouter + is_system: true + register: so +- name: verify create system service offering idempotence + assert: + that: + - so is not changed + - so.name == "System Offering for Ansible" + - so.display_text == "System Offering for Ansible" + - so.cpu_number == 1 + - so.cpu_speed == 500 + - so.memory == 512 + - so.host_tags == ['perf'] + - so.storage_tags == ['perf'] + - so.storage_type == "shared" + - so.offer_ha == true + - so.limit_cpu_usage == false + - so.system_vm_type == "domainrouter" + - so.is_system == true + +- name: remove system service offering in check mode + cs_service_offering: + name: System Offering for Ansible + is_system: true + state: absent + check_mode: true + register: so +- name: verify remove system service offering in check mode + assert: + that: + - so is changed + - so.name == "System Offering for Ansible" + - so.is_system == true + +- name: remove system service offering + cs_service_offering: + name: System Offering for Ansible + is_system: true + state: absent + register: so +- name: verify remove system service offering + assert: + that: + - so is changed + - so.name == "System Offering for Ansible" + - so.is_system == true + +- name: remove system service offering idempotence + cs_service_offering: + name: System Offering for Ansible + is_system: true + state: absent + register: so +- name: verify remove system service offering idempotence + assert: + that: + - so is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml new file mode 100644 index 00000000..d5ba1bdc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_snapshot_policy/tasks/main.yml @@ -0,0 +1,176 @@ +--- +- name: setup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-snapshot-policy" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + +- name: setup snapshot policy absent + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + state: absent + register: snapshot +- name: verify setup snapshot policy absent + assert: + that: + - snapshot is successful + +- name: create snapshot policy in check mode + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 5 + check_mode: true + register: snapshot +- name: verify create snapshot policy in check mode + assert: + that: + - snapshot is changed + +- name: create snapshot policy + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 5 + register: snapshot +- name: verify create snapshot policy + assert: + that: + - snapshot is changed + - snapshot.schedule == "5" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + +- name: create snapshot policy idempotence + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 5 + register: snapshot +- name: verify create snapshot policy idempotence + assert: + that: + - snapshot is not changed + - snapshot.schedule == "5" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + +- name: update snapshot policy + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 6 + check_mode: true + register: snapshot +- name: verify update snapshot policy + assert: + that: + - snapshot is changed + - snapshot.schedule == "5" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + +- name: update snapshot policy in check mode + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 6 + max_snaps: 3 + time_zone: "Europe/Zurich" + check_mode: true + register: snapshot +- name: verify update snapshot policy in check mode + assert: + that: + - snapshot is changed + - snapshot.schedule == "5" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + - snapshot.max_snaps == 8 + - snapshot.time_zone == "UTC" + +- name: update snapshot policy + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 6 + max_snaps: 3 + time_zone: "Europe/Zurich" + register: snapshot +- name: verify update snapshot policy + assert: + that: + - snapshot is changed + - snapshot.schedule == "6" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + - snapshot.max_snaps == 3 + - snapshot.time_zone == "Europe/Zurich" + +- name: update snapshot policy idempotence + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + schedule: 6 + max_snaps: 3 + time_zone: "Europe/Zurich" + register: snapshot +- name: verify update snapshot policy idempotence + assert: + that: + - snapshot is not changed + - snapshot.schedule == "6" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + - snapshot.max_snaps == 3 + - snapshot.time_zone == "Europe/Zurich" + +- name: remove snapshot policy in check mode + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + state: absent + check_mode: true + register: snapshot +- name: verify remove snapshot policy in check mode + assert: + that: + - snapshot is changed + - snapshot.schedule == "6" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + - snapshot.max_snaps == 3 + - snapshot.time_zone == "Europe/Zurich" + +- name: remove snapshot policy + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + state: absent + register: snapshot +- name: verify remove snapshot policy + assert: + that: + - snapshot is changed + - snapshot.schedule == "6" + - snapshot.interval_type == "hourly" + - snapshot.volume != "" + - snapshot.max_snaps == 3 + - snapshot.time_zone == "Europe/Zurich" + +- name: remove snapshot policy idempotence + cs_snapshot_policy: + vm: "{{ cs_resource_prefix }}-vm-snapshot-policy" + interval_type: hourly + state: absent + register: snapshot +- name: verify remove snapshot policy idempotence + assert: + that: + - snapshot is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml new file mode 100644 index 00000000..89aa2522 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_sshkeypair/tasks/main.yml @@ -0,0 +1,197 @@ +--- +- name: setup cleanup + cs_sshkeypair: + name: "{{ item }}" + state: absent + register: sshkey + with_items: + - first-sshkey + - first-sshkey-renamed + - second-sshkey +- name: verify setup cleanup + assert: + that: + - sshkey is success + +- name: test fail on missing name + action: cs_sshkeypair + ignore_errors: true + register: sshkey +- name: verify results of fail on missing name + assert: + that: + - sshkey is failed + - "sshkey.msg == 'missing required arguments: name'" + +- name: test ssh key creation in check mode + cs_sshkeypair: + name: first-sshkey + register: sshkey + check_mode: true +- name: verify results of ssh key creation in check mode + assert: + that: + - sshkey is successful + - sshkey is changed + +- name: test ssh key creation + cs_sshkeypair: + name: first-sshkey + register: sshkey +- name: verify results of ssh key creation + assert: + that: + - sshkey is successful + - sshkey is changed + - sshkey.fingerprint is defined and sshkey.fingerprint != "" + - sshkey.private_key is defined and sshkey.private_key != "" + - sshkey.name == "first-sshkey" + +- name: test ssh key creation idempotence + cs_sshkeypair: + name: first-sshkey + register: sshkey2 +- name: verify results of ssh key creation idempotence + assert: + that: + - sshkey2 is successful + - sshkey2 is not changed + - sshkey2.fingerprint is defined and sshkey2.fingerprint == sshkey.fingerprint + - sshkey2.private_key is not defined + - sshkey2.name == "first-sshkey" + +- name: test replace ssh public key in check mode + cs_sshkeypair: + name: first-sshkey + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey2 + check_mode: true +- name: verify results of replace ssh public key in check mode + assert: + that: + - sshkey2 is successful + - sshkey2 is changed + - sshkey2.fingerprint is defined and sshkey2.fingerprint == sshkey.fingerprint + - sshkey2.private_key is not defined + - sshkey2.name == "first-sshkey" + +- name: test replace ssh public key + cs_sshkeypair: + name: first-sshkey + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey3 +- name: verify results of replace ssh public key + assert: + that: + - sshkey3 is changed + - sshkey3.fingerprint is defined and sshkey3.fingerprint != sshkey2.fingerprint + - sshkey3.private_key is not defined + - sshkey3.name == "first-sshkey" + +- name: test replace ssh public key idempotence + cs_sshkeypair: + name: first-sshkey + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey4 +- name: verify results of ssh public key idempotence + assert: + that: + - sshkey4 is not changed + - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint + - sshkey4.private_key is not defined + - sshkey4.name == "first-sshkey" + +- name: test rename ssh key in check mode + cs_sshkeypair: + name: first-sshkey-renamed + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey4 + check_mode: true +- name: verify test rename ssh key in check mode + assert: + that: + - sshkey4 is changed + - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint + - sshkey4.private_key is not defined + - sshkey4.name == "first-sshkey" + +- name: test rename ssh key + cs_sshkeypair: + name: first-sshkey-renamed + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey4 +- name: verify test rename ssh key + assert: + that: + - sshkey4 is changed + - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint + - sshkey4.private_key is not defined + - sshkey4.name == "first-sshkey-renamed" + +- name: test rename ssh key idempotence + cs_sshkeypair: + name: first-sshkey-renamed + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey4 +- name: verify test rename ssh key idempotence + assert: + that: + - sshkey4 is not changed + - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint + - sshkey4.private_key is not defined + - sshkey4.name == "first-sshkey-renamed" + +- name: setup ssh key with name "second-sshkey" + cs_sshkeypair: + name: second-sshkey + +- name: test different but exisitng name but same ssh public key as first-sshkey + cs_sshkeypair: + name: second-sshkey + public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch" + register: sshkey +- name: verify test different but exisitng name but same ssh public key as first-sshkey + assert: + that: + - sshkey is changed + - sshkey.fingerprint is defined and sshkey.fingerprint == sshkey4.fingerprint + - sshkey.private_key is not defined + - sshkey.name == "second-sshkey" + +- name: test ssh key absent in check mode + cs_sshkeypair: name=second-sshkey state=absent + register: sshkey5 + check_mode: true +- name: verify result of key absent in check mode + assert: + that: + - sshkey5 is changed + - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint + - sshkey5.private_key is not defined + - sshkey5.name == "second-sshkey" + +- name: test ssh key absent + cs_sshkeypair: + name: second-sshkey + state: absent + register: sshkey5 +- name: verify result of key absent + assert: + that: + - sshkey5 is changed + - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint + - sshkey5.private_key is not defined + - sshkey5.name == "second-sshkey" + +- name: test ssh key absent idempotence + cs_sshkeypair: + name: second-sshkey + state: absent + register: sshkey6 +- name: verify result of ssh key absent idempotence + assert: + that: + - sshkey6 is not changed + - sshkey6.fingerprint is not defined + - sshkey6.private_key is not defined + - sshkey6.name is not defined diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml new file mode 100644 index 00000000..a418b984 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_storage_pool/tasks/main.yml @@ -0,0 +1,465 @@ +--- +- name: setup host is present + cs_host: + name: sim + url: "http://sim/c0-basic/h2" + cluster: C0-adv + pod: POD0-adv + username: root + password: password + hypervisor: Simulator + allocation_state: enabled + zone: "{{ cs_common_zone_adv }}" + register: host +- name: verify setup host is present + assert: + that: + - host is successful + +- name: setup storage pool is absent + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify setup storage pool is absent + assert: + that: + - sp is successful + +- name: test fail if missing params + cs_storage_pool: + register: sp + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - sp is failed + - "sp.msg == 'missing required arguments: name'" + +- name: test fail if provider unknown + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + provider: DNE + scope: cluster + cluster: C0-adv + pod: POD0-adv + register: sp + ignore_errors: true +- name: verify test fail if provider unknown + assert: + that: + - sp is failed + - "sp.msg == 'Storage provider DNE not found'" + +- name: test fail if cluster unknown + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: DNE + pod: POD0-adv + register: sp + ignore_errors: true +- name: verify test fail if cluster unknown + assert: + that: + - sp is failed + - "sp.msg == 'Cluster DNE not found'" + +- name: test fail if pod unknown + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: DNE + register: sp + ignore_errors: true +- name: verify test fail if pod unknown + assert: + that: + - sp is failed + - "'Pod DNE not found' in sp.msg" + +- name: create storage pool in check mode + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + register: sp + check_mode: true +- name: verify create storage pool in check mode + assert: + that: + - sp is successful + - sp is changed + +- name: create storage pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + register: sp +- name: verify create storage pool + assert: + that: + - sp is successful + - sp is changed + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: create storage pool idempotence + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + cluster: C0-adv + pod: POD0-adv + register: sp +- name: verify create storage pool idempotence + assert: + that: + - sp is successful + - sp is not changed + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: disable storage pool in check mode + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + cluster: C0-adv + pod: POD0-adv + allocation_state: disabled + check_mode: true + register: sp +- name: verify disable storage pool in check mode + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'enabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: disable storage pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: disabled + register: sp +- name: verify disable storage pool + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: disable storage pool idempotence + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: disabled + register: sp +- name: verify disable storage pool idempotence + assert: + that: + - sp is successful + - sp is not changed + - sp.allocation_state == 'disabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: update while storage pool disabled in check mode + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + storage_tags: + - eco + - ssd + check_mode: true + register: sp +- name: verify update while storage pool disabled in check mode + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.storage_tags == [] + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: update while storage pool disabled + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + storage_tags: + - eco + - ssd + register: sp +- name: verify update while storage pool disabled + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.storage_tags == ['eco', 'ssd'] + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: update while storage pool disabled idempotence + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + storage_tags: + - eco + - ssd + register: sp +- name: verify update while storage pool disabled idempotence + assert: + that: + - sp is successful + - sp is not changed + - sp.allocation_state == 'disabled' + - sp.storage_tags == ['eco', 'ssd'] + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: put storage in maintenance pool in check mode + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: maintenance + check_mode: true + register: sp +- name: verify put storage in maintenance pool in check mode + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: put storage in maintenance pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: maintenance + register: sp +- name: verify put storage in maintenance pool + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'maintenance' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: put storage in maintenance pool idempotence + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: maintenance + register: sp +- name: verify put storage in maintenance pool idempotence + assert: + that: + - sp is successful + - sp is not changed + - sp.allocation_state == 'maintenance' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: update while in maintenance pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + storage_tag: perf + register: sp +- name: verify update while in maintenance pool + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'maintenance' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + - sp.storage_tags == ['perf'] + +- name: remove storage pool in check mode + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp + check_mode: true +- name: verify remove storage pool in check mode + assert: + that: + - sp is successful + - sp is changed + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: remove storage pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify remove storage pool + assert: + that: + - sp is successful + - sp is changed + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: remove storage pool idempotence + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify remove storage pool idempotence + assert: + that: + - sp is successful + - sp is not changed + +- name: create storage pool in maintenance + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: maintenance + register: sp +- name: verify create storage pool in maintenance + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'maintenance' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: remove storage pool in maintenance + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify storage pool in maintenance + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'maintenance' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: create storage pool disabled + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + storage_url: rbd://admin:SECRET@ceph-mons.domain/poolname + scope: cluster + cluster: C0-adv + pod: POD0-adv + allocation_state: disabled + register: sp +- name: verify create storage pool in disabled + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" + +- name: verify remove disabled storag e pool + cs_storage_pool: + name: "storage_pool_adv" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: sp +- name: verify remove disabled storage pool + assert: + that: + - sp is successful + - sp is changed + - sp.allocation_state == 'disabled' + - sp.cluster == "C0-adv" + - sp.pod == "POD0-adv" + - sp.storage_url == "RBD://ceph-mons.domain/poolname" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml new file mode 100644 index 00000000..80f67305 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/defaults/main.yml @@ -0,0 +1,5 @@ +--- +cs_template_hypervisor: Simulator +cs_template_os_type: Other Linux (64-bit) +cs_template_url: http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-vmware.ova +cs_template_format: OVA diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml new file mode 100644 index 00000000..ffeaa8a0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- import_tasks: test1.yml +- import_tasks: test2.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml new file mode 100644 index 00000000..755394fa --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test1.yml @@ -0,0 +1,160 @@ +--- +- name: setup template + cs_template: + name: "ansible-template-test1" + state: absent + register: template +- name: verify setup template + assert: + that: + - template is successful + +- name: test download template in check mode + cs_template: + name: "ansible-template-test1" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + register: template + check_mode: yes +- name: verify test download template in check mode + assert: + that: + - template is changed + +- name: test download template + cs_template: + name: "ansible-template-test1" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + register: template +- name: verify test download template + assert: + that: + - template is changed + - template.name == "ansible-template-test1" + - template.display_text == "ansible-template-test1" + - template.cross_zones == true + +- name: test download template idempotence + cs_template: + name: "ansible-template-test1" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + register: template +- name: verify test download template idempotence + assert: + that: + - template is not changed + - template.name == "ansible-template-test1" + - template.display_text == "ansible-template-test1" + - template.cross_zones == true + +- name: test update template in check mode + cs_template: + name: "ansible-template-test1" + display_text: "{{ cs_resource_prefix }}-template display_text" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + is_featured: yes + cross_zones: yes + register: template + check_mode: yes +- name: verify test update template in check mode + assert: + that: + - template is changed + - template.name == "ansible-template-test1" + - template.display_text == "ansible-template-test1" + - template.cross_zones == true + - template.is_featured == false + +- name: test update template + cs_template: + name: "ansible-template-test1" + display_text: "{{ cs_resource_prefix }}-template display_text" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + is_featured: yes + cross_zones: yes + register: template +- name: verify test update template + assert: + that: + - template is changed + - template.name == "ansible-template-test1" + - template.display_text == "{{ cs_resource_prefix }}-template display_text" + - template.cross_zones == true + - template.is_featured == true + +- name: test update template idempotence + cs_template: + name: "ansible-template-test1" + display_text: "{{ cs_resource_prefix }}-template display_text" + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + is_featured: yes + cross_zones: yes + register: template +- name: verify test update template idempotence + assert: + that: + - template is not changed + - template.name == "ansible-template-test1" + - template.display_text == "{{ cs_resource_prefix }}-template display_text" + - template.cross_zones == true + - template.is_featured == true + +- name: test remove template in check mode + cs_template: + name: "ansible-template-test1" + state: absent + cross_zones: yes + register: template + check_mode: yes +- name: verify test remove template in check mode + assert: + that: + - template is changed + - template.name == "ansible-template-test1" + - template.display_text == "{{ cs_resource_prefix }}-template display_text" + - template.cross_zones == true + +- name: test remove template + cs_template: + name: "ansible-template-test1" + state: absent + cross_zones: yes + register: template +- name: verify test remove template + assert: + that: + - template is changed + - template.name == "ansible-template-test1" + - template.display_text == "{{ cs_resource_prefix }}-template display_text" + - template.cross_zones == true + +- name: test remove template idempotence + cs_template: + name: "ansible-template-test1" + state: absent + cross_zones: yes + register: template +- name: verify test remove template idempotence + assert: + that: + - template is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml new file mode 100644 index 00000000..d5d44453 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_template/tasks/test2.yml @@ -0,0 +1,181 @@ +--- +- name: setup template first template + cs_template: + name: ansible-template-test2 + display_text: first template + state: absent + cross_zones: yes + template_find_options: display_text + register: template +- name: verify setup template first template + assert: + that: + - template is successful + +- name: setup template second template + cs_template: + name: ansible-template-test2 + display_text: second template + state: absent + cross_zones: yes + template_find_options: display_text + register: template +- name: verify setup template second template + assert: + that: + - template is successful + +- name: test register first template + cs_template: + name: ansible-template-test2 + display_text: first template + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + template_find_options: display_text + register: template_first +- name: verify test register first template + assert: + that: + - template_first is changed + - template_first.name == "ansible-template-test2" + - template_first.display_text == "first template" + - template_first.cross_zones == true + +- name: test register second template + cs_template: + name: ansible-template-test2 + display_text: second template + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + template_find_options: display_text + register: template_second +- name: verify test register second template + assert: + that: + - template_second is changed + - template_second.name == "ansible-template-test2" + - template_second.display_text == "second template" + - template_second.cross_zones == true + - template_second.id != template_first.id + +- name: test multiple template same name absent without find options + cs_template: + name: ansible-template-test2 + state: absent + cross_zones: yes + register: template + ignore_errors: yes +- name: verify test multiple template same name absent without find options + assert: + that: + - template is failed + - template.msg.startswith('Multiple templates found') + +- name: test update second template + cs_template: + name: ansible-template-test2 + display_text: second template + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + is_featured: yes + is_public: yes + cross_zones: yes + template_find_options: display_text + register: template +- name: verify test update second template + assert: + that: + - template is changed + - template.name == "ansible-template-test2" + - template.display_text == "second template" + - template.cross_zones == true + - template.id == template_second.id + - template.is_featured == true + - template.is_public == true + +- name: test update second template idempotence + cs_template: + name: ansible-template-test2 + display_text: second template + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + is_featured: yes + is_public: yes + cross_zones: yes + template_find_options: display_text + register: template +- name: verify test update second template idempotence + assert: + that: + - template is not changed + - template.name == "ansible-template-test2" + - template.display_text == "second template" + - template.cross_zones == true + - template.id == template_second.id + - template.is_featured == true + +- name: test update second template idempotence 2 + cs_template: + name: ansible-template-test2 + display_text: second template + url: "{{ cs_template_url }}" + format: "{{ cs_template_format }}" + hypervisor: "{{ cs_template_hypervisor }}" + os_type: "{{ cs_template_os_type }}" + cross_zones: yes + template_find_options: display_text + register: template +- name: verify test update second template idempotence + assert: + that: + - template is not changed + - template.name == "ansible-template-test2" + - template.display_text == "second template" + - template.cross_zones == true + - template.id == template_second.id + +- name: test delete first template + cs_template: + name: ansible-template-test2 + display_text: first template + state: absent + cross_zones: yes + template_find_options: display_text + register: template +- name: verify test delete first template + assert: + that: + - template is changed + - template.name == "ansible-template-test2" + - template.display_text == "first template" + - template.cross_zones == true + - template.id == template_first.id + - template.is_featured == false + +- name: test delete second template + cs_template: + name: ansible-template-test2 + display_text: second template + state: absent + cross_zones: yes + template_find_options: display_text + register: template +- name: verify test delete second template + assert: + that: + - template is changed + - template.name == "ansible-template-test2" + - template.display_text == "second template" + - template.cross_zones == true + - template.id == template_second.id + - template.is_featured == true diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml new file mode 100644 index 00000000..76d42054 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_traffic_type/tasks/main.yml @@ -0,0 +1,174 @@ +--- +# Create a new zone - the default one is enabled +- name: assure zone for tests + cs_zone: + name: cs-test-zone + state: present + dns1: 8.8.8.8 + network_type: Advanced + register: cszone + +- name: ensure the zone is disabled + cs_zone: + name: "{{ cszone.name }}" + state: disabled + register: cszone + +- name: setup a network + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + broadcast_domain_range: ZONE + ignore_errors: true + register: pn + + +- name: fail on missing params + cs_traffic_type: + zone: "{{ pn.zone }}" + ignore_errors: true + register: tt +- name: validate fail on missing params + assert: + that: + - tt is failed + - 'tt.msg == "missing required arguments: physical_network, traffic_type"' + +- name: add a traffic type in check mode + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Guest + zone: "{{ pn.zone }}" + register: tt + check_mode: yes +- name: validate add a traffic type in check mode + assert: + that: + - tt is changed + - tt.zone == pn.zone + +- name: add a traffic type + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Guest + zone: "{{ pn.zone }}" + register: tt +- name: validate add a traffic type + assert: + that: + - tt is changed + - tt.physical_network == pn.id + - tt.traffic_type == 'Guest' + - tt.zone == pn.zone + +- name: add a traffic type idempotence + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Guest + zone: "{{ pn.zone }}" + register: tt +- name: validate add a traffic type idempotence + assert: + that: + - tt is not changed + - tt.physical_network == pn.id + - tt.traffic_type == 'Guest' + - tt.zone == pn.zone + +- name: update traffic type + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Guest + kvm_networklabel: cloudbr0 + zone: "{{ pn.zone }}" + register: tt +- name: validate update traffic type + assert: + that: + - tt is changed + - tt.physical_network == pn.id + - tt.traffic_type == 'Guest' + - tt.zone == pn.zone + - tt.kvm_networklabel == 'cloudbr0' + +- name: update traffic type idempotence + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Guest + kvm_networklabel: cloudbr0 + zone: "{{ pn.zone }}" + register: tt +- name: validate update traffic type idempotence + assert: + that: + - tt is not changed + - tt.physical_network == pn.id + - tt.traffic_type == 'Guest' + - tt.zone == pn.zone + - tt.kvm_networklabel == 'cloudbr0' + +- name: add a removable traffic type + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Public + kvm_networklabel: cloudbr1 + zone: "{{ pn.zone }}" + register: tt +- name: validate add a removable traffic type + assert: + that: + - tt is changed + - tt.physical_network == pn.id + - tt.traffic_type == 'Public' + - tt.zone == pn.zone + - tt.kvm_networklabel == 'cloudbr1' + +- name: remove traffic type in check mode + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Public + state: absent + zone: "{{ pn.zone }}" + check_mode: yes + register: tt +- name: validate remove traffic type in check mode + assert: + that: + - tt is changed + +- name: remove traffic type + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Public + state: absent + zone: "{{ pn.zone }}" + register: tt +- name: validate remove traffic type + assert: + that: + - tt is changed + - tt.zone == pn.zone + +- name: remove traffic type idempotence + cs_traffic_type: + physical_network: "{{ pn.name }}" + traffic_type: Public + state: absent + zone: "{{ pn.zone }}" + register: tt +- name: validate + assert: + that: + - tt is not changed + - tt.zone == pn.zone + +- name: cleanup + block: + - cs_physical_network: + name: "{{ pn.name }}" + zone: "{{ cszone.name }}" + state: absent + - cs_zone: + name: "{{ cszone.name }}" + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml new file mode 100644 index 00000000..f48588da --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_user/tasks/main.yml @@ -0,0 +1,618 @@ +--- +- name: setup + cs_user: username={{ cs_resource_prefix }}_user state=absent + register: user +- name: verify setup + assert: + that: + - user is successful + +- name: test fail if missing username + action: cs_user + register: user + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - user is failed + - 'user.msg == "missing required arguments: username"' + +- name: test fail if missing params if state=present + cs_user: + username: "{{ cs_resource_prefix }}_user" + register: user + ignore_errors: true +- name: verify results of fail if missing params if state=present + assert: + that: + - user is failed + - 'user.msg == "missing required arguments: account, email, password, first_name, last_name"' + +- name: test create user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + register: user + check_mode: true +- name: verify results of create user in check mode + assert: + that: + - user is successful + - user is changed + +- name: test create user + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + register: user +- name: verify results of create user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is not defined + +- name: test create user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + register: user +- name: verify results of create user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is not defined + +- name: test create account + cs_account: + name: "{{ cs_resource_prefix }}_acc" + username: "{{ cs_resource_prefix }}_acc_username" + password: "{{ cs_resource_prefix }}_acc_password" + last_name: "{{ cs_resource_prefix }}_acc_last_name" + first_name: "{{ cs_resource_prefix }}_acc_first_name" + email: "{{ cs_resource_prefix }}@example.com" + network_domain: "example.com" + register: acc +- name: verify results of create account + assert: + that: + - acc is successful + - acc is changed + - acc.name == "{{ cs_resource_prefix }}_acc" + - acc.network_domain == "example.com" + - acc.account_type == "user" + - acc.state == "enabled" + - acc.domain == "ROOT" + - acc is changed + +- name: test create user2 in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user2" + password: "{{ cs_resource_prefix }}_password2" + last_name: "{{ cs_resource_prefix }}_last_name2" + first_name: "{{ cs_resource_prefix }}_first_name2" + email: "{{ cs_resource_prefix }}@example2.com" + account: "{{ cs_resource_prefix }}_acc" + keys_registered: true + check_mode: true + register: user +- name: verify results of create user idempotence + assert: + that: + - user is successful + - user is changed + +- name: test create user2 + cs_user: + username: "{{ cs_resource_prefix }}_user2" + password: "{{ cs_resource_prefix }}_password2" + last_name: "{{ cs_resource_prefix }}_last_name2" + first_name: "{{ cs_resource_prefix }}_first_name2" + email: "{{ cs_resource_prefix }}@example2.com" + account: "{{ cs_resource_prefix }}_acc" + keys_registered: true + register: user +- name: verify results of create user idempotence + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user2" + - user.first_name == "{{ cs_resource_prefix }}_first_name2" + - user.last_name == "{{ cs_resource_prefix }}_last_name2" + - user.email == "{{ cs_resource_prefix }}@example2.com" + - user.account_type == "user" + - user.account == "{{ cs_resource_prefix }}_acc" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is defined + +- name: test create user2 idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user2" + password: "{{ cs_resource_prefix }}_password2" + last_name: "{{ cs_resource_prefix }}_last_name2" + first_name: "{{ cs_resource_prefix }}_first_name2" + email: "{{ cs_resource_prefix }}@example2.com" + account: "{{ cs_resource_prefix }}_acc" + keys_registered: true + register: user +- name: verify results of create user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user2" + - user.first_name == "{{ cs_resource_prefix }}_first_name2" + - user.last_name == "{{ cs_resource_prefix }}_last_name2" + - user.email == "{{ cs_resource_prefix }}@example2.com" + - user.account_type == "user" + - user.account == "{{ cs_resource_prefix }}_acc" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is defined + +- name: test update user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name1" + first_name: "{{ cs_resource_prefix }}_first_name1" + email: "{{ cs_resource_prefix }}@example.com1" + account: "admin" + keys_registered: true + register: user + check_mode: true +- name: verify results of update user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is not defined + +- name: test update user + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name1" + first_name: "{{ cs_resource_prefix }}_first_name1" + email: "{{ cs_resource_prefix }}@example.com1" + account: "admin" + keys_registered: true + register: user +- name: verify results of update user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name1" + - user.last_name == "{{ cs_resource_prefix }}_last_name1" + - user.email == "{{ cs_resource_prefix }}@example.com1" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is defined + +- name: test update user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name1" + first_name: "{{ cs_resource_prefix }}_first_name1" + email: "{{ cs_resource_prefix }}@example.com1" + account: "admin" + keys_registered: true + register: user +- name: verify results of update user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name1" + - user.last_name == "{{ cs_resource_prefix }}_last_name1" + - user.email == "{{ cs_resource_prefix }}@example.com1" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + - user.user_api_key is defined + +- name: test lock user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user + check_mode: true +- name: verify results of lock user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state != "locked" + - user.domain == "ROOT" + +- name: test lock user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user +- name: verify results of lock user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test lock user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user +- name: verify results of lock user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test disable user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: disabled + register: user + check_mode: true +- name: verify results of disable user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state != "disabled" + - user.domain == "ROOT" + +- name: test disable user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: disabled + register: user +- name: verify results of disable user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "disabled" + - user.domain == "ROOT" + +- name: test disable user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: disabled + register: user +- name: verify results of disable user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "disabled" + - user.domain == "ROOT" + +- name: test lock disabled user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user + check_mode: true +- name: verify results of lock disabled user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "disabled" + - user.domain == "ROOT" + +- name: test lock disabled user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user +- name: verify results of lock disabled user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test lock disabled user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: locked + register: user +- name: verify results of lock disabled user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test enable user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: enabled + register: user + check_mode: true +- name: verify results of enable user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state != "enabled" + - user.domain == "ROOT" + +- name: test enable user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: enabled + register: user +- name: verify results of enable user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + +- name: test enable user idempotence using unlocked + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: unlocked + register: user +- name: verify results of enable user idempotence + assert: + that: + - user is successful + - user is not changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + +- name: test remove user in check mode + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user + check_mode: true +- name: verify results of remove user in check mode + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + +- name: test remove user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user +- name: verify results of remove user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + +- name: test remove user idempotence + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user +- name: verify results of remove user idempotence + assert: + that: + - user is successful + - user is not changed + +- name: test create locked user + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + state: locked + register: user +- name: verify results of create locked user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test remove locked user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user +- name: verify results of remove locked user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "locked" + - user.domain == "ROOT" + +- name: test create disabled user + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + state: disabled + register: user +- name: verify results of create disabled user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "disabled" + - user.domain == "ROOT" + +- name: test remove disabled user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user +- name: verify results of remove disabled user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "disabled" + - user.domain == "ROOT" + +- name: test create enabled user + cs_user: + username: "{{ cs_resource_prefix }}_user" + password: "{{ cs_resource_prefix }}_password" + last_name: "{{ cs_resource_prefix }}_last_name" + first_name: "{{ cs_resource_prefix }}_first_name" + email: "{{ cs_resource_prefix }}@example.com" + account: "admin" + state: enabled + register: user +- name: verify results of create enabled user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.first_name == "{{ cs_resource_prefix }}_first_name" + - user.last_name == "{{ cs_resource_prefix }}_last_name" + - user.email == "{{ cs_resource_prefix }}@example.com" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" + +- name: test remove enabled user + cs_user: + username: "{{ cs_resource_prefix }}_user" + state: absent + register: user +- name: verify results of remove enabled user + assert: + that: + - user is successful + - user is changed + - user.username == "{{ cs_resource_prefix }}_user" + - user.account_type == "root_admin" + - user.account == "admin" + - user.state == "enabled" + - user.domain == "ROOT" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml new file mode 100644 index 00000000..fdfc2515 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vlan_ip_range/tasks/main.yml @@ -0,0 +1,461 @@ +--- +- name: setup cleanup test network + cs_network: + name: ipr_test_network + state: absent + zone: "{{ cs_common_zone_adv }}" + +- name: setup create test network + cs_network: + name: ipr_test_network + zone: "{{ cs_common_zone_adv }}" + vlan: 98 + start_ip: 10.2.4.2 + end_ip: 10.2.4.9 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + network_offering: DefaultSharedNetworkOffering + register: ipr_net +- name: verify setup create test network + assert: + that: + - ipr_net is successful + - ipr_net is changed + +- name: test create a VLAN IP RANGE with missing required param + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + zone: "{{ cs_common_zone_adv }}" + ignore_errors: yes + register: ipr +- name: verify test create VLAN IP RANGE with missing required param + assert: + that: + - ipr is not successful + - ipr is not changed + - 'ipr.msg == "state is present but all of the following are missing: netmask"' + +- name: test create a VLAN IP RANGE with conflicting params + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + project: fakeproject + account: fakeaccount + zone: "{{ cs_common_zone_adv }}" + ignore_errors: yes + register: ipr +- name: verify test create VLAN IP RANGE with missing conflicting params + assert: + that: + - ipr is not successful + - ipr is not changed + - 'ipr.msg == "parameters are mutually exclusive: account|project"' + +- name: test create a VLAN IP RANGE in check mode + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr + check_mode: true +- name: verify test create VLAN IP RANGE in check mode + assert: + that: + - ipr is successful + - ipr is changed + +- name: test create a VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr +- name: verify test create VLAN IP RANGE + assert: + that: + - ipr is successful + - ipr is changed + - ipr.vlan == "vlan://98" + - ipr.start_ip == "10.2.4.10" + - ipr.end_ip == "10.2.4.100" + - ipr.gateway == "10.2.4.1" + - ipr.netmask == "255.255.255.0" + - ipr.network == "ipr_test_network" + - ipr.for_virtual_network == false + +- name: test create a VLAN IP RANGE idempotence + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr +- name: verify test create VLAN IP RANGE idempotence + assert: + that: + - ipr is successful + - ipr is not changed + - ipr.vlan == "vlan://98" + - ipr.start_ip == "10.2.4.10" + - ipr.end_ip == "10.2.4.100" + - ipr.gateway == "10.2.4.1" + - ipr.netmask == "255.255.255.0" + - ipr.network == "ipr_test_network" + - ipr.for_virtual_network == false + +- name: test create a second VLAN IP RANGE in check mode + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.101 + end_ip: 10.2.4.150 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr2 + check_mode: true +- name: verify test create a second VLAN IP RANGE in check mode + assert: + that: + - ipr2 is successful + - ipr2 is changed + +- name: test create a second VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.101 + end_ip: 10.2.4.150 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr2 +- name: verify test create a second VLAN IP RANGE + assert: + that: + - ipr2 is successful + - ipr2 is changed + - ipr2.vlan == "vlan://98" + - ipr2.start_ip == "10.2.4.101" + - ipr2.end_ip == "10.2.4.150" + - ipr2.gateway == "10.2.4.1" + - ipr2.netmask == "255.255.255.0" + - ipr2.network == "ipr_test_network" + - ipr2.for_virtual_network == false + - ipr2.id != ipr.id + +- name: test create a second VLAN IP RANGE idempotence + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.101 + end_ip: 10.2.4.150 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr2 +- name: verify test create a second VLAN IP RANGE idempotence + assert: + that: + - ipr2 is successful + - ipr2 is not changed + - ipr2.vlan == "vlan://98" + - ipr2.start_ip == "10.2.4.101" + - ipr2.end_ip == "10.2.4.150" + - ipr2.gateway == "10.2.4.1" + - ipr2.netmask == "255.255.255.0" + - ipr2.network == "ipr_test_network" + - ipr2.for_virtual_network == false + +- name: test create a single IP VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.200 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + zone: "{{ cs_common_zone_adv }}" + register: ipr3 +- name: verify test create single IP VLAN IP RANGE + assert: + that: + - ipr3 is successful + - ipr3 is changed + - ipr3.vlan == "vlan://98" + - ipr3.start_ip == "10.2.4.200" + - ipr3.end_ip == "10.2.4.200" + - ipr3.gateway == "10.2.4.1" + - ipr3.netmask == "255.255.255.0" + - ipr3.network == "ipr_test_network" + - ipr3.for_virtual_network == false + +- name: test create an IPv4 + IPv6 VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + vlan: 98 + start_ip: 10.2.4.151 + end_ip: 10.2.4.199 + gateway: 10.2.4.1 + netmask: 255.255.255.0 + start_ipv6: 2001:db8::10 + end_ipv6: 2001:db8::50 + gateway_ipv6: 2001:db8::1 + cidr_ipv6: 2001:db8::/64 + zone: "{{ cs_common_zone_adv }}" + register: iprv6 +- name: verify test create an IPv4 + IPv6 VLAN IP RANGE + assert: + that: + - iprv6 is successful + - iprv6 is changed + - iprv6.vlan == "vlan://98" + - iprv6.start_ip == "10.2.4.151" + - iprv6.end_ip == "10.2.4.199" + - iprv6.gateway == "10.2.4.1" + - iprv6.netmask == "255.255.255.0" + - iprv6.start_ipv6 == "2001:db8::10" + - iprv6.end_ipv6 == "2001:db8::50" + - iprv6.gateway_ipv6 == "2001:db8::1" + - iprv6.cidr_ipv6 == "2001:db8::/64" + - iprv6.network == "ipr_test_network" + - iprv6.for_virtual_network == false + +- name: test cleanup VLAN IP RANGE in check mode + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + zone: "{{ cs_common_zone_adv }}" + state: absent + check_mode: true + register: ipr +- name: verify test cleanup VLAN IP RANGE in check mode + assert: + that: + - ipr is successful + - ipr is changed + - ipr.vlan == "vlan://98" + - ipr.start_ip == "10.2.4.10" + - ipr.end_ip == "10.2.4.100" + - ipr.gateway == "10.2.4.1" + - ipr.netmask == "255.255.255.0" + - ipr.network == "ipr_test_network" + - ipr.for_virtual_network == false + +- name: test cleanup VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ipr +- name: verify test cleanup VLAN IP RANGE + assert: + that: + - ipr is successful + - ipr is changed + - ipr.vlan == "vlan://98" + - ipr.start_ip == "10.2.4.10" + - ipr.end_ip == "10.2.4.100" + - ipr.gateway == "10.2.4.1" + - ipr.netmask == "255.255.255.0" + - ipr.network == "ipr_test_network" + - ipr.for_virtual_network == false + +- name: test cleanup VLAN IP RANGE idempotence + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.10 + end_ip: 10.2.4.100 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ipr +- name: verify test cleanup VLAN IP RANGE idempotence + assert: + that: + - ipr is successful + - ipr is not changed + +- name: test cleanup single IP VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.200 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ipr +- name: verify test cleanup single IP VLAN IP RANGE + assert: + that: + - ipr is successful + - ipr is changed + - ipr.vlan == "vlan://98" + - ipr.start_ip == "10.2.4.200" + - ipr.end_ip == "10.2.4.200" + - ipr.gateway == "10.2.4.1" + - ipr.netmask == "255.255.255.0" + - ipr.network == "ipr_test_network" + - ipr.for_virtual_network == false + +- name: cleanup second VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.101 + end_ip: 10.2.4.150 + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ipr2 +- name: verify cleanup second VLAN IP RANGE + assert: + that: + - ipr2 is successful + - ipr2 is changed + - ipr2.vlan == "vlan://98" + - ipr2.start_ip == "10.2.4.101" + - ipr2.end_ip == "10.2.4.150" + - ipr2.gateway == "10.2.4.1" + - ipr2.netmask == "255.255.255.0" + - ipr2.network == "ipr_test_network" + - ipr2.for_virtual_network == false + +- name: test cleanup IPv4 + IPv6 VLAN IP RANGE + cs_vlan_ip_range: + network: ipr_test_network + start_ip: 10.2.4.151 + end_ip: 10.2.4.199 + state: absent + zone: "{{ cs_common_zone_adv }}" + register: iprv6 +- name: verify test cleanup IPv4 + IPv6 VLAN IP RANGE + assert: + that: + - iprv6 is successful + - iprv6 is changed + - iprv6.vlan == "vlan://98" + - iprv6.start_ip == "10.2.4.151" + - iprv6.end_ip == "10.2.4.199" + - iprv6.gateway == "10.2.4.1" + - iprv6.netmask == "255.255.255.0" + - iprv6.start_ipv6 == "2001:db8::10" + - iprv6.end_ipv6 == "2001:db8::50" + - iprv6.gateway_ipv6 == "2001:db8::1" + - iprv6.cidr_ipv6 == "2001:db8::/64" + - iprv6.network == "ipr_test_network" + - iprv6.for_virtual_network == false + +- name: cleanup test network + cs_network: + name: ipr_test_network + zone: "{{ cs_common_zone_adv }}" + state: absent + register: ipr_net +- name: verify cleanup test network + assert: + that: + - ipr_net is successful + - ipr_net is changed + +# Create a new zone - the default one is enabled +- name: assure zone for tests + cs_zone: + name: cs-test-zone + state: present + dns1: 8.8.8.8 + network_type: Advanced + register: cszone + +- name: ensure the zone is disabled + cs_zone: + name: "{{ cszone.name }}" + state: disabled + +- name: setup a network for tests + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + isolation_method: VLAN + broadcast_domain_range: ZONE + state: present + register: public_network + +- name: setup public network traffic + cs_traffic_type: + physical_network: "{{ public_network.name }}" + traffic_type: Public + kvm_networklabel: cloudbr1 + zone: "{{ public_network.zone }}" + +- name: test adding a public IP range + cs_vlan_ip_range: + end_ip: 10.0.3.250 + start_ip: 10.0.3.10 + zone: "{{ cszone.name }}" + netmask: 255.255.255.0 + for_virtual_network: 'yes' + gateway: 10.0.3.2 + vlan: untagged + register: public_range +- name: verify test adding a public IP range + assert: + that: + - public_range is successful + - public_range is changed + - public_range.physical_network == public_network.id + - public_range.vlan == 'vlan://untagged' + - public_range.gateway == '10.0.3.2' + - public_range.netmask == '255.255.255.0' + - public_range.zone == cszone.name + - public_range.start_ip == '10.0.3.10' + - public_range.end_ip == '10.0.3.250' + - public_range.for_systemvms == false + +- name: test adding a public IP range for System VMs + cs_vlan_ip_range: + end_ip: 10.0.4.250 + start_ip: 10.0.4.10 + zone: "{{ cszone.name }}" + netmask: 255.255.255.0 + for_virtual_network: 'yes' + for_system_vms: 'yes' + gateway: 10.0.4.2 + vlan: untagged + register: public_range +- name: verify test adding a public IP range for System VMs + assert: + that: + - public_range is successful + - public_range is changed + - public_range.physical_network == public_network.id + - public_range.vlan == 'vlan://untagged' + - public_range.gateway == '10.0.4.2' + - public_range.netmask == '255.255.255.0' + - public_range.zone == cszone.name + - public_range.start_ip == '10.0.4.10' + - public_range.end_ip == '10.0.4.250' + - public_range.for_systemvms == true + +- name: cleanup the network + cs_physical_network: + name: net01 + zone: "{{ cszone.name }}" + state: absent + +- name: cleanup the zone + cs_zone: + name: "{{ cszone.name }}" + state: absent
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml new file mode 100644 index 00000000..490c6c14 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/defaults/main.yml @@ -0,0 +1,3 @@ +--- +test_cs_instance_template: "{{ cs_common_template }}" +test_cs_instance_offering_1: Small Instance diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml new file mode 100644 index 00000000..51ce5767 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vmsnapshot/tasks/main.yml @@ -0,0 +1,165 @@ +--- +- name: setup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-snapshot" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + zone: "{{ cs_common_zone_basic }}" + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: ensure no snapshot exists + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: snap +- name: verify setup + assert: + that: + - snap is successful + +- name: test fail if missing name + cs_vmsnapshot: + zone: "{{ cs_common_zone_basic }}" + register: snap + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - snap is failed + - 'snap.msg.startswith("missing required arguments: ")' + +- name: test create snapshot in check mode + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + snapshot_memory: yes + register: snap + check_mode: true +- name: verify test create snapshot in check mode + assert: + that: + - snap is changed + +- name: test create snapshot + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + snapshot_memory: yes + register: snap +- name: verify test create snapshot + assert: + that: + - snap is changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test create snapshot idempotence + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + snapshot_memory: yes + register: snap +- name: verify test create snapshot idempotence + assert: + that: + - snap is not changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test revert snapshot in check mode + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: revert + register: snap + check_mode: true +- name: verify test revert snapshot in check mode + assert: + that: + - snap is changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test fail revert unknown snapshot + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot_unknown" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: revert + register: snap + ignore_errors: true +- name: verify test fail revert unknown snapshot + assert: + that: + - snap is failed + - snap.msg == "snapshot not found, could not revert VM" + +- name: test revert snapshot + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: revert + register: snap +- name: verify test revert snapshot + assert: + that: + - snap is changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test remove snapshot in check mode + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: snap + check_mode: true +- name: verify test remove snapshot in check mode + assert: + that: + - snap is changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test remove snapshot + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: snap +- name: verify test remove snapshot + assert: + that: + - snap is changed + - snap.display_name == "{{ cs_resource_prefix }}_snapshot" + +- name: test remove snapshot idempotence + cs_vmsnapshot: + name: "{{ cs_resource_prefix }}_snapshot" + vm: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: snap +- name: verify test remove snapshot idempotence + assert: + that: + - snap is not changed + +- name: cleanup instance + cs_instance: + name: "{{ cs_resource_prefix }}-vm-snapshot" + zone: "{{ cs_common_zone_basic }}" + state: expunged + register: instance +- name: verify destroy instance + assert: + that: + - instance is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml new file mode 100644 index 00000000..f1074cf1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/defaults/main.yml @@ -0,0 +1,8 @@ +--- +test_cs_instance_1: "{{ cs_resource_prefix }}-vm1" +test_cs_instance_2: "{{ cs_resource_prefix }}-vm2" +test_cs_instance_3: "{{ cs_resource_prefix }}-vm3" +test_cs_instance_template: "{{ cs_common_template }}" +test_cs_instance_offering_1: Small Instance +test_cs_disk_offering_1: Custom +test_cs_volume_to_upload: http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml new file mode 100644 index 00000000..f011f858 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/common.yml @@ -0,0 +1,322 @@ +--- +- name: setup + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: vol +- name: verify setup + assert: + that: + - vol is successful + +- name: setup instance 1 + cs_instance: + name: "{{ test_cs_instance_1 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + zone: "{{ cs_common_zone_basic }}" + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: setup instance 2 + cs_instance: + name: "{{ test_cs_instance_2 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + zone: "{{ cs_common_zone_basic }}" + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: test fail if missing name + cs_volume: + zone: "{{ cs_common_zone_basic }}" + register: vol + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - vol is failed + - "vol.msg == 'missing required arguments: name'" + +- name: test create volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + +- name: test create volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test create volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 20 + register: vol +- name: verify results test create volume idempotence + assert: + that: + - vol is not changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + - vol.size == 20 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.size == 10 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test shrink volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + disk_offering: "{{ test_cs_disk_offering_1 }}" + size: 10 + shrink_ok: yes + register: vol +- name: verify results test create volume + assert: + that: + - vol is not changed + - vol.size == 10 * 1024 ** 3 + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test attach volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol + check_mode: true +- name: verify results test attach volume in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is not defined + +- name: test attach volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol +- name: verify results test attach volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_1 }}" + state: attached + register: vol +- name: verify results test attach volume idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm in check mdoe + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol + check_mode: true +- name: verify results test attach attached volume to another vm in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_1 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol +- name: verify results test attach attached volume to another vm + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_2 }}" + - vol.attached is defined + +- name: test attach attached volume to another vm idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + vm: "{{ test_cs_instance_2 }}" + state: attached + register: vol +- name: verify results test attach attached volume to another vm idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.vm == "{{ test_cs_instance_2 }}" + - vol.attached is defined + +- name: test detach volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: detached + register: vol + check_mode: true +- name: verify results test detach volume in check mdoe + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is defined + +- name: test detach volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: detached + register: vol +- name: verify results test detach volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is undefined + +- name: test detach volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: detached + register: vol +- name: verify results test detach volume idempotence + assert: + that: + - vol is not changed + - vol.name == "{{ cs_resource_prefix }}_vol" + - vol.attached is undefined + +- name: test delete volume in check mode + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: vol + check_mode: true +- name: verify results test create volume in check mode + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test delete volume + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: vol +- name: verify results test create volume + assert: + that: + - vol is changed + - vol.name == "{{ cs_resource_prefix }}_vol" + +- name: test delete volume idempotence + cs_volume: + name: "{{ cs_resource_prefix }}_vol" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: vol +- name: verify results test delete volume idempotence + assert: + that: + - vol is not changed + +- name: cleanup instance 1 + cs_instance: + name: "{{ test_cs_instance_1 }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify create instance + assert: + that: + - instance is successful + +- name: cleanup instance 2 + cs_instance: + name: "{{ test_cs_instance_2 }}" + zone: "{{ cs_common_zone_basic }}" + state: absent + register: instance +- name: verify create instance + assert: + that: + - instance is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml new file mode 100644 index 00000000..5dc70187 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/extract_upload.yml @@ -0,0 +1,190 @@ +--- +- name: setup + cs_volume: + zone: "{{ cs_common_zone_adv }}" + name: "{{ cs_resource_prefix }}_upload" + state: absent + register: uploaded_vol +- name: verify setup + assert: + that: + - uploaded_vol is successful + +- name: setup network + cs_network: + name: "cs_volume_network" + zone: "{{ cs_common_zone_adv }}" + network_offering: DefaultSharedNetworkOffering + vlan: 2435 + start_ip: 10.100.129.11 + end_ip: 10.100.129.250 + gateway: 10.100.129.1 + netmask: 255.255.255.0 + register: net +- name: verify setup network + assert: + that: + - net is successful + - net.name == "cs_volume_network" + +- name: setup instance + cs_instance: + zone: "{{ cs_common_zone_adv }}" + name: "{{ test_cs_instance_3 }}" + template: "{{ test_cs_instance_template }}" + service_offering: "{{ test_cs_instance_offering_1 }}" + network: cs_volume_network + register: instance +- name: verify setup instance + assert: + that: + - instance is successful + +- name: setup stop instance + cs_instance: + zone: "{{ cs_common_zone_adv }}" + name: "{{ test_cs_instance_3 }}" + state: stopped + register: instance +- name: verify stop instance + assert: + that: + - instance is successful + - instance.state == 'Stopped' + +- name: setup get instance info + cs_instance_info: + name: "{{ test_cs_instance_3 }}" + register: instance +- name: verify setup get instance info + assert: + that: + - instance is successful + +- name: test extract volume in check mode + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: extracted + name: "{{ instance.instances[0].volumes[0].name }}" + check_mode: yes + register: extracted_vol +- name: verify test extract volume in check mode + assert: + that: + - extracted_vol is successful + - extracted_vol is changed + - extracted_vol.state == "Ready" + - extracted_vol.name == "{{ instance.instances[0].volumes[0].name }}" + - extracted_vol.url is not defined + +- name: test extract volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: extracted + name: "{{ instance.instances[0].volumes[0].name }}" + register: extracted_vol +- name: verify test extract volume + assert: + that: + - extracted_vol is successful + - extracted_vol is changed + - extracted_vol.state == "DOWNLOAD_URL_CREATED" + - extracted_vol.name == "{{ instance.instances[0].volumes[0].name }}" + - extracted_vol.url is defined + +- name: test upload volume with missing param + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + url: "{{ test_cs_volume_to_upload }}" + ignore_errors: yes + register: uploaded_vol +- name: verify upload volume with missing param + assert: + that: + - uploaded_vol is failed + - uploaded_vol is not changed + - 'uploaded_vol.msg == "state is uploaded but all of the following are missing: format"' + +- name: test upload volume in check mode + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + check_mode: yes + register: uploaded_vol +- name: verify upload volume in check mode + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed + - uploaded_vol.name is not defined + +- name: test upload volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + register: uploaded_vol +- name: verify upload volume + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed + - uploaded_vol.name == "{{ cs_resource_prefix }}_upload" + - uploaded_vol.state == "Uploaded" + +- name: test upload volume idempotence + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: uploaded + name: "{{ cs_resource_prefix }}_upload" + format: VHD + url: "{{ test_cs_volume_to_upload }}" + register: uploaded_vol +- name: verify upload volume idempotence + assert: + that: + - uploaded_vol is successful + - uploaded_vol is not changed + - uploaded_vol.name == "{{ cs_resource_prefix }}_upload" + - uploaded_vol.state == "Uploaded" + +- name: delete volume + cs_volume: + zone: "{{ cs_common_zone_adv }}" + state: absent + name: "{{ cs_resource_prefix }}_upload" + register: uploaded_vol +- name: verify delete volume + assert: + that: + - uploaded_vol is successful + - uploaded_vol is changed + +- name: destroy instance + cs_instance: + zone: "{{ cs_common_zone_adv }}" + name: "{{ test_cs_instance_3 }}" + state: expunged + register: instance +- name: verify destroy instance + assert: + that: + - instance is successful + +- name: delete network + cs_network: + name: "cs_volume_network" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: net +- name: verify delete network + assert: + that: + - net is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml new file mode 100644 index 00000000..3b863beb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_volume/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- include_tasks: common.yml +- include_tasks: extract_upload.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml new file mode 100644 index 00000000..11e310a5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc/tasks/main.yml @@ -0,0 +1,728 @@ +--- +- name: setup + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpc +- name: verify setup + assert: + that: + - vpc is successful + +- name: test fail missing name of vpc + cs_vpc: + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: vpc +- name: verify test fail missing name of vpc + assert: + that: + - vpc is failed + - "vpc.msg.startswith('missing required arguments: ')" + +- name: test fail missing cidr for vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + ignore_errors: true + register: vpc +- name: verify test fail missing cidr for vpc + assert: + that: + - vpc is failed + - 'vpc.msg == "state is present but all of the following are missing: cidr"' + +- name: test fail missing vpc offering not found + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + vpc_offering: does_not_exist + zone: "{{ cs_common_zone_adv }}" + cidr: 10.10.1.0/16 + ignore_errors: true + register: vpc +- name: verify test fail missing cidr for vpc + assert: + that: + - vpc is failed + - 'vpc.msg == "VPC offering not found or not enabled: does_not_exist"' + +- name: test fail name substring match + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + # Full name is "Redundant VPC offering" + vpc_offering: "Redundant" + zone: "{{ cs_common_zone_adv }}" + cidr: 10.10.1.0/16 + ignore_errors: true + register: vpc +- name: verify test fail name substring match + assert: + that: + - vpc is failed + - 'vpc.msg == "VPC offering not found or not enabled: Redundant"' + +- name: test create vpc with custom offering in check mode + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_custom" + display_text: "{{ cs_resource_prefix }}_display_text_custom" + cidr: 10.10.1.0/16 + vpc_offering: Redundant VPC offering + network_domain: test.example.com + zone: "{{ cs_common_zone_adv }}" + state: stopped + register: vpc + check_mode: true +- name: verify test create vpc with custom offering in check mode + assert: + that: + - vpc is successful + - vpc is changed + +- name: test create vpc with custom offering + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_custom" + display_text: "{{ cs_resource_prefix }}_display_text_custom" + cidr: 10.10.1.0/16 + vpc_offering: Redundant VPC offering + network_domain: test.example.com + zone: "{{ cs_common_zone_adv }}" + state: stopped + register: vpc +- name: verify test create vpc with custom offering + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc_custom" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text_custom" + - vpc.cidr == "10.10.1.0/16" + - vpc.network_domain == "test.example.com" + +- name: test create vpc with custom offering idempotence + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_custom" + display_text: "{{ cs_resource_prefix }}_display_text_custom" + cidr: 10.10.1.0/16 + vpc_offering: Redundant VPC offering + network_domain: test.example.com + zone: "{{ cs_common_zone_adv }}" + state: stopped + register: vpc +- name: verify test create vpc with custom offering idempotence + assert: + that: + - vpc is successful + - vpc is not changed + - vpc.name == "{{ cs_resource_prefix }}_vpc_custom" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text_custom" + - vpc.cidr == "10.10.1.0/16" + - vpc.network_domain == "test.example.com" + +- name: test create vpc with default offering in check mode + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc + check_mode: true +- name: verify test create vpc with default offering in check mode + assert: + that: + - vpc is successful + - vpc is changed + +- name: test create vpc with default offering + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test create vpc with default offering + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text" + - vpc.cidr == "10.10.0.0/16" + +- name: test create vpc with default offering idempotence + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test create vpc with default offering idempotence + assert: + that: + - vpc is successful + - vpc is not changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text" + - vpc.cidr == "10.10.0.0/16" + +- name: test create vpc with default offering idempotence2 + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test create vpc idempotence2 + assert: + that: + - vpc is successful + - vpc is not changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text" + - vpc.cidr == "10.10.0.0/16" + +- name: test update vpc with default offering in check mode + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc + check_mode: true +- name: verify test update vpc with default offering in check mode + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text" + - vpc.cidr == "10.10.0.0/16" + +- name: test update vpc with default offering + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test update vpc with default offering + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test update vpc with default offering idempotence + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test update vpc idempotence + assert: + that: + - vpc is successful + - vpc is not changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test restart vpc with default offering with clean up in check mode + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + clean_up: true + state: restarted + register: vpc + check_mode: true +- name: verify test restart vpc with default offering with clean up in check mode + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test restart vpc with default offering with clean up + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + clean_up: true + state: restarted + register: vpc +- name: verify test restart vpc with default offering with clean up + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test restart vpc with default offering without clean up + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text2" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + state: restarted + register: vpc +- name: verify test restart vpc with default offering without clean up + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test create network in vpc in check mode + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + network_offering: Offering for Isolated Vpc networks with Source Nat service enabled + vpc: "{{ cs_resource_prefix }}_vpc" + gateway: 10.10.0.1 + netmask: 255.255.255.0 + register: vpc_net + check_mode: true +- name: verify test create network in vpc in check mode + assert: + that: + - vpc_net is successful + - vpc_net is changed + +- name: test create network in vpc + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + network_offering: Offering for Isolated Vpc networks with Source Nat service enabled + vpc: "{{ cs_resource_prefix }}_vpc" + gateway: 10.10.0.1 + netmask: 255.255.255.0 + register: vpc_net +- name: verify test create network in vpc + assert: + that: + - vpc_net is successful + - vpc_net is changed + - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc" + +- name: test create network in vpc idempotence + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + network_offering: Offering for Isolated Vpc networks with Source Nat service enabled + vpc: "{{ cs_resource_prefix }}_vpc" + gateway: 10.10.0.1 + netmask: 255.255.255.0 + register: vpc_net +- name: verify test create network in vpc idempotence + assert: + that: + - vpc_net is successful + - vpc_net is not changed + - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc" + +- name: test create instance in vpc in check mode + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "{{ cs_resource_prefix }}_net_vpc" + register: instance + check_mode: true +- name: verify test create instance in vpc in check mode + assert: + that: + - instance is successful + - instance is changed + +- name: test create instance in vpc + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "{{ cs_resource_prefix }}_net_vpc" + register: instance +- name: verify test create instance in vpc + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-vpc" + - instance.state == "Running" + +- name: test create instance in vpc idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + template: "{{ cs_common_template }}" + service_offering: "{{ cs_common_service_offering }}" + zone: "{{ cs_common_zone_adv }}" + network: "{{ cs_resource_prefix }}_net_vpc" + register: instance +- name: verify test create instance in vpc idempotence + assert: + that: + - instance is successful + - instance is not changed + - instance.name == "{{ cs_resource_prefix }}-vm-vpc" + - instance.state == "Running" + +- name: test get ip address in vpc + cs_ip_address: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: ip_address + when: instance.public_ip is undefined + +- name: test static nat in vpc in check mode + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + register: static_nat + check_mode: true +- name: verify test static nat in vpc in check mode + assert: + that: + - static_nat is successful + - static_nat is changed + +- name: test static nat in vpc + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + register: static_nat +- name: verify test static nat in vpc + assert: + that: + - static_nat is successful + - static_nat is changed + +- name: test static nat in vpc idempotence + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + register: static_nat +- name: verify test static nat in vpc idempotence + assert: + that: + - static_nat is successful + - static_nat is not changed + +- name: test remove static nat in vpc in check mode + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + state: absent + register: static_nat + check_mode: true +- name: verify test remove static nat in vpc in check mode + assert: + that: + - static_nat is successful + - static_nat is changed + +- name: test remove static nat in vpc + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + state: absent + register: static_nat +- name: verify test remove static nat in vpc + assert: + that: + - static_nat is successful + - static_nat is changed + +- name: test remove static nat in vpc idempotence + cs_staticnat: + vm: "{{ cs_resource_prefix }}-vm-vpc" + ip_address: "{{ ip_address.ip_address }}" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + network: "{{ cs_resource_prefix }}_net_vpc" + state: absent + register: static_nat +- name: verify test remove static nat in vpc idempotence + assert: + that: + - static_nat is successful + - static_nat is not changed + +- name: test create port forwarding in vpc in check mode + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: port_forward + check_mode: true +- name: verify test create port forwarding in vpc in check mode + assert: + that: + - port_forward is successful + - port_forward is changed + +- name: test create port forwarding in vpc + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: port_forward +- name: verify test create port forwarding in vpc + assert: + that: + - port_forward is successful + - port_forward is changed + +- name: test create port forwarding in vpc idempotence + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: port_forward +- name: verify test create port forwarding in vpc idempotence + assert: + that: + - port_forward is successful + - port_forward is not changed + +- name: test remove port forwarding in vpc in check mode + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: port_forward + check_mode: true +- name: verify test remove port forwarding in vpc in check mode + assert: + that: + - port_forward is successful + - port_forward is changed + +- name: test remove port forwarding in vpc + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: port_forward +- name: verify test remove port forwarding in vpc + assert: + that: + - port_forward is successful + - port_forward is changed + +- name: test remove port forwarding in vpc idempotence + cs_portforward: + ip_address: "{{ ip_address.ip_address }}" + vm: "{{ cs_resource_prefix }}-vm-vpc" + public_port: 80 + private_port: 8080 + network: "{{ cs_resource_prefix }}_net_vpc" + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: port_forward +- name: verify test remove port forwarding in vpc idempotence + assert: + that: + - port_forward is successful + - port_forward is not changed + +- name: test remove ip address from vpc + cs_ip_address: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + ip_address: "{{ ip_address.ip_address }}" + state: absent + register: ip_address_removed +- name: verify test remove ip address from vpc + assert: + that: + - ip_address_removed is successful + - ip_address_removed is changed + +- name: test remove instance in vpc in check mdoe + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance + check_mode: true +- name: verify test remove instance in vpc in check mode + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-vpc" + - instance.state == "Running" + +- name: test remove instance in vpc + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify test remove instance in vpc + assert: + that: + - instance is successful + - instance is changed + - instance.name == "{{ cs_resource_prefix }}-vm-vpc" + - instance.state == "Running" + +- name: test remove instance in vpc idempotence + cs_instance: + name: "{{ cs_resource_prefix }}-vm-vpc" + zone: "{{ cs_common_zone_adv }}" + state: expunged + register: instance +- name: verify test remove instance in vpc idempotence + assert: + that: + - instance is successful + - instance is not changed + +- name: test remove network in vpc in check mode + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpc_net + check_mode: true +- name: verify test remove network in vpc in check mode + assert: + that: + - vpc_net is successful + - vpc_net is changed + - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc" + +- name: test remove network in vpc + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpc_net +- name: verify test remove network in vpc + assert: + that: + - vpc_net is successful + - vpc_net is changed + - vpc_net.name == "{{ cs_resource_prefix }}_net_vpc" + +- name: test remove network in vpc idempotence + cs_network: + name: "{{ cs_resource_prefix }}_net_vpc" + zone: "{{ cs_common_zone_adv }}" + vpc: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpc_net +- name: verify test remove network in vpc idempotence + assert: + that: + - vpc_net is successful + - vpc_net is not changed + +- name: test remove vpc with default offering in check mode + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + zone: "{{ cs_common_zone_adv }}" + register: vpc + check_mode: true +- name: verify test remove vpc with default offering in check mode + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test remove vpc with default offering + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test remove vpc with default offering + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc" + - vpc.display_text == "{{ cs_resource_prefix }}_display_text2" + - vpc.cidr == "10.10.0.0/16" + +- name: test remove vpc with default offering idempotence + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpc +- name: verify test remove vpc idempotence + assert: + that: + - vpc is successful + - vpc is not changed + +- name: test remove vpc with custom offering + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc_custom" + state: absent + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify test remove vpc with custom offering + assert: + that: + - vpc is successful + - vpc is changed + - vpc.name == "{{ cs_resource_prefix }}_vpc_custom" + - vpc.cidr == "10.10.1.0/16" diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml new file mode 100644 index 00000000..ebbeaf91 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpc_offering/tasks/main.yml @@ -0,0 +1,427 @@ +--- +- name: setup + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpcoffer +- name: verify setup + assert: + that: + - vpcoffer is successful + +- name: test fail if missing name + cs_vpc_offering: + register: vpcoffer + ignore_errors: true +- name: verify results of fail if missing name + assert: + that: + - vpcoffer is failed + - 'vpcoffer.msg == "missing required arguments: name"' + +- name: test fail if missing params + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + register: vpcoffer + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - vpcoffer is failed + - 'vpcoffer.msg == "missing required arguments: display_text, supported_services"' + +- name: test create vpc offer in check mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: vpcoffer + check_mode: yes +- name: verify results of vpc offer in check mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + +- name: test create vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: vpcoffer +- name: verify results of vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + - vpcoffer.distributed == false + - vpcoffer.region_level == false + +- name: test create vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + register: vpcoffer +- name: verify results of create vpc offer idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + - vpcoffer.distributed == false + - vpcoffer.region_level == false + +- name: test enabling existing vpc offer in check_mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: enabled + register: vpcoffer + check_mode: yes +- name: verify results of enabling existing vpc offer in check_mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test enabling existing vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: enabled + register: vpcoffer +- name: verify results of enabling existing vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test enabling existing vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: enabled + register: vpcoffer +- name: verify results of enabling existing vpc idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test disabling vpc offer in check_mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer + check_mode: yes +- name: verify results of disabling vpc offer in check_mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test disabling vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer +- name: verify results of disabling vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test disabling vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer +- name: verify results of disabling vpc idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test rename vpc offer in check_mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description renamed" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer + check_mode: yes +- name: verify results of rename vpc offer in check_mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test rename vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description renamed" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer +- name: verify results of rename vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description renamed" + +- name: test rename vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description renamed" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: disabled + register: vpcoffer +- name: verify results of rename vpc offer idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description renamed" + +- name: test update offer with minimal params in check_mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description update" + register: vpcoffer + check_mode: yes +- name: verify results of update offer with minimal params in check_mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description renamed" + +- name: test update offer with minimal params + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description update" + register: vpcoffer +- name: verify results of update offer with minimal params + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description update" + +- name: test update offer with minimal params idempotency + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description update" + register: vpcoffer +- name: verify results of update offer with minimal params idempotency + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description update" + +- name: test remove vpc offer in check_mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpcoffer + check_mode: yes +- name: verify results of rename vpc offer in check_mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Disabled" + - vpcoffer.display_text == "vpc offering description update" + +- name: test remove vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpcoffer +- name: verify results of rename vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + +- name: test remove vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpcoffer +- name: verify results of rename vpc offer idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + +- name: test create enabled vpc offer in check mode + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: vpcoffer + check_mode: yes +- name: verify results of create enabled vpc offer in check mode + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + +- name: test create enabled vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: vpcoffer +- name: verify results of create enabled vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test create enabled vpc offer idempotence + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + register: vpcoffer +- name: verify results of create enabled vpc offer idempotence + assert: + that: + - vpcoffer is successful + - vpcoffer is not changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + +- name: test create enabled region level vpc offer with distrubuted router + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc_drl" + display_text: "vpc offering description" + supported_services: [ Dns, PortForwarding, Dhcp, SourceNat, UserData, StaticNat, Vpn, Lb ] + service_providers: + - { service: 'dns', provider: 'virtualrouter' } + - { service: 'dhcp', provider: 'virtualrouter' } + state: enabled + service_capabilities: + - {service: 'Connectivity', capabilitytype: 'DistributedRouter', capabilityvalue: true} + - {service: 'Connectivity', capabilitytype: 'RegionLevelVPC', capabilityvalue: true} + register: vpcoffer +- name: verify results of create enabled region level vpc offer with distrubuted router + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + - vpcoffer.name == "{{ cs_resource_prefix }}_vpc_drl" + - vpcoffer.state == "Enabled" + - vpcoffer.display_text == "vpc offering description" + - vpcoffer.distributed == true + - vpcoffer.region_level == true + +- name: remove vpc offer + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc" + state: absent + register: vpcoffer +- name: verify results of remove vpc offer + assert: + that: + - vpcoffer is successful + - vpcoffer is changed + +- name: remove region level vpc offer with distrubuted router + cs_vpc_offering: + name: "{{ cs_resource_prefix }}_vpc_drl" + state: absent + register: vpcoffer +- name: verify results of remove region level vpc offer with distrubuted router + assert: + that: + - vpcoffer is successful + - vpcoffer is changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml new file mode 100644 index 00000000..97e1d941 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_connection/tasks/main.yml @@ -0,0 +1,205 @@ +--- +- name: setup vpc + cs_vpc: + name: my_vpc + display_text: my_vpc + cidr: 10.10.1.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup customer gateway + cs_vpn_customer_gateway: + name: my_vpn_customer_gateway + cidr: 192.168.123.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.11.1.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y¼ + esp_lifetime: 3600 + register: vcg +- name: setup customer gateway + assert: + that: + - vcg is successful + +- name: setup remove vpn connection + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_conn +- name: verify setup remove vpn connection + assert: + that: + - vpn_conn is successful + +- name: setup vpn gateway absent + cs_vpn_gateway: + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_gateway +- name: verify setup vpn gateway absent + assert: + that: + - vpn_gateway is successful + +- name: test fail create vpn connection without gateway and force + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + ignore_errors: yes + register: vpn_conn +- name: verify test fail create vpn connection without gateway and force + assert: + that: + - vpn_conn is failed + - vpn_conn.msg == "VPN gateway not found and not forced to create one" + +- name: test create vpn connection with force in check mode + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + force: yes + zone: "{{ cs_common_zone_adv }}" + check_mode: yes + register: vpn_conn +- name: verify test create vpn connection with force in check mode + assert: + that: + - vpn_conn is changed + +- name: test create vpn connection with force + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + force: yes + zone: "{{ cs_common_zone_adv }}" + register: vpn_conn +- name: verify test create vpn connection with force + assert: + that: + - vpn_conn is changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: test create vpn connection with force idempotence + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + force: yes + zone: "{{ cs_common_zone_adv }}" + register: vpn_conn +- name: verify test create vpn connection with force idempotence + assert: + that: + - vpn_conn is not changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: test remove vpn connection in check mode + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + check_mode: yes + register: vpn_conn +- name: verify test remove vpn connection in check mode + assert: + that: + - vpn_conn is changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: test remove vpn connection + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_conn +- name: verify test remove vpn connection + assert: + that: + - vpn_conn is changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: test remove vpn connection idempotence + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_conn +- name: verify test remove vpn connection idempotence + assert: + that: + - vpn_conn is not changed + +- name: setup create vpn gateway + cs_vpn_gateway: + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + register: vpn_gateway +- name: verify setup create vpn gateway + assert: + that: + - vpn_gateway is success + +- name: test create vpn connection without force in check mode + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + check_mode: yes + register: vpn_conn +- name: verify test create vpn connection without force in check mode + assert: + that: + - vpn_conn is changed + +- name: test create vpn connection without force + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + register: vpn_conn +- name: verify test create vpn connection without force + assert: + that: + - vpn_conn is changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: test create vpn connection without force + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + register: vpn_conn +- name: verify test create vpn connection without force + assert: + that: + - vpn_conn is not changed + - vpn_conn.vpn_customer_gateway == "my_vpn_customer_gateway" + - vpn_conn.vpc == "my_vpc" + +- name: cleanup remove vpn connection + cs_vpn_connection: + vpn_customer_gateway: my_vpn_customer_gateway + vpc: my_vpc + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_conn +- name: verify cleanup remove vpn connection idempotence + assert: + that: + - vpn_conn is successful diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml new file mode 100644 index 00000000..d18d4b6f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_customer_gateway/tasks/main.yml @@ -0,0 +1,208 @@ +--- +- name: setup vpn customer gateway absent + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + state: absent + register: vcg +- name: verify setup vpn customer gateway absent + assert: + that: + - vcg is successful + +- name: test create vpn customer gateway in check mode + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidr: 192.168.123.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.0.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y¼ + esp_lifetime: 3600 + check_mode: true + register: vcg +- name: verify test create vpn customer gateway in check mode + assert: + that: + - vcg is changed + +- name: test create vpn customer gateway + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidr: 192.168.123.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.0.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y¼ + esp_lifetime: 3600 + register: vcg +- name: verify test create vpn customer gateway + assert: + that: + - vcg is changed + - "vcg.cidrs == ['192.168.123.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 3600 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == false + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.0.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 86400 + +- name: test create vpn customer gateway idempotency + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidr: 192.168.123.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.0.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y¼ + esp_lifetime: 3600 + register: vcg +- name: verify test create vpn customer gateway idempotency + assert: + that: + - vcg is not changed + - "vcg.cidrs == ['192.168.123.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 3600 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == false + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.0.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 86400 + +- name: test update vpn customer gateway in check mode + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidrs: + - 192.168.123.0/24 + - 192.168.124.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.1.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y@ + esp_lifetime: 1800 + ike_lifetime: 23200 + force_encap: true + check_mode: true + register: vcg +- name: verify test update vpn customer gateway in check mode + assert: + that: + - vcg is changed + - "vcg.cidrs == ['192.168.123.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 3600 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == false + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.0.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 86400 + +- name: test update vpn customer gateway + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidrs: + - 192.168.123.0/24 + - 192.168.124.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.1.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y@ + esp_lifetime: 1800 + ike_lifetime: 23200 + force_encap: true + register: vcg +- name: verify test update vpn customer gateway + assert: + that: + - vcg is changed + - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 1800 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == true + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.1.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 23200 + +- name: test update vpn customer gateway idempotence + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + cidrs: + - 192.168.123.0/24 + - 192.168.124.0/24 + esp_policy: aes256-sha1;modp1536 + gateway: 10.10.1.1 + ike_policy: aes256-sha1;modp1536 + ipsec_psk: ~S3¢r3Tk3Y@ + esp_lifetime: 1800 + ike_lifetime: 23200 + force_encap: true + register: vcg +- name: verify test update vpn customer gateway idempotence + assert: + that: + - vcg is not changed + - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 1800 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == true + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.1.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 23200 + +- name: test remove vpn customer gateway in check mode + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + state: absent + check_mode: true + register: vcg +- name: verify test remove vpn customer gateway in check mode + assert: + that: + - vcg is changed + - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 1800 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == true + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.1.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 23200 + +- name: test remove vpn customer gateway + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + state: absent + register: vcg +- name: verify test remove vpn customer gateway + assert: + that: + - vcg is changed + - "vcg.cidrs == ['192.168.123.0/24', '192.168.124.0/24']" + - vcg.dpd == false + - vcg.esp_lifetime == 1800 + - vcg.esp_policy == 'aes256-sha1;modp1536' + - vcg.force_encap == true + - vcg.ike_policy == 'aes256-sha1;modp1536' + - vcg.gateway == '10.10.1.1' + - vcg.name == 'ansible_vpn_customer_gw' + - vcg.ike_lifetime == 23200 + +- name: test remove vpn customer gateway idempotence + cs_vpn_customer_gateway: + name: ansible_vpn_customer_gw + state: absent + register: vcg +- name: verify test remove vpn customer gateway idempotence + assert: + that: + - vcg is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml new file mode 100644 index 00000000..2dd7a445 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_vpn_gateway/tasks/main.yml @@ -0,0 +1,108 @@ +--- +- name: setup vpc + cs_vpc: + name: "{{ cs_resource_prefix }}_vpc" + display_text: "{{ cs_resource_prefix }}_display_text" + cidr: 10.10.0.0/16 + zone: "{{ cs_common_zone_adv }}" + register: vpc +- name: verify setup vpc + assert: + that: + - vpc is successful + +- name: setup vpn gateway absent + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_gateway +- name: verify setup vpn gateway absent + assert: + that: + - vpn_gateway is successful + +- name: test fail missing param vpc for vpn gateway + cs_vpn_gateway: + ignore_errors: true + register: vpn_gateway +- name: verify test fail missing param vpc for vpn gateway + assert: + that: + - vpn_gateway is failed + - "vpn_gateway.msg.startswith('missing required arguments: ')" + +- name: test create vpn gateway in check mode + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: vpn_gateway + check_mode: true +- name: verify test create vpn gateway in check mode + assert: + that: + - vpn_gateway is successful + - vpn_gateway is changed + +- name: test create vpn gateway + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: vpn_gateway +- name: verify test create vpn gateway + assert: + that: + - vpn_gateway is successful + - vpn_gateway is changed + - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc" + +- name: test create vpn gateway idempotence + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + register: vpn_gateway +- name: verify test create vpn gateway idempotence + assert: + that: + - vpn_gateway is successful + - vpn_gateway is not changed + - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc" + +- name: test remove vpn gateway in check mode + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_gateway + check_mode: true +- name: verify test remove vpn gateway in check mode + assert: + that: + - vpn_gateway is successful + - vpn_gateway is changed + - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc" + +- name: test remove vpn gateway + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_gateway +- name: verify test remove vpn gateway + assert: + that: + - vpn_gateway is successful + - vpn_gateway is changed + - vpn_gateway.vpc == "{{ cs_resource_prefix }}_vpc" + +- name: test remove vpn gateway idempotence + cs_vpn_gateway: + vpc: "{{ cs_resource_prefix }}_vpc" + zone: "{{ cs_common_zone_adv }}" + state: absent + register: vpn_gateway +- name: verify test remove vpn gateway idempotence + assert: + that: + - vpn_gateway is successful + - vpn_gateway is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases new file mode 100644 index 00000000..a315c1b5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/aliases @@ -0,0 +1,2 @@ +cloud/cs +shippable/cs/group2 diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml new file mode 100644 index 00000000..9137db44 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone/tasks/main.yml @@ -0,0 +1,205 @@ +--- +- name: setup zone is absent + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + state: absent + register: zone +- name: verify setup zone absent + assert: + that: + - zone is successful + +- name: test fail missing param + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + register: zone + ignore_errors: true +- name: verify test fail missing param + assert: + that: + - zone is failed + - "zone.msg == 'missing required arguments: dns1'" + +- name: test create zone in check mode + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone + check_mode: true +- name: verify test create zone in check mode + assert: + that: + - zone is successful + - zone is changed + +- name: test create zone + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone +- name: verify test create zone + assert: + that: + - zone is successful + - zone is changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "8.8.8.8" + - zone.internal_dns2 == "8.8.4.4" + - zone.local_storage_enabled == false + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + - zone.dhcp_provider == "VirtualRouter" + +- name: test create zone idempotency + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone +- name: verify test create zone idempotency + assert: + that: + - zone is successful + - zone is not changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "8.8.8.8" + - zone.internal_dns2 == "8.8.4.4" + - zone.local_storage_enabled == false + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + - zone.dhcp_provider == "VirtualRouter" + +- name: test update zone in check mode + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + internal_dns1: 10.10.1.100 + internal_dns2: 10.10.1.101 + local_storage_enabled: true + network_type: Basic + register: zone + check_mode: true +- name: verify test update zone in check mode + assert: + that: + - zone is successful + - zone is changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "8.8.8.8" + - zone.internal_dns2 == "8.8.4.4" + - zone.local_storage_enabled == false + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + - zone.dhcp_provider == "VirtualRouter" + +- name: test update zone + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + internal_dns1: 10.10.1.100 + internal_dns2: 10.10.1.101 + local_storage_enabled: true + network_type: Basic + register: zone +- name: verify test update zone + assert: + that: + - zone is successful + - zone is changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "10.10.1.100" + - zone.internal_dns2 == "10.10.1.101" + - zone.local_storage_enabled == true + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + - zone.dhcp_provider == "VirtualRouter" + +- name: test update zone idempotency + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + internal_dns1: 10.10.1.100 + internal_dns2: 10.10.1.101 + local_storage_enabled: true + network_type: Basic + register: zone +- name: verify test update zone idempotency + assert: + that: + - zone is successful + - zone is not changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "10.10.1.100" + - zone.internal_dns2 == "10.10.1.101" + - zone.local_storage_enabled == true + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + - zone.dhcp_provider == "VirtualRouter" + +- name: test absent zone in check mode + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + state: absent + register: zone + check_mode: true +- name: verify test absent zone in check mode + assert: + that: + - zone is successful + - zone is changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "10.10.1.100" + - zone.internal_dns2 == "10.10.1.101" + - zone.local_storage_enabled == true + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + +- name: test absent zone + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + state: absent + register: zone +- name: verify test absent zone + assert: + that: + - zone is successful + - zone is changed + - zone.dns1 == "8.8.8.8" + - zone.dns2 == "8.8.4.4" + - zone.internal_dns1 == "10.10.1.100" + - zone.internal_dns2 == "10.10.1.101" + - zone.local_storage_enabled == true + - zone.network_type == "Basic" + - zone.zone_token != "" + - zone.securitygroups_enabled == true + +- name: test absent zone idempotency + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + state: absent + register: zone +- name: verify test absent zone idempotency + assert: + that: + - zone is successful + - zone is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases new file mode 100644 index 00000000..3b5a38e7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/aliases @@ -0,0 +1,3 @@ +cloud/cs +shippable/cs/group2 +shippable/cs/smoketest diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml new file mode 100644 index 00000000..e9a5b9ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - cs_common diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml new file mode 100644 index 00000000..74dccf80 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/integration/targets/cs_zone_info/tasks/main.yml @@ -0,0 +1,73 @@ +--- +- name: setup zone is present + cs_zone: + name: "{{ cs_resource_prefix }}-zone" + dns1: 8.8.8.8 + dns2: 8.8.4.4 + network_type: Basic + register: zone +- name: verify setup zone is present + assert: + that: + - zone is successful + +- name: get info from zone in check mode + cs_zone_info: + name: "{{ cs_resource_prefix }}-zone" + register: zone + check_mode: yes +- name: verify get info from zone in check mode + assert: + that: + - zone is successful + - zone is not changed + - zone.zones[0].dns1 == "8.8.8.8" + - zone.zones[0].dns2 == "8.8.4.4" + - zone.zones[0].internal_dns1 == "8.8.8.8" + - zone.zones[0].internal_dns2 == "8.8.4.4" + - zone.zones[0].local_storage_enabled == false + - zone.zones[0].network_type == "Basic" + - zone.zones[0].zone_token != "" + - zone.zones[0].securitygroups_enabled == true + - zone.zones[0].dhcp_provider == "VirtualRouter" + - zone.zones[0].local_storage_enabled == false + +- name: get info from zone + cs_zone_info: + name: "{{ cs_resource_prefix }}-zone" + register: zone +- name: verify get info from zone + assert: + that: + - zone is successful + - zone is not changed + - zone.zones[0].dns1 == "8.8.8.8" + - zone.zones[0].dns2 == "8.8.4.4" + - zone.zones[0].internal_dns1 == "8.8.8.8" + - zone.zones[0].internal_dns2 == "8.8.4.4" + - zone.zones[0].local_storage_enabled == false + - zone.zones[0].network_type == "Basic" + - zone.zones[0].zone_token != "" + - zone.zones[0].securitygroups_enabled == true + - zone.zones[0].dhcp_provider == "VirtualRouter" + - zone.zones[0].local_storage_enabled == false + +- name: get info from all zones + cs_zone_info: + register: zones +- name: verify get info from all zones + assert: + that: + - zones is successful + - zones is not changed + - zones.zones | length > 0 + - '"dns1" in zone.zones[0]' + - '"dns2" in zone.zones[0]' + - '"internal_dns1" in zone.zones[0]' + - '"internal_dns2" in zone.zones[0]' + - '"local_storage_enabled" in zone.zones[0]' + - '"network_type" in zone.zones[0]' + - '"zone_token" in zone.zones[0]' + - '"securitygroups_enabled" in zone.zones[0]' + - '"dhcp_provider" in zone.zones[0]' + - '"local_storage_enabled" in zone.zones[0]' diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.10.txt diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/ignore-2.9.txt diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt new file mode 100644 index 00000000..3e3a9669 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/sanity/requirements.txt @@ -0,0 +1,4 @@ +packaging # needed for update-bundled and changelog +sphinx ; python_version >= '3.5' # docs build requires python 3+ +sphinx-notfound-page ; python_version >= '3.5' # docs build requires python 3+ +straight.plugin ; python_version >= '3.5' # needed for hacking/build-ansible.py which will host changelog generation and requires python 3+ diff --git a/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py new file mode 100644 index 00000000..0747b7ad --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/cloudstack/tests/unit/modules/test_cs_traffic_type.py @@ -0,0 +1,135 @@ +from __future__ import (absolute_import, division, print_function) +import sys +import pytest +import units.compat.unittest as unittest +from units.compat.mock import MagicMock +from units.compat.unittest import TestCase +from units.modules.utils import set_module_args + +__metaclass__ = type + + +# Exoscale's cs doesn't support Python 2.6 +pytestmark = [] +if sys.version_info[:2] != (2, 6): + from ansible.modules.cloud.cloudstack.cs_traffic_type import AnsibleCloudStackTrafficType, setup_module_object + from ansible.module_utils.cloudstack import HAS_LIB_CS + if not HAS_LIB_CS: + pytestmark.append(pytest.mark.skip('The cloudstack library, "cs", is needed to test cs_traffic_type')) +else: + pytestmark.append(pytest.mark.skip('Exoscale\'s cs doesn\'t support Python 2.6')) + + +EXISTING_TRAFFIC_TYPES_RESPONSE = { + "count": 3, + "traffictype": [ + { + "id": "9801cf73-5a73-4883-97e4-fa20c129226f", + "kvmnetworklabel": "cloudbr0", + "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c", + "traffictype": "Management" + }, + { + "id": "28ed70b7-9a1f-41bf-94c3-53a9f22da8b6", + "kvmnetworklabel": "cloudbr0", + "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c", + "traffictype": "Guest" + }, + { + "id": "9c05c802-84c0-4eda-8f0a-f681364ffb46", + "kvmnetworklabel": "cloudbr0", + "physicalnetworkid": "659c1840-9374-440d-a412-55ca360c9d3c", + "traffictype": "Storage" + } + ] +} + +VALID_LIST_NETWORKS_RESPONSE = { + "count": 1, + "physicalnetwork": [ + { + "broadcastdomainrange": "ZONE", + "id": "659c1840-9374-440d-a412-55ca360c9d3c", + "name": "eth1", + "state": "Enabled", + "vlan": "3900-4000", + "zoneid": "49acf813-a8dd-4da0-aa53-1d826d6003e7" + } + ] +} + +VALID_LIST_ZONES_RESPONSE = { + "count": 1, + "zone": [ + { + "allocationstate": "Enabled", + "dhcpprovider": "VirtualRouter", + "dns1": "8.8.8.8", + "dns2": "8.8.4.4", + "guestcidraddress": "10.10.0.0/16", + "id": "49acf813-a8dd-4da0-aa53-1d826d6003e7", + "internaldns1": "192.168.56.1", + "localstorageenabled": True, + "name": "DevCloud-01", + "networktype": "Advanced", + "securitygroupsenabled": False, + "tags": [], + "zonetoken": "df20d65a-c6c8-3880-9064-4f77de2291ef" + } + ] +} + + +base_module_args = { + "api_key": "api_key", + "api_secret": "very_secret_content", + "api_url": "http://localhost:8888/api/client", + "kvm_networklabel": "cloudbr0", + "physical_network": "eth1", + "poll_async": True, + "state": "present", + "traffic_type": "Guest", + "zone": "DevCloud-01" +} + + +class TestAnsibleCloudstackTraffiType(TestCase): + + def test_module_is_created_sensibly(self): + set_module_args(base_module_args) + module = setup_module_object() + assert module.params['traffic_type'] == 'Guest' + + def test_update_called_when_traffic_type_exists(self): + set_module_args(base_module_args) + module = setup_module_object() + actt = AnsibleCloudStackTrafficType(module) + actt.get_traffic_type = MagicMock(return_value=EXISTING_TRAFFIC_TYPES_RESPONSE['traffictype'][0]) + actt.update_traffic_type = MagicMock() + actt.present_traffic_type() + self.assertTrue(actt.update_traffic_type.called) + + def test_update_not_called_when_traffic_type_doesnt_exist(self): + set_module_args(base_module_args) + module = setup_module_object() + actt = AnsibleCloudStackTrafficType(module) + actt.get_traffic_type = MagicMock(return_value=None) + actt.update_traffic_type = MagicMock() + actt.add_traffic_type = MagicMock() + actt.present_traffic_type() + self.assertFalse(actt.update_traffic_type.called) + self.assertTrue(actt.add_traffic_type.called) + + def test_traffic_type_returned_if_exists(self): + set_module_args(base_module_args) + module = setup_module_object() + actt = AnsibleCloudStackTrafficType(module) + actt.get_physical_network = MagicMock(return_value=VALID_LIST_NETWORKS_RESPONSE['physicalnetwork'][0]) + actt.get_traffic_types = MagicMock(return_value=EXISTING_TRAFFIC_TYPES_RESPONSE) + tt = actt.present_traffic_type() + self.assertTrue(tt.get('kvmnetworklabel') == base_module_args['kvm_networklabel']) + self.assertTrue(tt.get('traffictype') == base_module_args['traffic_type']) + + +if __name__ == '__main__': + unittest.main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/publish.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/publish.yml new file mode 100644 index 00000000..0318edfc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/publish.yml @@ -0,0 +1,25 @@ +name: Upload release to Galaxy + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ansible + - name: Build and publish + env: + ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} + run: | + ansible-galaxy collection build . + ansible-galaxy collection publish *.tar.gz --api-key $ANSIBLE_GALAXY_API_KEY diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/sanity.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/sanity.yml new file mode 100644 index 00000000..7e0fab5b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/.github/workflows/sanity.yml @@ -0,0 +1,31 @@ +name: Sanity +on: +- pull_request + +jobs: + sanity: + name: Sanity (${{ matrix.ansible }}) + strategy: + matrix: + ansible: + - stable-2.10 + - stable-2.9 + - devel + runs-on: ubuntu-latest + steps: + + - name: Check out code + uses: actions/checkout@v1 + with: + path: ansible_collections/ngine_io/exoscale + + - name: Set up Python 3.6 + uses: actions/setup-python@v1 + with: + python-version: 3.6 + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + - name: Run sanity tests + run: ansible-test sanity --docker -v --color --python 3.6 diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/CHANGELOG.rst b/collections-debian-merged/ansible_collections/ngine_io/exoscale/CHANGELOG.rst new file mode 100644 index 00000000..54909f89 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/CHANGELOG.rst @@ -0,0 +1,9 @@ +========================================= +Exoscale Ansible Collection Release Notes +========================================= + +.. contents:: Topics + + +v1.0.0 +====== diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/CONTRIBUTING.md b/collections-debian-merged/ansible_collections/ngine_io/exoscale/CONTRIBUTING.md new file mode 100644 index 00000000..44683c13 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# Contributing + +Any contribution is welcome and we only ask contributors to: + +- Create an issues for any significant contribution that would change a large portion of the code base. +- Provide at least integration tests for any contribution diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/FILES.json b/collections-debian-merged/ansible_collections/ngine_io/exoscale/FILES.json new file mode 100644 index 00000000..f725ab2d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/FILES.json @@ -0,0 +1,250 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy/roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy/roles/test_exoscale_dns", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy/roles/test_exoscale_dns/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy/roles/test_exoscale_dns/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4e0ebd8ef1cdaf150fbcf76859542f017fc0203ca642dff07f0600337760491b", + "format": 1 + }, + { + "name": "tests/legacy/roles/test_exoscale_dns/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/legacy/roles/test_exoscale_dns/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed720423a1d55815026eca860e4b39dd0f6609775f2cab3c07642720a3c448d7", + "format": 1 + }, + { + "name": "tests/legacy/exoscale.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "38d542d66924d6e8fd7991ffc2e73544cfd7f88cdd4734ba47734b8ec86ea3fb", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f3a697694dc57ace9e8600b5b2afbff42deeb76739d55cf66d844aec1ebb5dbf", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d61725d614410e2ee0a900fb0f6b6d742ad8fb689ae27c4d6a3a7f89e82fc791", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "65ddf4c03edf730c4bf7da2184d83dfd28e790cb816ef1f9d82904273cb0c854", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "476a74dcdd9be0337c38135c7ab2f0f65de2ab4fdff679ceaa66b04f3e844811", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/doc_fragments/exoscale.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c484b770aa74ea4fbd70bf2f673af2e7f469ad732e818223152a356a5b9fd861", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/exoscale.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "27754664282f766b3ad37dde8ac45d67495e3bc599e4bfa4a089a11819038311", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/exo_dns_domain.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fe708671d29b57cdf89f39aee4b0f81672db58030a92b832bf6b78008e080b80", + "format": 1 + }, + { + "name": "plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/modules/exo_dns_record.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "920ee4da3ced628cec9e998467ec04cd84db296b47e36225cf0693445fa483a9", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6077ffbd67c5ad687d45cb43010521973fe662e82c2f167c5121016803861cea", + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.keep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "919ef00776e7d2ff349950ac4b806132aa9faf006e214d5285de54533e443b33", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2dbaa843cb55fda031c7fa291a37ff6a59c596763cce1eaf97fd72b3a1761d92", + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/publish.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c529e2810ae1f02ea98dcae1b78241d21a5988496ed5389b2ce8c37395323756", + "format": 1 + }, + { + "name": ".github/workflows/sanity.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "33964a78f085244db7db9904c39776a726cd4cfef48c3b1dcb5e1cf57714d223", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/MANIFEST.json b/collections-debian-merged/ansible_collections/ngine_io/exoscale/MANIFEST.json new file mode 100644 index 00000000..acebe157 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/MANIFEST.json @@ -0,0 +1,35 @@ +{ + "collection_info": { + "namespace": "ngine_io", + "name": "exoscale", + "version": "1.0.0", + "authors": [ + "Ren\u00e9 Moser <mail@renemoser.net>" + ], + "readme": "README.md", + "tags": [ + "cloud", + "dns", + "exoscale", + "ngine_io" + ], + "description": "Ansible Collection for Exoscale", + "license": [ + "GPL-3.0-or-later" + ], + "license_file": null, + "dependencies": {}, + "repository": "https://github.com/ngine-io/ansible-collection-exoscale", + "documentation": "", + "homepage": "https://github.com/ngine-io/ansible-collection-exoscale", + "issues": "https://github.com/ngine-io/ansible-collection-exoscale/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dbbe7cf8b0656632d858a3bcec7ed6049ee30663c1ed9488392b80c53311d4a4", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/README.md b/collections-debian-merged/ansible_collections/ngine_io/exoscale/README.md new file mode 100644 index 00000000..824f6b77 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/README.md @@ -0,0 +1,72 @@ +![Collection integration](https://github.com/ngine-io/ansible-collection-exoscale/workflows/Collection%20integration/badge.svg) + [![Codecov](https://img.shields.io/codecov/c/github/ngine-io/ansible-collection-exoscale)](https://codecov.io/gh/ngine-io/ansible-collection-exoscale) +[![License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](LICENSE) + +# Ansible Collection for exoscale Cloud + +This collection provides a series of Ansible modules and plugins for interacting with the [exoscale](https://www.exoscale.com) Cloud. + +## Requirements + +- ansible version >= 2.9 + +## Installation + +To install the collection hosted in Galaxy: + +```bash +ansible-galaxy collection install ngine_io.exoscale +``` + +To upgrade to the latest version of the collection: + +```bash +ansible-galaxy collection install ngine_io.exoscale --force +``` + +## Usage + +### Playbooks + +To use a module from exoscale collection, please reference the full namespace, collection name, and modules name that you want to use: + +```yaml +--- +- name: Using exoscale collection + hosts: localhost + tasks: + - ngine_io.exoscale.<module>: + ... +``` + +Or you can add full namepsace and collecton name in the `collections` element: + +```yaml +--- +- name: Using exoscale collection + hosts: localhost + collections: + - ngine_io.exoscale + tasks: + - <module>: + ... +``` + +### Roles + +For existing Ansible roles, please also reference the full namespace, collection name, and modules name which used in tasks instead of just modules name. + +## Contributing + +There are many ways in which you can participate in the project, for example: + +- Submit bugs and feature requests, and help us verify as they are checked in +- Review source code changes +- Review the documentation and make pull requests for anything from typos to new content +- If you are interested in fixing issues and contributing directly to the code base, please see the [CONTRIBUTING](CONTRIBUTING.md) document. + +## License + +GNU General Public License v3.0 + +See [COPYING](COPYING) to see the full text. diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/.gitignore b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/.gitignore new file mode 100644 index 00000000..6be6b533 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/.gitignore @@ -0,0 +1 @@ +/.plugin-cache.yaml diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/changelog.yaml new file mode 100644 index 00000000..4eef701c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/changelog.yaml @@ -0,0 +1,4 @@ +ancestor: null +releases: + 1.0.0: + release_date: '2020-08-15' diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/config.yaml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/config.yaml new file mode 100644 index 00000000..969c215e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/config.yaml @@ -0,0 +1,30 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +keep_fragments: false +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: Exoscale Ansible Collection +trivial_section_name: trivial +use_fqcn: true diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/fragments/.keep b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/fragments/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/changelogs/fragments/.keep diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/meta/runtime.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/meta/runtime.yml new file mode 100644 index 00000000..cf7c04dc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/meta/runtime.yml @@ -0,0 +1,5 @@ +requires_ansible: '>=2.9.10' +action_groups: + exoscale: + - exo_dns_domain + - exo_dns_record diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/exoscale.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/exoscale.py new file mode 100644 index 00000000..52ea2cd4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/doc_fragments/exoscale.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Standard exoscale documentation fragment + DOCUMENTATION = r''' +options: + api_key: + description: + - API key of the Exoscale DNS API. + - The ENV variable C(CLOUDSTACK_KEY) is used as default, when defined. + type: str + api_secret: + description: + - Secret key of the Exoscale DNS API. + - The ENV variable C(CLOUDSTACK_SECRET) is used as default, when defined. + type: str + api_timeout: + description: + - HTTP timeout to Exoscale DNS API. + - The ENV variable C(CLOUDSTACK_TIMEOUT) is used as default, when defined. + type: int + default: 10 + api_region: + description: + - Name of the ini section in the C(cloustack.ini) file. + - The ENV variable C(CLOUDSTACK_REGION) is used as default, when defined. + type: str + default: cloudstack + validate_certs: + description: + - Validate SSL certs of the Exoscale DNS API. + type: bool + default: yes +requirements: + - python >= 2.6 +notes: + - As Exoscale DNS uses the same API key and secret for all services, we reuse the config used for Exscale Compute based on CloudStack. + The config is read from several locations, in the following order. + The C(CLOUDSTACK_KEY), C(CLOUDSTACK_SECRET) environment variables. + A C(CLOUDSTACK_CONFIG) environment variable pointing to an C(.ini) file, + A C(cloudstack.ini) file in the current working directory. + A C(.cloudstack.ini) file in the users home directory. + Optionally multiple credentials and endpoints can be specified using ini sections in C(cloudstack.ini). + Use the argument C(api_region) to select the section name, default section is C(cloudstack). + - This module does not support multiple A records and will complain properly if you try. + - More information Exoscale DNS can be found on https://community.exoscale.ch/documentation/dns/. + - This module supports check mode and diff. +''' diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/module_utils/exoscale.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/module_utils/exoscale.py new file mode 100644 index 00000000..44933b1b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/module_utils/exoscale.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import os + +from ansible.module_utils.six.moves import configparser +from ansible.module_utils.six import integer_types, string_types +from ansible.module_utils._text import to_native, to_text +from ansible.module_utils.urls import fetch_url + +EXO_DNS_BASEURL = "https://api.exoscale.ch/dns/v1" + + +def exo_dns_argument_spec(): + return dict( + api_key=dict(type='str', default=os.environ.get('CLOUDSTACK_KEY'), no_log=True), + api_secret=dict(type='str', default=os.environ.get('CLOUDSTACK_SECRET'), no_log=True), + api_timeout=dict(type='int', default=os.environ.get('CLOUDSTACK_TIMEOUT') or 10), + api_region=dict(type='str', default=os.environ.get('CLOUDSTACK_REGION') or 'cloudstack'), + validate_certs=dict(default=True, type='bool'), + ) + + +def exo_dns_required_together(): + return [['api_key', 'api_secret']] + + +class ExoDns(object): + + def __init__(self, module): + self.module = module + + self.api_key = self.module.params.get('api_key') + self.api_secret = self.module.params.get('api_secret') + if not (self.api_key and self.api_secret): + try: + region = self.module.params.get('api_region') + config = self.read_config(ini_group=region) + self.api_key = config['key'] + self.api_secret = config['secret'] + except Exception as e: + self.module.fail_json(msg="Error while processing config: %s" % to_native(e)) + + self.headers = { + 'X-DNS-Token': "%s:%s" % (self.api_key, self.api_secret), + 'Content-Type': 'application/json', + 'Accept': 'application/json', + } + self.result = { + 'changed': False, + 'diff': { + 'before': {}, + 'after': {}, + } + } + + def read_config(self, ini_group=None): + if not ini_group: + ini_group = os.environ.get('CLOUDSTACK_REGION', 'cloudstack') + + keys = ['key', 'secret'] + env_conf = {} + for key in keys: + if 'CLOUDSTACK_%s' % key.upper() not in os.environ: + break + else: + env_conf[key] = os.environ['CLOUDSTACK_%s' % key.upper()] + else: + return env_conf + + # Config file: $PWD/cloudstack.ini or $HOME/.cloudstack.ini + # Last read wins in configparser + paths = ( + os.path.join(os.path.expanduser('~'), '.cloudstack.ini'), + os.path.join(os.getcwd(), 'cloudstack.ini'), + ) + # Look at CLOUDSTACK_CONFIG first if present + if 'CLOUDSTACK_CONFIG' in os.environ: + paths += (os.path.expanduser(os.environ['CLOUDSTACK_CONFIG']),) + if not any([os.path.exists(c) for c in paths]): + self.module.fail_json(msg="Config file not found. Tried : %s" % ", ".join(paths)) + + conf = configparser.ConfigParser() + conf.read(paths) + return dict(conf.items(ini_group)) + + def api_query(self, resource="/domains", method="GET", data=None): + url = EXO_DNS_BASEURL + resource + if data: + data = self.module.jsonify(data) + + response, info = fetch_url( + module=self.module, + url=url, + data=data, + method=method, + headers=self.headers, + timeout=self.module.params.get('api_timeout'), + ) + + if info['status'] not in (200, 201, 204): + self.module.fail_json(msg="%s returned %s, with body: %s" % (url, info['status'], info['msg'])) + + try: + return self.module.from_json(to_text(response.read())) + + except Exception as e: + self.module.fail_json(msg="Could not process response into json: %s" % to_native(e)) + + def has_changed(self, want_dict, current_dict, only_keys=None): + changed = False + for key, value in want_dict.items(): + # Optionally limit by a list of keys + if only_keys and key not in only_keys: + continue + # Skip None values + if value is None: + continue + if key in current_dict: + if isinstance(current_dict[key], integer_types): + if value != current_dict[key]: + self.result['diff']['before'][key] = current_dict[key] + self.result['diff']['after'][key] = value + changed = True + elif isinstance(current_dict[key], string_types): + if value.lower() != current_dict[key].lower(): + self.result['diff']['before'][key] = current_dict[key] + self.result['diff']['after'][key] = value + changed = True + else: + self.module.fail_json(msg="Unable to determine comparison for key %s" % key) + else: + self.result['diff']['after'][key] = value + changed = True + return changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_domain.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_domain.py new file mode 100644 index 00000000..334c5c02 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_domain.py @@ -0,0 +1,204 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: exo_dns_domain +short_description: Manages domain records on Exoscale DNS API. +description: + - Create and remove domain records. +author: "René Moser (@resmo)" +version_added: "0.1.0" +options: + name: + description: + - Name of the record. + required: true + type: str + state: + description: + - State of the resource. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: ngine_io.exoscale.exoscale +''' + +EXAMPLES = ''' +- name: Create a domain + exo_dns_domain: + name: example.com + +- name: Remove a domain + exo_dns_domain: + name: example.com + state: absent +''' + +RETURN = ''' +--- +exo_dns_domain: + description: API domain results + returned: success + type: complex + contains: + account_id: + description: Your account ID + returned: success + type: int + sample: 34569 + auto_renew: + description: Whether domain is auto renewed or not + returned: success + type: bool + sample: false + created_at: + description: When the domain was created + returned: success + type: str + sample: "2016-08-12T15:24:23.989Z" + expires_on: + description: When the domain expires + returned: success + type: str + sample: "2016-08-12T15:24:23.989Z" + id: + description: ID of the domain + returned: success + type: int + sample: "2016-08-12T15:24:23.989Z" + lockable: + description: Whether the domain is lockable or not + returned: success + type: bool + sample: true + name: + description: Domain name + returned: success + type: str + sample: example.com + record_count: + description: Number of records related to this domain + returned: success + type: int + sample: 5 + registrant_id: + description: ID of the registrant + returned: success + type: int + sample: null + service_count: + description: Number of services + returned: success + type: int + sample: 0 + state: + description: State of the domain + returned: success + type: str + sample: "hosted" + token: + description: Token + returned: success + type: str + sample: "r4NzTRp6opIeFKfaFYvOd6MlhGyD07jl" + unicode_name: + description: Domain name as unicode + returned: success + type: str + sample: "example.com" + updated_at: + description: When the domain was updated last. + returned: success + type: str + sample: "2016-08-12T15:24:23.989Z" + user_id: + description: ID of the user + returned: success + type: int + sample: null + whois_protected: + description: Whether the whois is protected or not + returned: success + type: bool + sample: false +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.exoscale import ExoDns, exo_dns_argument_spec, exo_dns_required_together + + +class ExoDnsDomain(ExoDns): + + def __init__(self, module): + super(ExoDnsDomain, self).__init__(module) + self.name = self.module.params.get('name').lower() + + def get_domain(self): + domains = self.api_query("/domains", "GET") + for z in domains: + if z['domain']['name'].lower() == self.name: + return z + return None + + def present_domain(self): + domain = self.get_domain() + data = { + 'domain': { + 'name': self.name, + } + } + if not domain: + self.result['diff']['after'] = data['domain'] + self.result['changed'] = True + if not self.module.check_mode: + domain = self.api_query("/domains", "POST", data) + return domain + + def absent_domain(self): + domain = self.get_domain() + if domain: + self.result['diff']['before'] = domain + self.result['changed'] = True + if not self.module.check_mode: + self.api_query("/domains/%s" % domain['domain']['name'], "DELETE") + return domain + + def get_result(self, resource): + if resource: + self.result['exo_dns_domain'] = resource['domain'] + return self.result + + +def main(): + argument_spec = exo_dns_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=exo_dns_required_together(), + supports_check_mode=True + ) + + exo_dns_domain = ExoDnsDomain(module) + if module.params.get('state') == "present": + resource = exo_dns_domain.present_domain() + else: + resource = exo_dns_domain.absent_domain() + result = exo_dns_domain.get_result(resource) + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_record.py b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_record.py new file mode 100644 index 00000000..8da3491e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/plugins/modules/exo_dns_record.py @@ -0,0 +1,339 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: exo_dns_record +short_description: Manages DNS records on Exoscale DNS. +description: + - Create, update and delete records. +author: "René Moser (@resmo)" +version_added: "0.1.0" +options: + name: + description: + - Name of the record. + default: "" + type: str + domain: + description: + - Domain the record is related to. + required: true + type: str + record_type: + description: + - Type of the record. + default: A + choices: [ A, ALIAS, CNAME, MX, SPF, URL, TXT, NS, SRV, NAPTR, PTR, AAAA, SSHFP, HINFO, POOL ] + aliases: [ rtype, type ] + type: str + content: + description: + - Content of the record. + - Required if C(state=present) or C(multiple=yes). + aliases: [ value, address ] + type: str + ttl: + description: + - TTL of the record in seconds. + default: 3600 + type: int + prio: + description: + - Priority of the record. + aliases: [ priority ] + type: int + multiple: + description: + - Whether there are more than one records with similar I(name) and I(record_type). + - Only allowed for a few record types, e.g. C(record_type=A), C(record_type=NS) or C(record_type=MX). + - I(content) will not be updated, instead it is used as a key to find existing records. + type: bool + default: no + state: + description: + - State of the record. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: ngine_io.exoscale.exoscale +''' + +EXAMPLES = ''' +- name: Create or update an A record + ngine_io.exoscale.exo_dns_record: + name: web-vm-1 + domain: example.com + content: 1.2.3.4 + +- name: Update an existing A record with a new IP + ngine_io.exoscale.exo_dns_record: + name: web-vm-1 + domain: example.com + content: 1.2.3.5 + +- name: Create another A record with same name + ngine_io.exoscale.exo_dns_record: + name: web-vm-1 + domain: example.com + content: 1.2.3.6 + multiple: yes + +- name: Create or update a CNAME record + ngine_io.exoscale.exo_dns_record: + name: www + domain: example.com + record_type: CNAME + content: web-vm-1 + +- name: Create another MX record + ngine_io.exoscale.exo_dns_record: + domain: example.com + record_type: MX + content: mx1.example.com + prio: 10 + multiple: yes + +- name: Delete one MX record out of multiple + ngine_io.exoscale.exo_dns_record: + domain: example.com + record_type: MX + content: mx1.example.com + multiple: yes + state: absent + +- name: Remove a single A record + ngine_io.exoscale.exo_dns_record: + name: www + domain: example.com + state: absent +''' + +RETURN = ''' +--- +exo_dns_record: + description: API record results + returned: success + type: complex + contains: + content: + description: value of the record + returned: success + type: str + sample: 1.2.3.4 + created_at: + description: When the record was created + returned: success + type: str + sample: "2016-08-12T15:24:23.989Z" + domain: + description: Name of the domain + returned: success + type: str + sample: example.com + domain_id: + description: ID of the domain + returned: success + type: int + sample: 254324 + id: + description: ID of the record + returned: success + type: int + sample: 254324 + name: + description: name of the record + returned: success + type: str + sample: www + parent_id: + description: ID of the parent + returned: success + type: int + sample: null + prio: + description: Priority of the record + returned: success + type: int + sample: 10 + record_type: + description: Priority of the record + returned: success + type: str + sample: A + system_record: + description: Whether the record is a system record or not + returned: success + type: bool + sample: false + ttl: + description: Time to live of the record + returned: success + type: int + sample: 3600 + updated_at: + description: When the record was updated + returned: success + type: str + sample: "2016-08-12T15:24:23.989Z" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.exoscale import ExoDns, exo_dns_argument_spec, exo_dns_required_together + + +EXO_RECORD_TYPES = [ + 'A', + 'ALIAS', + 'CNAME', + 'MX', + 'SPF', + 'URL', + 'TXT', + 'NS', + 'SRV', + 'NAPTR', + 'PTR', + 'AAAA', + 'SSHFP', + 'HINFO', + 'POOL' +] + + +class ExoDnsRecord(ExoDns): + + def __init__(self, module): + super(ExoDnsRecord, self).__init__(module) + + self.domain = self.module.params.get('domain').lower() + self.name = self.module.params.get('name').lower() + if self.name == self.domain: + self.name = "" + + self.multiple = self.module.params.get('multiple') + self.record_type = self.module.params.get('record_type') + self.content = self.module.params.get('content') + + def _create_record(self, record): + self.result['changed'] = True + data = { + 'record': { + 'name': self.name, + 'record_type': self.record_type, + 'content': self.content, + 'ttl': self.module.params.get('ttl'), + 'prio': self.module.params.get('prio'), + } + } + self.result['diff']['after'] = data['record'] + if not self.module.check_mode: + record = self.api_query("/domains/%s/records" % self.domain, "POST", data) + return record + + def _update_record(self, record): + data = { + 'record': { + 'name': self.name, + 'content': self.content, + 'ttl': self.module.params.get('ttl'), + 'prio': self.module.params.get('prio'), + } + } + if self.has_changed(data['record'], record['record']): + self.result['changed'] = True + if not self.module.check_mode: + record = self.api_query("/domains/%s/records/%s" % (self.domain, record['record']['id']), "PUT", data) + return record + + def get_record(self): + domain = self.module.params.get('domain') + records = self.api_query("/domains/%s/records" % domain, "GET") + + result = {} + for r in records: + + if r['record']['record_type'] != self.record_type: + continue + + r_name = r['record']['name'].lower() + r_content = r['record']['content'] + + if r_name == self.name: + if not self.multiple: + if result: + self.module.fail_json(msg="More than one record with record_type=%s and name=%s params. " + "Use multiple=yes for more than one record." % (self.record_type, self.name)) + else: + result = r + elif r_content == self.content: + return r + + return result + + def present_record(self): + record = self.get_record() + if not record: + record = self._create_record(record) + else: + record = self._update_record(record) + return record + + def absent_record(self): + record = self.get_record() + if record: + self.result['diff']['before'] = record + self.result['changed'] = True + if not self.module.check_mode: + self.api_query("/domains/%s/records/%s" % (self.domain, record['record']['id']), "DELETE") + return record + + def get_result(self, resource): + if resource: + self.result['exo_dns_record'] = resource['record'] + self.result['exo_dns_record']['domain'] = self.domain + return self.result + + +def main(): + argument_spec = exo_dns_argument_spec() + argument_spec.update(dict( + name=dict(type='str', default=''), + record_type=dict(type='str', choices=EXO_RECORD_TYPES, aliases=['rtype', 'type'], default='A'), + content=dict(type='str', aliases=['value', 'address']), + multiple=(dict(type='bool', default=False)), + ttl=dict(type='int', default=3600), + prio=dict(type='int', aliases=['priority']), + domain=dict(type='str', required=True), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_together=exo_dns_required_together(), + required_if=[ + ('state', 'present', ['content']), + ('multiple', True, ['content']), + ], + supports_check_mode=True, + ) + + exo_dns_record = ExoDnsRecord(module) + if module.params.get('state') == "present": + resource = exo_dns_record.present_record() + else: + resource = exo_dns_record.absent_record() + + result = exo_dns_record.get_result(resource) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/exoscale.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/exoscale.yml new file mode 100644 index 00000000..dbe5bb16 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/exoscale.yml @@ -0,0 +1,6 @@ +--- +- hosts: localhost + gather_facts: no + roles: + - role: test_exoscale_dns + tags: test_exoscale_dns diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/defaults/main.yml new file mode 100644 index 00000000..a98c8690 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/defaults/main.yml @@ -0,0 +1,4 @@ +--- +exo_dns_domain_name: example.com +exo_dns_record_name_web: web +exo_dns_record_name_mx: mx diff --git a/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/tasks/main.yml new file mode 100644 index 00000000..1b0ecb6f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/exoscale/tests/legacy/roles/test_exoscale_dns/tasks/main.yml @@ -0,0 +1,347 @@ +--- +- name: setup + ngine_io.exoscale.exo_dns_domain: + name: "{{ exo_dns_domain_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is successful + +- name: test fail if missing name + ngine_io.exoscale.exo_dns_domain: + register: result + ignore_errors: true +- name: verify results of fail if missing params + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test create a domain + ngine_io.exoscale.exo_dns_domain: + name: "{{ exo_dns_domain_name }}" + register: result +- name: verify results of test create a domain + assert: + that: + - result is changed + - 'result.exo_dns_domain.name == "{{ exo_dns_domain_name }}"' + +- name: test create a domain idempotence + ngine_io.exoscale.exo_dns_domain: + name: "{{ exo_dns_domain_name }}" + register: result +- name: verify results of test create a domain idempotence + assert: + that: + - result is not changed + - 'result.exo_dns_domain.name == "{{ exo_dns_domain_name }}"' + +- name: test fail if missing required params + ngine_io.exoscale.exo_dns_record: + register: result + ignore_errors: true +- name: verify results of test fail if missing required params + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: domain"' + +- name: test fail if missing required params state=present + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "" + register: result + ignore_errors: true +- name: verify results of test fail if missing required params state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: content"' + +- name: test create a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + content: 1.2.3.4 + register: result +- name: verify results of test create a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.4"' + +- name: test create a record idempotence + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + content: 1.2.3.4 + register: result +- name: verify results of test create a record + assert: + that: + - result is not changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.4"' + +- name: test update a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + content: 1.2.3.5 + ttl: 7200 + register: result +- name: verify results of test update a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + - 'result.exo_dns_record.ttl == 7200' + +- name: test update a record idempotence + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + content: 1.2.3.5 + ttl: 7200 + register: result +- name: verify results of test update a record idempotence + assert: + that: + - result is not changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + - 'result.exo_dns_record.ttl == 7200' + +- name: test delete a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + state: absent + register: result +- name: verify results of test create a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + - 'result.exo_dns_record.ttl == 7200' + +- name: test delete a record idempotence + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + state: absent + register: result +- name: verify results of test create a record idempotence + assert: + that: + - result is not changed + +- name: setup an existing MX record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + record_type: MX + name: "" + content: "mx2.{{ exo_dns_domain_name }}" + prio: 10 + register: result +- name: verify results of test create a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == ""' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "mx2.{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.prio == 10' + +- name: test create a MX record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + record_type: MX + name: "" + content: "mx1.{{ exo_dns_domain_name }}" + prio: 10 + register: result +- name: verify results of test create a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == ""' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "mx1.{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.prio == 10' + +- name: test update a MX record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + record_type: MX + name: "" + content: "mx1.{{ exo_dns_domain_name }}" + prio: 20 + tags: foo + register: result +- name: verify results of test create a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == ""' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "mx1.{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.prio == 20' + tags: foo + +- name: test delete a MX record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + record_type: MX + name: "" + content: "mx1.{{ exo_dns_domain_name }}" + state: absent + register: result +- name: verify results of test delete a MX record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == ""' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "mx1.{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.prio == 20' + +- name: test delete a MX record idempotence + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + record_type: MX + name: "" + content: "mx1.{{ exo_dns_domain_name }}" + state: absent + register: result +- name: verify results of test delete a MX record idempotence + assert: + that: + - result is not changed + +- name: test create first multiple a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.4 + register: result +- name: verify results of test create first multiple a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.4"' + +- name: test create another similar a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.5 + register: result +- name: verify results of test create another similar a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + - 'result.exo_dns_record.ttl == 3600' + +- name: test update another similar a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.5 + ttl: 7200 + register: result +- name: verify results of test create another similar a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + - 'result.exo_dns_record.ttl == 7200' + +- name: test create first multiple a record idempotence + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.4 + register: result +- name: verify results of test create first multiple a record idempotence + assert: + that: + - result is not changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.4"' + +- name: test delete similar a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.5 + state: absent + register: result +- name: verify results of test delete similar a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.5"' + +- name: test delete first similar a record + ngine_io.exoscale.exo_dns_record: + domain: "{{ exo_dns_domain_name }}" + name: "{{ exo_dns_record_name_web }}" + multiple: yes + content: 1.2.3.4 + state: absent + register: result +- name: verify results of test delete first similar a record + assert: + that: + - result is changed + - 'result.exo_dns_record.name == "{{ exo_dns_record_name_web }}"' + - 'result.exo_dns_record.domain == "{{ exo_dns_domain_name }}"' + - 'result.exo_dns_record.content == "1.2.3.4"' + +- name: test delete a domain + ngine_io.exoscale.exo_dns_domain: + name: "{{ exo_dns_domain_name }}" + state: absent + register: result +- name: verify results of test delete a domain + assert: + that: + - result is changed + - 'result.exo_dns_domain.name == "{{ exo_dns_domain_name }}"' + +- name: test delete a domain idempotence + ngine_io.exoscale.exo_dns_domain: + name: "{{ exo_dns_domain_name }}" + state: absent + register: result +- name: verify results of test delete a domain idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/integration.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/integration.yml new file mode 100644 index 00000000..d8e21253 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/integration.yml @@ -0,0 +1,74 @@ +name: Collection integration + +on: + push: + schedule: + - cron: 31 6 * * * # Run weekly + +jobs: + integration-test: + name: Integration test using Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: ansible_collections/ngine_io/vultr + strategy: + fail-fast: false + matrix: + runner-python-version: + - 3.6 + python-version: + - 3.6 + - 2.7 + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/vultr + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + + - name: Install ansible and collection dependencies + run: | + python -m pip install --upgrade pip + pip install ansible + + - name: Build and install collection + run: | + ansible-galaxy collection build . + ansible-galaxy collection install *.gz + + - name: Add config file + env: + CONFIG_FILE: ${{ secrets.CONFIG_FILE }} + run: | + echo "$CONFIG_FILE" > tests/integration/cloud-config-vultr.ini + + - name: Run the tests + run: >- + ansible-test + integration + --docker + -v + --diff + --color + --retry-on-error + --python ${{ matrix.python-version }} + --continue-on-error + --coverage + smoke/vultr/ + + - name: Generate coverage report + run: >- + ansible-test + coverage xml + -v + --requirements + --group-by command + --group-by version + - uses: codecov/codecov-action@v1 + with: + fail_ci_if_error: false diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/publish.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/publish.yml new file mode 100644 index 00000000..31b5d45c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/publish.yml @@ -0,0 +1,33 @@ +name: Upload release to Galaxy + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ansible_collections/ngine_io/vultr + steps: + - uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/vultr + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ansible + + - name: Build and publish + env: + ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} + run: | + ansible-galaxy collection build . + ansible-galaxy collection publish *.tar.gz --api-key $ANSIBLE_GALAXY_API_KEY diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/sanity.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/sanity.yml new file mode 100644 index 00000000..3467db38 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/.github/workflows/sanity.yml @@ -0,0 +1,33 @@ +name: Sanity +on: +- pull_request + +jobs: + sanity: + name: Sanity (${{ matrix.ansible }}) + runs-on: ubuntu-latest + defaults: + run: + working-directory: ansible_collections/ngine_io/vultr + strategy: + matrix: + ansible: + - stable-2.10 + - stable-2.9 + - devel + steps: + - name: Check out code + uses: actions/checkout@v2 + with: + path: ansible_collections/ngine_io/vultr + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install ansible-base (${{ matrix.ansible }}) + run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check + + - name: Run sanity tests + run: ansible-test sanity --docker -v --color diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/CHANGELOG.rst b/collections-debian-merged/ansible_collections/ngine_io/vultr/CHANGELOG.rst new file mode 100644 index 00000000..1ae9e20d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/CHANGELOG.rst @@ -0,0 +1,36 @@ +============================== +Vultr Collection Release Notes +============================== + +.. contents:: Topics + + +v1.1.0 +====== + +Minor Changes +------------- + +- vultr_block_storage - Included ability to resize, attach and detach Block Storage Volumes. + +v1.0.0 +====== + +v0.3.0 +====== + +Minor Changes +------------- + +- vultr_server_info, vultr_server - Improved handling of discontinued plans (https://github.com/ansible/ansible/issues/66707). + +Bugfixes +-------- + +- vultr - Fixed the issue retry max delay param was ignored. + +New Modules +----------- + +- vultr_plan_baremetal_info - Gather information about the Vultr Bare Metal plans available. +- vultr_server_baremetal - Manages baremetal servers on Vultr. diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/CONTRIBUTING.md b/collections-debian-merged/ansible_collections/ngine_io/vultr/CONTRIBUTING.md new file mode 100644 index 00000000..44683c13 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# Contributing + +Any contribution is welcome and we only ask contributors to: + +- Create an issues for any significant contribution that would change a large portion of the code base. +- Provide at least integration tests for any contribution diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/COPYING b/collections-debian-merged/ansible_collections/ngine_io/vultr/COPYING new file mode 100644 index 00000000..94a04532 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/COPYING @@ -0,0 +1,621 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + 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 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/FILES.json b/collections-debian-merged/ansible_collections/ngine_io/vultr/FILES.json new file mode 100644 index 00000000..f2a07a7a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/FILES.json @@ -0,0 +1,1398 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".github/workflows/integration.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2387368cafcf372c45a3a3e29b5943fdfe9b263de4ce69e987e8d7986575075c", + "format": 1 + }, + { + "name": ".github/workflows/sanity.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b868ba49308a64d3e4144aa5ba5bd5a2a7ff0da435b430343b6b4028772348ff", + "format": 1 + }, + { + "name": ".github/workflows/publish.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b7f39bb1ca799cbd6a80c3a80de6fdafd20e7688b97e667e2d6dca11f2ac5fc5", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d61725d614410e2ee0a900fb0f6b6d742ad8fb689ae27c4d6a3a7f89e82fc791", + "format": 1 + }, + { + "name": "CHANGELOG.rst", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c0b667e55bda2e2df65c4a6092ddaa90c736db50d0cb11b699cf717226519832", + "format": 1 + }, + { + "name": "codecov.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0271dcfe609d71afb466112f2d1c4c13943580fa97bb42b2baa08a1c37bb1c14", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "04696fbd217cbc5e9a0e779e9e454dd4ea2ccaa2e64e2085e347a7462bf79f4c", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/sanity/ignore-2.10.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "tests/integration", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "92fad4ee0d5c2d22cb6aafdda4a9183fd62c27c97a56d70decbb0fb945eb1b2b", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9fba8e6bc585ec240c3f3bffb23cfff580ac96af614abcb3cb1b48dda34b0899", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3583c2e51479f99f2789216687ca7d6e6a79c46c15fba4f60e846c25ec995595", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6688640d74d536b63a99aa454af8d95926d3414f3bd079db044f4a1aeab66995", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7c3fd3f2a66a26ce7bd0a214f10a8a38a7cc32c929e1cb0edb2afa8d3f5c645a", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b47d658ee4a20e470eacefc5c0af57b907bb59f6452ef26bc7a0c70c064d90b5", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/update_record.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8a814ab6ef117b021c046f01a8e03e53572716bbc6103262cd6627804d2f860b", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/create_record.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6e3b6d7add4f8473e4595e678ade0804741ec1068e087839efbec0c5274ccdc9", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/test_fail_multiple.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3a94ab90dcc82900b65490a746281c87160d580526d4ec38367feba99befa20d", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/record.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4c8c1b02a45598f03fa27946a87939e2b17b1719a8edb68650abb01482c64240", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/tasks/remove_record.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "01024888321c9e35dade95aba129279ec0cb6427a455a4ac2b26e0cb5a3da7ab", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_record/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_os_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_os_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_os_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8d515e570329548c517d733888f9911af92d74b74b20b4a60cbb618580661fc9", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_os_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e9a72a5ae88e71690565abf81fe1845976e98e4b60c6025f0679921da414ceac", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a11142abb34964253786b2ea016c9a2ed58309aa051410b083226cf162742b9e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0d9ebc00866bc772b097af315ebb7319b2a778a307505fd7d2094d3752f2b34f", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3732f439f529df507d7eab14482c3169b5c5ba21ae00587f67aded27ad3d5206", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cf60b23a46df48b08ffce07e4def1d3291299bf8944b0d3dd3231b848febeb4e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e2ac0c621416243b85b0d0f2299a5943039f7bf1954831fc7a27399c334c2b2e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c80c20cc2e0d5de0eaf1face10b2ca3c25ed1e2e0aed1b1ca8ee848e96a018fb", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac16afb521ac559c983c0156ad13c3740a096db69beae749893791fbbdf915a2", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_region_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_region_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_region_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "758a60a461a9519fdb262d236962529c80e9517291ce9381e207db92337c768c", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_region_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f1cb3b66756569be69eb64f65f904c293d21125084629ebeb272d5bc69687712", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "271718ae1ecbe2fecf47d77888141cf0630d33122689c8830b9053d49210e2b1", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_startup_script_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9cc9cf623c20f06134f0d2e26b4d00483c42144fc6e136274419f138820e3c4e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a13acf223b7c92f2f0f983c444cbc607f9ca72cd82ecb23ec50da8f31fac9913", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_group_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cf60b23a46df48b08ffce07e4def1d3291299bf8944b0d3dd3231b848febeb4e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c3df36fb3e46b9e23422f0ed4e4071ed281d20f46b6ed901e857be0abe6742e3", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_firewall_rule/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_account_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_account_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_account_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5148a9bfd2dcc70aa62d5353969369689b4cd87e45d552084e17a1c7ef8b79c8", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_account_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a9f61a9487700a83508395d74ce06374baecfcaf4306b30f008d8b726c626a69", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a75a95397dd5ff4e75aa41b33a7b142cd4b8e3298f351e3ad7ee7ee65ef26cb6", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "68833971624986eaae87ba589430fb3b2aba3832e19146122cd114d20ff1faf1", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_server_baremetal/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a4609951c802849cf47485f3ac1f8a2456a7a983dc766a401c3b1e8abfec1f46", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "94b223424a4ddc5ba9b41c6a2379cc42f92c772a44a70798cc2e884b5272f8f1", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3d923883d3a71a5555afc52cc37e231e1008876c9e842a16bf8377768b0f21ae", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9a42f029a3a8daba55ddff38d2f57bf3450b9a3974926000961a0947edf7fdfb", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "970b3f3fa2d747586bee87eff012ab07a9b3a2ad52673363a63c0bd6c5def496", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_user/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0405938e979d0f501873c49595a0eec4541488843f81e4a96b59a73da0813044", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2372e00148dd2e1989fed47315130a9f75b01f22183759f2905a1b78833fa5bb", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "60f56cb0a4e068a6cf706fb1f4274a7124fab21aba34cb4cc67e73f6f815cb3c", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0564f7ada76804ade4f8f7859d596cdcff1346d5cbcab4231169e37077085480", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_block_storage/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d6f8edf2333ade957235db03f9c8412db265aefe56736ac06f24fd534e50e356", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "22b70287f62d5562b9095e154e25fe2673254a88e6d0a6b7cce9f6f830b605f0", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_dns_domain/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "87bc2569f04cdd9da8579f970937ca75f29a934b5f561e3900684003bdb2e097", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0acb1ee578a5103b8b2031b0029387ab47773a2d44426eb3a41a16515145c5cd", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "554685b32769bcb7ee18dc94b2348362f45b7ca002ecb6d77d7f333703307431", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "be07a1772baa2f0d1fd9eb364ce8b2cf8f576c7b4811c1c0b301673083c095bf", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_ssh_key_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_baremetal_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_baremetal_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_baremetal_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "01c4fbfc268b765fc270e362466b72b398fa2f112249592afcf11ba5f2c6418d", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_plan_baremetal_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d9cd08d5e6dbd37f17ffbe7c917de9612232dc51f54a6cb71dfc212d8d202571", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b9b380a86e35239430dc7422da32dfff6f6ec22f06e5409ff441369fdccd507e", + "format": 1 + }, + { + "name": "tests/integration/targets/vultr_network_info/aliases", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "dc2ce6b1319ce6a5d14015a0ce0e61945a5fcb9f4b1cc1e3f2705ba7a5d4b466", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/doc_fragments/vultr.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0fc3cbb0cba1768526231546d18fcd5651483f65fb8caf7e1619d14edcc2399f", + "format": 1 + }, + { + "name": "plugins/doc_fragments/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/inventory", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/inventory/vultr.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c8f9fd3280fad4f73c1caf30051a682319bd9af57c1eb328471dff354067d148", + "format": 1 + }, + { + "name": "plugins/inventory/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/module_utils", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/module_utils/vultr.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "528ba35e2d038565b7975ee67ad2bb87f955d19849cd2709a63e2c35707c56ea", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/vultr_firewall_group.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d089be1c1b13ffbbe9f5896e4424bad3f31e3302dc0fe1e7b880f8a2146a4284", + "format": 1 + }, + { + "name": "plugins/modules/vultr_plan_baremetal_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1fab8b861ea930ecffcb502b3979002f7be0ff391d77bbb87fcbfd717adc29bf", + "format": 1 + }, + { + "name": "plugins/modules/vultr_server.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fa551e2b3dd45480885115168afa5488a4ff8ae1efbd50cbb50bbb94d4b46b85", + "format": 1 + }, + { + "name": "plugins/modules/vultr_startup_script_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a5671941f5ea7accf04d5fc8b9e60bcdff79d5d75794842ba8c7c2c3702228d1", + "format": 1 + }, + { + "name": "plugins/modules/vultr_network_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "50194b45d86e273ecad00e3139c97eba38bb2a22afc1e560e035133d62fed1f1", + "format": 1 + }, + { + "name": "plugins/modules/vultr_server_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "91c152df38a3fbbc1cfd655052fc5c30c1cdbfa23435680aaec9a73057119e03", + "format": 1 + }, + { + "name": "plugins/modules/vultr_user_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ba07097ec26ef2112020b5e009056607a2c16869af83ea6463d200675798d9be", + "format": 1 + }, + { + "name": "plugins/modules/vultr_plan_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0108582ad1ee7a3f7c24a4f9257e35022a68b8cf701b2d1b0db807f02fb30143", + "format": 1 + }, + { + "name": "plugins/modules/vultr_server_baremetal.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "37049d692c819386bd8ef80989f4e386f048c2fd7d7cca58d9095c2c632b13a1", + "format": 1 + }, + { + "name": "plugins/modules/vultr_dns_domain_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4ca4982d27a9f56d3a326eff153ff47f909e30027d93732deecfa6163069f1d2", + "format": 1 + }, + { + "name": "plugins/modules/vultr_ssh_key_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "30fc759d9b6361143f04b53b376a12c723b1ae0adc796454ca38d4a735e730b9", + "format": 1 + }, + { + "name": "plugins/modules/vultr_user.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b31751880825def7c9b749a622adb94f42b2afa81990dd2cc1f64246814549ed", + "format": 1 + }, + { + "name": "plugins/modules/__init__.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "plugins/modules/vultr_firewall_rule.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "491e9f3a06a7f4e7c9069ab92e3c1596ec26948428a8f88a39e52b3b90cb53c9", + "format": 1 + }, + { + "name": "plugins/modules/vultr_dns_domain.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2dfaf1ef3f281a10cbea60ae9cb93bc8e3c7e0c91527f563a4262b2cd627d123", + "format": 1 + }, + { + "name": "plugins/modules/vultr_block_storage.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "67c440733c447f241bb2018bdb4ca6872193a3531c2df4fad6a107b82c6d436e", + "format": 1 + }, + { + "name": "plugins/modules/vultr_network.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5c8e9d690e660eebfdac87e9853c9289aefa16449f58b3584a0b16a5cc61dba8", + "format": 1 + }, + { + "name": "plugins/modules/vultr_block_storage_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f5c942415dd687493fc46b4a927b3f085a06c420d13147405319712ae5b7ad11", + "format": 1 + }, + { + "name": "plugins/modules/vultr_firewall_group_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "94258da259c9a38b878692e3303a2a0c937c5e05ffa3b5ccdb8f0a85ced3cb26", + "format": 1 + }, + { + "name": "plugins/modules/vultr_os_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2158f66c5a3b59fdb2ced1fa29c1fa8263f106a6f46d4630655fc66fda5a6819", + "format": 1 + }, + { + "name": "plugins/modules/vultr_startup_script.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "03cffa0a6294bad833e51fc30c83fd00a3da63dde34820f4f918ee669313d5a1", + "format": 1 + }, + { + "name": "plugins/modules/vultr_dns_record.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "64422dcff674d4ae5083d6b79992226c8f84223ecd495d365a2e6bab67ef69fa", + "format": 1 + }, + { + "name": "plugins/modules/vultr_ssh_key.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c4c675356cc201533c11cadbe5ec4a8d2ec122efa171fdad01046d7135e5f7b8", + "format": 1 + }, + { + "name": "plugins/modules/vultr_region_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ee0648ffad648505eac184d07d1ed4f657ca4931c0aed9530da5a415edd4edf6", + "format": 1 + }, + { + "name": "plugins/modules/vultr_account_info.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b6dcf9d0f7c4a225045294f1483404891378826f317104b95b986df1c05f698d", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7d1a7590d965147b4db6757a706d108db52856e5610cc118ebff84e4308060fa", + "format": 1 + }, + { + "name": "changelogs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "changelogs/fragments/.keep", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "format": 1 + }, + { + "name": "changelogs/fragments/14-attach-detach-and-resize-volumes.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f39269a367fef15e93c951ef4557ffb242d2e2cdf3f20b730eac2956b6aa8595", + "format": 1 + }, + { + "name": "changelogs/config.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "da8aadae1a2850c2013b6d2affb763075e25e5c67f24b7e863852ffdd9594cf5", + "format": 1 + }, + { + "name": "changelogs/.gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "919ef00776e7d2ff349950ac4b806132aa9faf006e214d5285de54533e443b33", + "format": 1 + }, + { + "name": "changelogs/changelog.yaml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8db8b7235c6e71d08ccd6d3a226322ee4d51d7bd175b79985c2d94ae2dddd4d1", + "format": 1 + }, + { + "name": "COPYING", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c61f12da7cdad526bdcbed47a4c0a603e60dbbfdaf8b66933cd088e9132c303f", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/MANIFEST.json b/collections-debian-merged/ansible_collections/ngine_io/vultr/MANIFEST.json new file mode 100644 index 00000000..78852fef --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/MANIFEST.json @@ -0,0 +1,35 @@ +{ + "collection_info": { + "namespace": "ngine_io", + "name": "vultr", + "version": "1.1.0", + "authors": [ + "Ren\u00e9 Moser (@resmo)", + "Yanis Guenane (@Spredzy)" + ], + "readme": "README.md", + "tags": [ + "cloud", + "vultr", + "ngine_io" + ], + "description": "Ansible Collection for Vultr Cloud", + "license": [ + "GPL-3.0-or-later" + ], + "license_file": null, + "dependencies": {}, + "repository": "https://github.com/ngine-io/ansible-collection-vultr", + "documentation": "", + "homepage": "https://github.com/ngine-io/ansible-collection-vultr", + "issues": "https://github.com/ngine-io/ansible-collection-vultr/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7a121733ea987beeec0056cb85b19aa25b176666bd97a8f23a9d52639262f321", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/README.md b/collections-debian-merged/ansible_collections/ngine_io/vultr/README.md new file mode 100644 index 00000000..be2e84b4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/README.md @@ -0,0 +1,80 @@ +![Collection integration](https://github.com/ngine-io/ansible-collection-vultr/workflows/Collection%20integration/badge.svg) + [![Codecov](https://img.shields.io/codecov/c/github/ngine-io/ansible-collection-vultr)](https://codecov.io/gh/ngine-io/ansible-collection-vultr) +[![License](https://img.shields.io/badge/license-GPL%20v3.0-brightgreen.svg)](LICENSE) + +# Ansible Collection for Vultr Cloud + +This collection provides a series of Ansible modules and plugins for interacting with the [Vultr](https://www.vultr.com) Cloud. + +## Requirements + +- ansible version >= 2.9 + +## Installation + +To install the collection hosted in Galaxy: + +```bash +ansible-galaxy collection install ngine_io.vultr +``` + +To upgrade to the latest version of the collection: + +```bash +ansible-galaxy collection install ngine_io.vultr --force +``` + +## Usage + +### Playbooks + +To use a module from Vultr collection, please reference the full namespace, collection name, and modules name that you want to use: + +```yaml +--- +- name: Using Vultr collection + hosts: localhost + tasks: + - ngine_io.vultr.vultr_server: + ... +``` + +Or you can add full namepsace and collecton name in the `collections` element: + +```yaml +--- +- name: Using Vultr collection + hosts: localhost + collections: + - ngine_io.vultr + tasks: + - vultr_server: + ... +``` + +### Roles + +For existing Ansible roles, please also reference the full namespace, collection name, and modules name which used in tasks instead of just modules name. + +### Plugins + +To use a pluign, please reference the full namespace, collection name, and plugins name that you want to use: + +```yaml +plugin: ngine_io.vultr.vultr +``` + +## Contributing + +There are many ways in which you can participate in the project, for example: + +- Submit bugs and feature requests, and help us verify as they are checked in +- Review source code changes +- Review the documentation and make pull requests for anything from typos to new content +- If you are interested in fixing issues and contributing directly to the code base, please see the [CONTRIBUTING](CONTRIBUTING.md) document. + +## License + +GNU General Public License v3.0 + +See [COPYING](COPYING) to see the full text. diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/.gitignore b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/.gitignore new file mode 100644 index 00000000..6be6b533 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/.gitignore @@ -0,0 +1 @@ +/.plugin-cache.yaml diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/changelog.yaml b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/changelog.yaml new file mode 100644 index 00000000..34e83afa --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/changelog.yaml @@ -0,0 +1,30 @@ +ancestor: null +releases: + 0.3.0: + changes: + bugfixes: + - vultr - Fixed the issue retry max delay param was ignored. + minor_changes: + - vultr_server_info, vultr_server - Improved handling of discontinued plans + (https://github.com/ansible/ansible/issues/66707). + fragments: + - 66792-vultr-improve-plan.yml + - 67437-vultr-fix-retry-max-delay-param.yml + modules: + - description: Gather information about the Vultr Bare Metal plans available. + name: vultr_plan_baremetal_info + namespace: '' + - description: Manages baremetal servers on Vultr. + name: vultr_server_baremetal + namespace: '' + release_date: '2020-07-03' + 1.0.0: + release_date: '2020-08-16' + 1.1.0: + changes: + minor_changes: + - vultr_block_storage - Included ability to resize, attach and detach Block + Storage Volumes. + fragments: + - 14-attach-detach-and-resize-volumes.yml + release_date: '2021-02-02' diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/config.yaml b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/config.yaml new file mode 100644 index 00000000..98cab92d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/config.yaml @@ -0,0 +1,29 @@ +changelog_filename_template: ../CHANGELOG.rst +changelog_filename_version_depth: 0 +changes_file: changelog.yaml +changes_format: combined +keep_fragments: true +mention_ancestor: true +new_plugins_after_name: removed_features +notesdir: fragments +prelude_section_name: release_summary +prelude_section_title: Release Summary +sections: +- - major_changes + - Major Changes +- - minor_changes + - Minor Changes +- - breaking_changes + - Breaking Changes / Porting Guide +- - deprecated_features + - Deprecated Features +- - removed_features + - Removed Features (previously deprecated) +- - security_fixes + - Security Fixes +- - bugfixes + - Bugfixes +- - known_issues + - Known Issues +title: Vultr Collection +trivial_section_name: trivial diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/.keep b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/.keep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/.keep diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/14-attach-detach-and-resize-volumes.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/14-attach-detach-and-resize-volumes.yml new file mode 100644 index 00000000..c78b2141 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/changelogs/fragments/14-attach-detach-and-resize-volumes.yml @@ -0,0 +1,2 @@ +minor_changes: + - vultr_block_storage - Included ability to resize, attach and detach Block Storage Volumes.
\ No newline at end of file diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/codecov.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/codecov.yml new file mode 100644 index 00000000..33c8f6ee --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/codecov.yml @@ -0,0 +1,5 @@ +--- +coverage: + precision: 2 + round: down + range: "70...100" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/meta/runtime.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/meta/runtime.yml new file mode 100644 index 00000000..d366b4b0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/meta/runtime.yml @@ -0,0 +1,135 @@ +requires_ansible: '>=2.9.10' +action_groups: + vultr: + - vultr_user + - vultr_plan_baremetal_info + - vultr_user_info + - vultr_block_storage + - vultr_plan_info + - vultr_ssh_key_info + - vultr_network_info + - vultr_firewall_group_info + - vultr_ssh_key + - vultr_dns_domain + - vultr_server_info + - vultr_dns_record + - vultr_server_baremetal + - vultr_block_storage_info + - vultr_firewall_group + - vultr_region_info + - vultr_network + - vultr_account_info + - vultr_firewall_rule + - vultr_dns_domain_info + - vultr_server + - vultr_startup_script + - vultr_os_info + - vultr_startup_script_info + +plugin_routing: + modules: + vr_account_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_account_info + redirect: ngine_io.vultr.vultr_account_info + vr_dns_domain: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_dns_domain + redirect: ngine_io.vultr.vultr_dns_domain + vr_dns_record: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_dns_record + redirect: ngine_io.vultr.vultr_dns_record + vr_firewall_group: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_firewall_group + redirect: ngine_io.vultr.vultr_firewall_group + vr_firewall_rule: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_firewall_rule + redirect: ngine_io.vultr.vultr_firewall_rule + vr_server: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_server + redirect: ngine_io.vultr.vultr_server + vr_ssh_key: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_ssh_key + redirect: ngine_io.vultr.vultr_ssh_key + vr_startup_script: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_startup_script + redirect: ngine_io.vultr.vultr_startup_script + vr_user: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_user + redirect: ngine_io.vultr.vultr_user + vultr_account_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_account_info + redirect: ngine_io.vultr.vultr_account_info + vultr_block_storage_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_block_storage_info + redirect: ngine_io.vultr.vultr_block_storage_info + vultr_dns_domain_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_dns_domain_info + redirect: ngine_io.vultr.vultr_dns_domain_info + vultr_firewall_group_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_firewall_group_info + redirect: ngine_io.vultr.vultr_firewall_group_info + vultr_network_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_network_info + redirect: ngine_io.vultr.vultr_network_info + vultr_os_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_os_info + redirect: ngine_io.vultr.vultr_os_info + vultr_plan_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_plan_info + redirect: ngine_io.vultr.vultr_plan_info + vultr_region_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_region_info + redirect: ngine_io.vultr.vultr_region_info + vultr_server_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_server_info + redirect: ngine_io.vultr.vultr_server_info + vultr_ssh_key_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_ssh_key_info + redirect: ngine_io.vultr.vultr_ssh_key_info + vultr_startup_script_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_startup_script_info + redirect: ngine_io.vultr.vultr_startup_script_info + vultr_user_facts: + deprecation: + removal_date: 2021-12-12 + warning_text: module was renamed, use ngine_io.vultr.vultr_user_info + redirect: ngine_io.vultr.vultr_user_info diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/vultr.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/vultr.py new file mode 100644 index 00000000..cb5cfb64 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/doc_fragments/vultr.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +class ModuleDocFragment(object): + + # Standard documentation fragment + DOCUMENTATION = r''' +options: + api_key: + description: + - API key of the Vultr API. + - The ENV variable C(VULTR_API_KEY) is used as default, when defined. + type: str + api_timeout: + description: + - HTTP timeout to Vultr API. + - The ENV variable C(VULTR_API_TIMEOUT) is used as default, when defined. + - Fallback value is 60 seconds if not specified. + type: int + api_retries: + description: + - Amount of retries in case of the Vultr API retuns an HTTP 503 code. + - The ENV variable C(VULTR_API_RETRIES) is used as default, when defined. + - Fallback value is 5 retries if not specified. + type: int + api_retry_max_delay: + description: + - Retry backoff delay in seconds is exponential up to this max. value, in seconds. + - The ENV variable C(VULTR_API_RETRY_MAX_DELAY) is used as default, when defined. + - Fallback value is 12 seconds. + type: int + api_account: + description: + - Name of the ini section in the C(vultr.ini) file. + - The ENV variable C(VULTR_API_ACCOUNT) is used as default, when defined. + type: str + default: default + api_endpoint: + description: + - URL to API endpint (without trailing slash). + - The ENV variable C(VULTR_API_ENDPOINT) is used as default, when defined. + - Fallback value is U(https://api.vultr.com) if not specified. + type: str + validate_certs: + description: + - Validate SSL certs of the Vultr API. + type: bool + default: yes +requirements: + - python >= 2.6 +notes: + - Also see the API documentation on https://www.vultr.com/api/. +''' diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/vultr.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/vultr.py new file mode 100644 index 00000000..83abd165 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/inventory/vultr.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +DOCUMENTATION = r''' + name: vultr + plugin_type: inventory + author: + - Yanis Guenane (@Spredzy) + - René Moser (@resmo) + short_description: Vultr inventory source + extends_documentation_fragment: + - constructed + description: + - Get inventory hosts from Vultr public cloud. + - Uses an YAML configuration file ending with either I(vultr.yml) or I(vultr.yaml) to set parameter values (also see examples). + - Uses I(api_config), I(~/.vultr.ini), I(./vultr.ini) or C(VULTR_API_CONFIG) pointing to a Vultr credentials INI file + (see U(https://docs.ansible.com/ansible/latest/scenario_guides/guide_vultr.html)). + options: + plugin: + description: Token that ensures this is a source file for the 'vultr' plugin. + type: string + required: True + choices: [ vultr ] + api_account: + description: Specify the account to be used. + type: string + default: default + api_config: + description: Path to the vultr configuration file. If not specified will be taken from regular Vultr configuration. + type: path + env: + - name: VULTR_API_CONFIG + api_key: + description: Vultr API key. If not specified will be taken from regular Vultr configuration. + type: string + env: + - name: VULTR_API_KEY + hostname: + description: Field to match the hostname. Note v4_main_ip corresponds to the main_ip field returned from the API and name to label. + type: string + default: v4_main_ip + choices: + - v4_main_ip + - v6_main_ip + - name + filter_by_tag: + description: Only return servers filtered by this tag + type: string +''' + +EXAMPLES = r''' +# inventory_vultr.yml file in YAML format +# Example command line: ansible-inventory --list -i inventory_vultr.yml + +# Group by a region as lower case and with prefix e.g. "vultr_region_amsterdam" and by OS without prefix e.g. "CentOS_7_x64" +plugin: vultr +keyed_groups: + - prefix: vultr_region + key: region | lower + - separator: "" + key: os + +# Pass a tag filter to the API +plugin: vultr +filter_by_tag: Cache +''' + +import json + +from ansible.errors import AnsibleError +from ansible.plugins.inventory import BaseInventoryPlugin, Constructable +from ansible.module_utils.six.moves import configparser +from ansible.module_utils.urls import open_url +from ansible.module_utils._text import to_native +from ..module_utils.vultr import Vultr, VULTR_API_ENDPOINT, VULTR_USER_AGENT +from ansible.module_utils.six.moves.urllib.parse import quote + + +SCHEMA = { + 'SUBID': dict(key='id'), + 'label': dict(key='name'), + 'date_created': dict(), + 'allowed_bandwidth_gb': dict(convert_to='int'), + 'auto_backups': dict(key='auto_backup_enabled', convert_to='bool'), + 'current_bandwidth_gb': dict(), + 'kvm_url': dict(), + 'default_password': dict(), + 'internal_ip': dict(), + 'disk': dict(), + 'cost_per_month': dict(convert_to='float'), + 'location': dict(key='region'), + 'main_ip': dict(key='v4_main_ip'), + 'network_v4': dict(key='v4_network'), + 'gateway_v4': dict(key='v4_gateway'), + 'os': dict(), + 'pending_charges': dict(convert_to='float'), + 'power_status': dict(), + 'ram': dict(), + 'plan': dict(), + 'server_state': dict(), + 'status': dict(), + 'firewall_group': dict(), + 'tag': dict(), + 'v6_main_ip': dict(), + 'v6_network': dict(), + 'v6_network_size': dict(), + 'v6_networks': dict(), + 'vcpu_count': dict(convert_to='int'), +} + + +def _load_conf(path, account): + + if path: + conf = configparser.ConfigParser() + conf.read(path) + + if not conf._sections.get(account): + return None + + return dict(conf.items(account)) + else: + return Vultr.read_ini_config(account) + + +def _retrieve_servers(api_key, tag_filter=None): + api_url = '%s/v1/server/list' % VULTR_API_ENDPOINT + if tag_filter is not None: + api_url = api_url + '?tag=%s' % quote(tag_filter) + + try: + response = open_url( + api_url, headers={'API-Key': api_key, 'Content-type': 'application/json'}, + http_agent=VULTR_USER_AGENT, + ) + servers_list = json.loads(response.read()) + + return servers_list.values() if servers_list else [] + except ValueError: + raise AnsibleError("Incorrect JSON payload") + except Exception as e: + raise AnsibleError("Error while fetching %s: %s" % (api_url, to_native(e))) + + +class InventoryModule(BaseInventoryPlugin, Constructable): + + NAME = 'ngine_io.vultr.vultr' + + def verify_file(self, path): + valid = False + if super(InventoryModule, self).verify_file(path): + if path.endswith(('vultr.yaml', 'vultr.yml')): + valid = True + return valid + + def parse(self, inventory, loader, path, cache=True): + super(InventoryModule, self).parse(inventory, loader, path) + self._read_config_data(path=path) + + conf = _load_conf(self.get_option('api_config'), self.get_option('api_account')) + try: + api_key = self.get_option('api_key') or conf.get('key') + except Exception: + raise AnsibleError('Could not find an API key. Check inventory file and Vultr configuration files.') + + hostname_preference = self.get_option('hostname') + + # Add a top group 'vultr' + self.inventory.add_group(group='vultr') + + # Filter by tag is supported by the api with a query + filter_by_tag = self.get_option('filter_by_tag') + for server in _retrieve_servers(api_key, filter_by_tag): + + server = Vultr.normalize_result(server, SCHEMA) + + self.inventory.add_host(host=server['name'], group='vultr') + + for attribute, value in server.items(): + self.inventory.set_variable(server['name'], attribute, value) + + if hostname_preference != 'name': + self.inventory.set_variable(server['name'], 'ansible_host', server[hostname_preference]) + + # Use constructed if applicable + strict = self.get_option('strict') + + # Composed variables + self._set_composite_vars(self.get_option('compose'), server, server['name'], strict=strict) + + # Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group + self._add_host_to_composed_groups(self.get_option('groups'), server, server['name'], strict=strict) + + # Create groups based on variable values and add the corresponding hosts to it + self._add_host_to_keyed_groups(self.get_option('keyed_groups'), server, server['name'], strict=strict) diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/module_utils/vultr.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/module_utils/vultr.py new file mode 100644 index 00000000..81e7b62c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/module_utils/vultr.py @@ -0,0 +1,336 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import os +import time +import random +import urllib +from ansible.module_utils.six.moves import configparser +from ansible.module_utils._text import to_text, to_native +from ansible.module_utils.urls import fetch_url + + +VULTR_API_ENDPOINT = "https://api.vultr.com" +VULTR_USER_AGENT = 'Ansible Vultr' + + +def vultr_argument_spec(): + return dict( + api_key=dict(type='str', default=os.environ.get('VULTR_API_KEY'), no_log=True), + api_timeout=dict(type='int', default=os.environ.get('VULTR_API_TIMEOUT')), + api_retries=dict(type='int', default=os.environ.get('VULTR_API_RETRIES')), + api_retry_max_delay=dict(type='int', default=os.environ.get('VULTR_API_RETRY_MAX_DELAY')), + api_account=dict(type='str', default=os.environ.get('VULTR_API_ACCOUNT') or 'default'), + api_endpoint=dict(type='str', default=os.environ.get('VULTR_API_ENDPOINT')), + validate_certs=dict(type='bool', default=True), + ) + + +class Vultr: + + def __init__(self, module, namespace): + + if module._name.startswith('vr_'): + module.deprecate( + "The Vultr modules were renamed. The prefix of the modules changed from vr_ to vultr_", + collection_name='ngine_io.vultr', + version='2.0.0') # Was Ansbile 2.11 + + self.module = module + + # Namespace use for returns + self.namespace = namespace + self.result = { + 'changed': False, + namespace: dict(), + 'diff': dict(before=dict(), after=dict()) + } + + # For caching HTTP API responses + self.api_cache = dict() + + try: + config = self.read_env_variables() + config.update(Vultr.read_ini_config(self.module.params.get('api_account'))) + except KeyError: + config = {} + + try: + self.api_config = { + 'api_key': self.module.params.get('api_key') or config.get('key'), + 'api_timeout': self.module.params.get('api_timeout') or int(config.get('timeout') or 60), + 'api_retries': self.module.params.get('api_retries') or int(config.get('retries') or 5), + 'api_retry_max_delay': self.module.params.get('api_retry_max_delay') or int(config.get('retry_max_delay') or 12), + 'api_endpoint': self.module.params.get('api_endpoint') or config.get('endpoint') or VULTR_API_ENDPOINT, + } + except ValueError as e: + self.fail_json(msg="One of the following settings, " + "in section '%s' in the ini config file has not an int value: timeout, retries. " + "Error was %s" % (self.module.params.get('api_account'), to_native(e))) + + if not self.api_config.get('api_key'): + self.module.fail_json(msg="No API key was specified. Please refer to the documentation.") + + # Common vultr returns + self.result['vultr_api'] = { + 'api_account': self.module.params.get('api_account'), + 'api_timeout': self.api_config['api_timeout'], + 'api_retries': self.api_config['api_retries'], + 'api_retry_max_delay': self.api_config['api_retry_max_delay'], + 'api_endpoint': self.api_config['api_endpoint'], + } + + # Headers to be passed to the API + self.headers = { + 'API-Key': "%s" % self.api_config['api_key'], + 'User-Agent': VULTR_USER_AGENT, + 'Accept': 'application/json', + } + + def read_env_variables(self): + keys = ['key', 'timeout', 'retries', 'retry_max_delay', 'endpoint'] + env_conf = {} + for key in keys: + if 'VULTR_API_%s' % key.upper() not in os.environ: + continue + env_conf[key] = os.environ['VULTR_API_%s' % key.upper()] + + return env_conf + + @staticmethod + def read_ini_config(ini_group): + paths = ( + os.path.join(os.path.expanduser('~'), '.vultr.ini'), + os.path.join(os.getcwd(), 'vultr.ini'), + ) + if 'VULTR_API_CONFIG' in os.environ: + paths += (os.path.expanduser(os.environ['VULTR_API_CONFIG']),) + + conf = configparser.ConfigParser() + conf.read(paths) + + if not conf._sections.get(ini_group): + return dict() + + return dict(conf.items(ini_group)) + + def fail_json(self, **kwargs): + self.result.update(kwargs) + self.module.fail_json(**self.result) + + def get_yes_or_no(self, key): + if self.module.params.get(key) is not None: + return 'yes' if self.module.params.get(key) is True else 'no' + + def switch_enable_disable(self, resource, param_key, resource_key=None): + if resource_key is None: + resource_key = param_key + + param = self.module.params.get(param_key) + if param is None: + return + + r_value = resource.get(resource_key) + if r_value in ['yes', 'no']: + if param and r_value != 'yes': + return "enable" + elif not param and r_value != 'no': + return "disable" + else: + if param and not r_value: + return "enable" + elif not param and r_value: + return "disable" + + def api_query(self, path="/", method="GET", data=None): + url = self.api_config['api_endpoint'] + path + + if data: + data_encoded = dict() + data_list = "" + for k, v in data.items(): + if isinstance(v, list): + for s in v: + try: + data_list += '&%s[]=%s' % (k, urllib.quote(s)) + except AttributeError: + data_list += '&%s[]=%s' % (k, urllib.parse.quote(s)) + elif v is not None: + data_encoded[k] = v + try: + data = urllib.urlencode(data_encoded) + data_list + except AttributeError: + data = urllib.parse.urlencode(data_encoded) + data_list + + retry_max_delay = self.api_config['api_retry_max_delay'] + randomness = random.randint(0, 1000) / 1000.0 + + for retry in range(0, self.api_config['api_retries']): + response, info = fetch_url( + module=self.module, + url=url, + data=data, + method=method, + headers=self.headers, + timeout=self.api_config['api_timeout'], + ) + + if info.get('status') == 200: + break + + # Vultr has a rate limiting requests per second, try to be polite + # Use exponential backoff plus a little bit of randomness + delay = 2 ** retry + randomness + if delay > retry_max_delay: + delay = retry_max_delay + randomness + time.sleep(delay) + + else: + self.fail_json(msg="Reached API retries limit %s for URL %s, method %s with data %s. Returned %s, with body: %s %s" % ( + self.api_config['api_retries'], + url, + method, + data, + info['status'], + info['msg'], + info.get('body') + )) + + if info.get('status') != 200: + self.fail_json(msg="URL %s, method %s with data %s. Returned %s, with body: %s %s" % ( + url, + method, + data, + info['status'], + info['msg'], + info.get('body') + )) + + res = response.read() + if not res: + return {} + + try: + return self.module.from_json(to_native(res)) or {} + except ValueError as e: + self.module.fail_json(msg="Could not process response into json: %s" % e) + + def query_resource_by_key(self, key, value, resource='regions', query_by='list', params=None, use_cache=False, id_key=None, optional=False): + if not value: + return {} + + r_list = None + if use_cache: + r_list = self.api_cache.get(resource) + + if not r_list: + r_list = self.api_query(path="/v1/%s/%s" % (resource, query_by), data=params) + if use_cache: + self.api_cache.update({ + resource: r_list + }) + + if not r_list: + return {} + + elif isinstance(r_list, list): + for r_data in r_list: + if str(r_data[key]) == str(value): + return r_data + if id_key is not None and to_text(r_data[id_key]) == to_text(value): + return r_data + elif isinstance(r_list, dict): + for r_id, r_data in r_list.items(): + if str(r_data[key]) == str(value): + return r_data + if id_key is not None and to_text(r_data[id_key]) == to_text(value): + return r_data + if not optional: + if id_key: + msg = "Could not find %s with ID or %s: %s" % (resource, key, value) + else: + msg = "Could not find %s with %s: %s" % (resource, key, value) + self.module.fail_json(msg=msg) + return {} + + @staticmethod + def normalize_result(resource, schema, remove_missing_keys=True): + if remove_missing_keys: + fields_to_remove = set(resource.keys()) - set(schema.keys()) + for field in fields_to_remove: + resource.pop(field) + + for search_key, config in schema.items(): + if search_key in resource: + if 'convert_to' in config: + if config['convert_to'] == 'int': + resource[search_key] = int(resource[search_key]) + elif config['convert_to'] == 'float': + resource[search_key] = float(resource[search_key]) + elif config['convert_to'] == 'bool': + resource[search_key] = True if resource[search_key] == 'yes' else False + + if 'transform' in config: + resource[search_key] = config['transform'](resource[search_key]) + + if 'key' in config: + resource[config['key']] = resource[search_key] + del resource[search_key] + + return resource + + def get_result(self, resource): + if resource: + if isinstance(resource, list): + self.result[self.namespace] = [Vultr.normalize_result(item, self.returns) for item in resource] + else: + self.result[self.namespace] = Vultr.normalize_result(resource, self.returns) + + return self.result + + def get_plan(self, plan=None, key='name', optional=False): + value = plan or self.module.params.get('plan') + + return self.query_resource_by_key( + key=key, + value=value, + resource='plans', + use_cache=True, + id_key='VPSPLANID', + optional=optional, + ) + + def get_firewallgroup(self, firewallgroup=None, key='description'): + value = firewallgroup or self.module.params.get('firewallgroup') + + return self.query_resource_by_key( + key=key, + value=value, + resource='firewall', + query_by='group_list', + use_cache=True + ) + + def get_application(self, application=None, key='name'): + value = application or self.module.params.get('application') + + return self.query_resource_by_key( + key=key, + value=value, + resource='app', + use_cache=True + ) + + def get_region(self, region=None, key='name'): + value = region or self.module.params.get('region') + + return self.query_resource_by_key( + key=key, + value=value, + resource='regions', + use_cache=True + ) diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/__init__.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/__init__.py diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_account_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_account_info.py new file mode 100644 index 00000000..1718ff66 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_account_info.py @@ -0,0 +1,130 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_account_info +short_description: Get information about the Vultr account. +description: + - Get infos about account balance, charges and payments. +version_added: "0.1.0" +author: "René Moser (@resmo)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Get Vultr account infos + ngine_io.vultr.vultr_account_info: + register: result + +- name: Print the infos + debug: + var: result.vultr_account_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_account_info: + description: Response from Vultr API + returned: success + type: complex + contains: + balance: + description: Your account balance. + returned: success + type: float + sample: -214.69 + pending_charges: + description: Charges pending. + returned: success + type: float + sample: 57.03 + last_payment_date: + description: Date of the last payment. + returned: success + type: str + sample: "2017-08-26 12:47:48" + last_payment_amount: + description: The amount of the last payment transaction. + returned: success + type: float + sample: -250.0 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrAccountInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrAccountInfo, self).__init__(module, "vultr_account_info") + + self.returns = { + 'balance': dict(convert_to='float'), + 'pending_charges': dict(convert_to='float'), + 'last_payment_date': dict(), + 'last_payment_amount': dict(convert_to='float'), + } + + def get_account_info(self): + return self.api_query(path="/v1/account/info") + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + account_info = AnsibleVultrAccountInfo(module) + result = account_info.get_result(account_info.get_account_info()) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage.py new file mode 100644 index 00000000..5cda1cd1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage.py @@ -0,0 +1,382 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_block_storage +short_description: Manages block storage volumes on Vultr. +description: + - Manage block storage volumes on Vultr. +author: "Yanis Guenane (@Spredzy)" +version_added: "0.1.0" +options: + name: + description: + - Name of the block storage volume. + required: true + aliases: [ description, label ] + type: str + size: + description: + - Size of the block storage volume in GB. + - Required if I(state) is present. + - If it's larger than the volume's current size, the volume will be resized. + type: int + region: + description: + - Region the block storage volume is deployed into. + - Required if I(state) is present. + type: str + state: + description: + - State of the block storage volume. + default: present + choices: [ present, absent, attached, detached ] + type: str + attached_to_SUBID: + description: + - The ID of the server the volume is attached to. + - Required if I(state) is attached. + aliases: [ attached_to_id ] + type: int + live_attachment: + description: + - Whether the volume should be attached/detached, even if the server not stopped. + type: bool + default: True +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: Ensure a block storage volume is present + ngine_io.vultr.vultr_block_storage: + name: myvolume + size: 10 + region: Amsterdam + +- name: Ensure a block storage volume is absent + ngine_io.vultr.vultr_block_storage: + name: myvolume + state: absent + +- name: Ensure a block storage volume exists and is attached to server 114 + ngine_io.vultr.vultr_block_storage: + name: myvolume + state: attached + attached_to_id: 114 + size: 10 + +- name: Ensure a block storage volume exists and is not attached to any server + ngine_io.vultr.vultr_block_storage: + name: myvolume + state: detached + size: 10 +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_block_storage: + description: Response from Vultr API + returned: success + type: complex + contains: + attached_to_id: + description: The ID of the server the volume is attached to + returned: success + type: str + sample: "10194376" + cost_per_month: + description: Cost per month for the volume + returned: success + type: float + sample: 1.00 + date_created: + description: Date when the volume was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + id: + description: ID of the block storage volume + returned: success + type: str + sample: "1234abcd" + name: + description: Name of the volume + returned: success + type: str + sample: "ansible-test-volume" + region: + description: Region the volume was deployed into + returned: success + type: str + sample: "New Jersey" + size: + description: Information about the volume size in GB + returned: success + type: int + sample: 10 + status: + description: Status about the deployment of the volume + returned: success + type: str + sample: "active" + +''' +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrBlockStorage(Vultr): + + def __init__(self, module): + super(AnsibleVultrBlockStorage, self).__init__(module, "vultr_block_storage") + + self.returns = { + 'SUBID': dict(key='id'), + 'label': dict(key='name'), + 'DCID': dict(key='region', transform=self._get_region_name), + 'attached_to_SUBID': dict(key='attached_to_id'), + 'cost_per_month': dict(convert_to='float'), + 'date_created': dict(), + 'size_gb': dict(key='size', convert_to='int'), + 'status': dict() + } + + def _get_region_name(self, region): + return self.get_region(region, 'DCID').get('name') + + def get_block_storage_volumes(self): + volumes = self.api_query(path="/v1/block/list") + if volumes: + for volume in volumes: + if volume.get('label') == self.module.params.get('name'): + return volume + return {} + + def present_block_storage_volume(self): + volume = self.get_block_storage_volumes() + if not volume: + volume = self._create_block_storage_volume(volume) + return volume + + def _create_block_storage_volume(self, volume): + self.result['changed'] = True + data = { + 'label': self.module.params.get('name'), + 'DCID': self.get_region().get('DCID'), + 'size_gb': self.module.params.get('size') + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/block/create", + method="POST", + data=data + ) + volume = self.get_block_storage_volumes() + return volume + + def absent_block_storage_volume(self): + volume = self.get_block_storage_volumes() + if volume: + self.result['changed'] = True + + data = { + 'SUBID': volume['SUBID'], + } + + self.result['diff']['before'] = volume + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/block/delete", + method="POST", + data=data + ) + return volume + + def detached_block_storage_volume(self): + volume = self.present_block_storage_volume() + if volume.get('attached_to_SUBID') is None: + return volume + + self.result['changed'] = True + + if not self.module.check_mode: + data = { + 'SUBID': volume['SUBID'], + 'live': self.get_yes_or_no('live_attachment') + } + self.api_query( + path='/v1/block/detach', + method='POST', + data=data + ) + + volume = self.get_block_storage_volumes() + else: + volume['attached_to_SUBID'] = None + + self.result['diff']['after'] = volume + + return volume + + def attached_block_storage_volume(self): + expected_server = self.module.params.get('attached_to_SUBID') + volume = self.present_block_storage_volume() + server = volume.get('attached_to_SUBID') + if server == expected_server: + return volume + + if server is not None: + self.module.fail_json( + msg='Volume already attached to server %s' % server + ) + + self.result['changed'] = True + + if not self.module.check_mode: + data = { + 'SUBID': volume['SUBID'], + # This API call expects a param called attach_to_SUBID, + # but all the BlockStorage API response payloads call + # this parameter attached_to_SUBID. So we'll standardize + # to the latter and attached_to_id, but we'll pass the + # expected attach_to_SUBID to this API call. + 'attach_to_SUBID': expected_server, + 'live': self.get_yes_or_no('live_attachment'), + } + self.api_query( + path='/v1/block/attach', + method='POST', + data=data + ) + volume = self.get_block_storage_volumes() + else: + volume['attached_to_SUBID'] = expected_server + + self.result['diff']['after'] = volume + + return volume + + def ensure_volume_size(self, volume, expected_size): + curr_size = volume.get('size_gb') + # When creating, attaching, or detaching a volume in check_mode, + # sadly, size_gb doesn't exist, because those methods return the + # result of get_block_storage_volumes, which is {} on check_mode. + if curr_size is None or curr_size >= expected_size: + # we only resize volumes that are smaller than + # expected. There's no shrinking operation. + return volume + + self.result['changed'] = True + + volume['size_gb'] = expected_size + self.result['diff']['after'] = volume + + if not self.module.check_mode: + data = {'SUBID': volume['SUBID'], 'size_gb': expected_size} + self.api_query( + path='/v1/block/resize', + method='POST', + data=data, + ) + + return volume + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True, aliases=['description', 'label']), + size=dict(type='int'), + region=dict(type='str'), + state=dict( + type='str', + choices=['present', 'absent', 'attached', 'detached'], + default='present' + ), + attached_to_SUBID=dict(type='int', aliases=['attached_to_id']), + live_attachment=dict(type='bool', default=True) + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ['state', 'present', ['size', 'region']], + ['state', 'detached', ['size', 'region']], + ['state', 'attached', ['size', 'region', 'attached_to_SUBID']], + ] + ) + + vultr_block_storage = AnsibleVultrBlockStorage(module) + + desired_state = module.params.get('state') + if desired_state == "absent": + volume = vultr_block_storage.absent_block_storage_volume() + elif desired_state == 'attached': + volume = vultr_block_storage.attached_block_storage_volume() + elif desired_state == 'detached': + volume = vultr_block_storage.detached_block_storage_volume() + else: + volume = vultr_block_storage.present_block_storage_volume() + + expected_size = module.params.get('size') + if expected_size and desired_state != 'absent': + volume = vultr_block_storage.ensure_volume_size( + volume, + expected_size + ) + + result = vultr_block_storage.get_result(volume) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage_info.py new file mode 100644 index 00000000..46bdbecb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_block_storage_info.py @@ -0,0 +1,160 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_block_storage_info +short_description: Get information about the Vultr block storage volumes available. +description: + - Get infos about block storage volumes available in Vultr. +version_added: "0.1.0" +author: + - "Yanis Guenane (@Spredzy)" + - "René Moser (@resmo)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Get Vultr block storage infos + ngine_io.vultr.vultr_block_storage_info: + register: result + +- name: Print the infos + debug: + var: result.vultr_block_storage_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_block_storage_info: + description: Response from Vultr API as list + returned: success + type: complex + contains: + id: + description: ID of the block storage. + returned: success + type: int + sample: 17332323 + size: + description: Size in GB of the block storage. + returned: success + type: int + sample: 10 + region: + description: Region the block storage is located in. + returned: success + type: str + sample: New Jersey + name: + description: Name of the block storage. + returned: success + type: str + sample: my volume + cost_per_month: + description: Cost per month of the block storage. + returned: success + type: float + sample: 1.0 + date_created: + description: Date created of the block storage. + returned: success + type: str + sample: "2018-07-24 12:59:59" + status: + description: Status of the block storage. + returned: success + type: str + sample: active + attached_to_id: + description: Block storage is attached to this server ID. + returned: success + type: str + sample: null +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrBlockStorageFacts(Vultr): + + def __init__(self, module): + super(AnsibleVultrBlockStorageFacts, self).__init__(module, "vultr_block_storage_info") + + self.returns = { + 'attached_to_SUBID': dict(key='attached_to_id'), + 'cost_per_month': dict(convert_to='float'), + 'date_created': dict(), + 'SUBID': dict(key='id'), + 'label': dict(key='name'), + 'DCID': dict(key='region', transform=self._get_region_name), + 'size_gb': dict(key='size', convert_to='int'), + 'status': dict() + } + + def _get_region_name(self, region): + return self.get_region(region, 'DCID').get('name') + + def get_block_storage_volumes(self): + return self.api_query(path="/v1/block/list") + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + volume_info = AnsibleVultrBlockStorageFacts(module) + result = volume_info.get_result(volume_info.get_block_storage_volumes()) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain.py new file mode 100644 index 00000000..131280d0 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain.py @@ -0,0 +1,202 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_dns_domain +short_description: Manages DNS domains on Vultr. +description: + - Create and remove DNS domains. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - The domain name. + required: true + aliases: [ domain ] + type: str + server_ip: + description: + - The default server IP. + - Use M(vultr_dns_record) to change it once the domain is created. + - Required if C(state=present). + type: str + state: + description: + - State of the DNS domain. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Ensure a domain exists + ngine_io.vultr.vultr_dns_domain: + name: example.com + server_ip: 10.10.10.10 + +- name: Ensure a domain is absent + ngine_io.vultr.vultr_dns_domain: + name: example.com + state: absent +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_dns_domain: + description: Response from Vultr API + returned: success + type: complex + contains: + name: + description: Name of the DNS Domain. + returned: success + type: str + sample: example.com + date_created: + description: Date the DNS domain was created. + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrDnsDomain(Vultr): + + def __init__(self, module): + super(AnsibleVultrDnsDomain, self).__init__(module, "vultr_dns_domain") + + self.returns = { + 'domain': dict(key='name'), + 'date_created': dict(), + } + + def get_domain(self): + domains = self.api_query(path="/v1/dns/list") + name = self.module.params.get('name').lower() + if domains: + for domain in domains: + if domain.get('domain').lower() == name: + return domain + return {} + + def present_domain(self): + domain = self.get_domain() + if not domain: + domain = self._create_domain(domain) + return domain + + def _create_domain(self, domain): + self.result['changed'] = True + data = { + 'domain': self.module.params.get('name'), + 'serverip': self.module.params.get('server_ip'), + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/dns/create_domain", + method="POST", + data=data + ) + domain = self.get_domain() + return domain + + def absent_domain(self): + domain = self.get_domain() + if domain: + self.result['changed'] = True + + data = { + 'domain': domain['domain'], + } + + self.result['diff']['before'] = domain + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/dns/delete_domain", + method="POST", + data=data + ) + return domain + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True, aliases=['domain']), + server_ip=dict(type='str',), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ('state', 'present', ['server_ip']), + ], + supports_check_mode=True, + ) + + vultr_domain = AnsibleVultrDnsDomain(module) + if module.params.get('state') == "absent": + domain = vultr_domain.absent_domain() + else: + domain = vultr_domain.present_domain() + + result = vultr_domain.get_result(domain) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain_info.py new file mode 100644 index 00000000..35a47d70 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_domain_info.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_dns_domain_info +short_description: Gather information about the Vultr DNS domains available. +description: + - Gather information about DNS domains available in Vultr. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr DNS domains information + ngine_io.vultr.vultr_dns_domains_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_dns_domain_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_dns_domain_info: + description: Response from Vultr API + returned: success + type: complex + contains: + domain: + description: Name of the DNS Domain. + returned: success + type: str + sample: example.com + date_created: + description: Date the DNS domain was created. + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrDnsDomainInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrDnsDomainInfo, self).__init__(module, "vultr_dns_domain_info") + + self.returns = { + "date_created": dict(), + "domain": dict(), + } + + def get_domains(self): + return self.api_query(path="/v1/dns/list") + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + domain_info = AnsibleVultrDnsDomainInfo(module) + result = domain_info.get_result(domain_info.get_domains()) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_record.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_record.py new file mode 100644 index 00000000..bab11c4c --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_dns_record.py @@ -0,0 +1,376 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_dns_record +short_description: Manages DNS records on Vultr. +description: + - Create, update and remove DNS records. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - The record name (subrecord). + default: "" + aliases: [ subrecord ] + type: str + domain: + description: + - The domain the record is related to. + type: str + required: true + record_type: + description: + - Type of the record. + default: A + choices: + - A + - AAAA + - CNAME + - MX + - SRV + - CAA + - TXT + - NS + - SSHFP + aliases: [ type ] + type: str + data: + description: + - Data of the record. + - Required if C(state=present) or C(multiple=yes). + type: str + ttl: + description: + - TTL of the record. + default: 300 + type: int + multiple: + description: + - Whether to use more than one record with similar C(name) including no name and C(record_type). + - Only allowed for a few record types, e.g. C(record_type=A), C(record_type=NS) or C(record_type=MX). + - C(data) will not be updated, instead it is used as a key to find existing records. + default: no + type: bool + priority: + description: + - Priority of the record. + default: 0 + type: int + state: + description: + - State of the DNS record. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: Ensure an A record exists + ngine_io.vultr.vultr_dns_record: + name: www + domain: example.com + data: 10.10.10.10 + ttl: 3600 + +- name: Ensure a second A record exists for round robin LB + ngine_io.vultr.vultr_dns_record: + name: www + domain: example.com + data: 10.10.10.11 + ttl: 60 + multiple: yes + +- name: Ensure a CNAME record exists + ngine_io.vultr.vultr_dns_record: + name: web + record_type: CNAME + domain: example.com + data: www.example.com + +- name: Ensure MX record exists + ngine_io.vultr.vultr_dns_record: + record_type: MX + domain: example.com + data: "{{ item.data }}" + priority: "{{ item.priority }}" + multiple: yes + with_items: + - { data: mx1.example.com, priority: 10 } + - { data: mx2.example.com, priority: 10 } + - { data: mx3.example.com, priority: 20 } + +- name: Ensure a record is absent + ngine_io.vultr.vultr_dns_record: + name: www + domain: example.com + state: absent + +- name: Ensure MX record is absent in case multiple exists + ngine_io.vultr.vultr_dns_record: + record_type: MX + domain: example.com + data: mx1.example.com + multiple: yes + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_dns_record: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: The ID of the DNS record. + returned: success + type: int + sample: 1265277 + name: + description: The name of the DNS record. + returned: success + type: str + sample: web + record_type: + description: The name of the DNS record. + returned: success + type: str + sample: web + data: + description: Data of the DNS record. + returned: success + type: str + sample: 10.10.10.10 + domain: + description: Domain the DNS record is related to. + returned: success + type: str + sample: example.com + priority: + description: Priority of the DNS record. + returned: success + type: int + sample: 10 + ttl: + description: Time to live of the DNS record. + returned: success + type: int + sample: 300 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + +RECORD_TYPES = [ + 'A', + 'AAAA', + 'CNAME', + 'MX', + 'TXT', + 'NS', + 'SRV', + 'CAA', + 'SSHFP' +] + + +class AnsibleVultrDnsRecord(Vultr): + + def __init__(self, module): + super(AnsibleVultrDnsRecord, self).__init__(module, "vultr_dns_record") + + self.returns = { + 'RECORDID': dict(key='id'), + 'name': dict(), + 'record': dict(), + 'priority': dict(), + 'data': dict(), + 'type': dict(key='record_type'), + 'ttl': dict(), + } + + def get_record(self): + records = self.api_query(path="/v1/dns/records?domain=%s" % self.module.params.get('domain')) + + multiple = self.module.params.get('multiple') + data = self.module.params.get('data') + name = self.module.params.get('name') + record_type = self.module.params.get('record_type') + + result = {} + for record in records or []: + if record.get('type') != record_type: + continue + + if record.get('name') == name: + if not multiple: + if result: + self.module.fail_json(msg="More than one record with record_type=%s and name=%s params. " + "Use multiple=yes for more than one record." % (record_type, name)) + else: + result = record + elif record.get('data') == data: + return record + + return result + + def present_record(self): + record = self.get_record() + if not record: + record = self._create_record(record) + else: + record = self._update_record(record) + return record + + def _create_record(self, record): + self.result['changed'] = True + data = { + 'name': self.module.params.get('name'), + 'domain': self.module.params.get('domain'), + 'data': self.module.params.get('data'), + 'type': self.module.params.get('record_type'), + 'priority': self.module.params.get('priority'), + 'ttl': self.module.params.get('ttl'), + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/dns/create_record", + method="POST", + data=data + ) + record = self.get_record() + return record + + def _update_record(self, record): + data = { + 'RECORDID': record['RECORDID'], + 'name': self.module.params.get('name'), + 'domain': self.module.params.get('domain'), + 'data': self.module.params.get('data'), + 'type': self.module.params.get('record_type'), + 'priority': self.module.params.get('priority'), + 'ttl': self.module.params.get('ttl'), + } + has_changed = [k for k in data if k in record and data[k] != record[k]] + if has_changed: + self.result['changed'] = True + + self.result['diff']['before'] = record + self.result['diff']['after'] = record.copy() + self.result['diff']['after'].update(data) + + if not self.module.check_mode: + self.api_query( + path="/v1/dns/update_record", + method="POST", + data=data + ) + record = self.get_record() + return record + + def absent_record(self): + record = self.get_record() + if record: + self.result['changed'] = True + + data = { + 'RECORDID': record['RECORDID'], + 'domain': self.module.params.get('domain'), + } + + self.result['diff']['before'] = record + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/dns/delete_record", + method="POST", + data=data + ) + return record + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + domain=dict(type='str', required=True), + name=dict(type='str', default="", aliases=['subrecord']), + state=dict(type='str', choices=['present', 'absent'], default='present'), + ttl=dict(type='int', default=300), + record_type=dict(type='str', choices=RECORD_TYPES, default='A', aliases=['type']), + multiple=dict(type='bool', default=False), + priority=dict(type='int', default=0), + data=dict(type='str',) + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ('state', 'present', ['data']), + ('multiple', True, ['data']), + ], + + supports_check_mode=True, + ) + + vultr_record = AnsibleVultrDnsRecord(module) + if module.params.get('state') == "absent": + record = vultr_record.absent_record() + else: + record = vultr_record.present_record() + + result = vultr_record.get_result(record) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group.py new file mode 100644 index 00000000..36ef3b43 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group.py @@ -0,0 +1,201 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_firewall_group +short_description: Manages firewall groups on Vultr. +description: + - Create and remove firewall groups. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - Name of the firewall group. + required: true + aliases: [ description ] + type: str + state: + description: + - State of the firewall group. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: ensure a firewall group is present + ngine_io.vultr.vultr_firewall_group: + name: my http firewall + +- name: ensure a firewall group is absent + ngine_io.vultr.vultr_firewall_group: + name: my http firewall + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_firewall_group: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the firewall group + returned: success + type: str + sample: 1234abcd + name: + description: Name of the firewall group + returned: success + type: str + sample: my firewall group + date_created: + description: Date the firewall group was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + date_modified: + description: Date the firewall group was modified + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrFirewallGroup(Vultr): + + def __init__(self, module): + super(AnsibleVultrFirewallGroup, self).__init__(module, "vultr_firewall_group") + + self.returns = { + 'FIREWALLGROUPID': dict(key='id'), + 'description': dict(key='name'), + 'date_created': dict(), + 'date_modified': dict(), + } + + def get_firewall_group(self): + firewall_groups = self.api_query(path="/v1/firewall/group_list") + if firewall_groups: + for firewall_group_id, firewall_group_data in firewall_groups.items(): + if firewall_group_data.get('description') == self.module.params.get('name'): + return firewall_group_data + return {} + + def present_firewall_group(self): + firewall_group = self.get_firewall_group() + if not firewall_group: + firewall_group = self._create_firewall_group(firewall_group) + return firewall_group + + def _create_firewall_group(self, firewall_group): + self.result['changed'] = True + data = { + 'description': self.module.params.get('name'), + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/firewall/group_create", + method="POST", + data=data + ) + firewall_group = self.get_firewall_group() + return firewall_group + + def absent_firewall_group(self): + firewall_group = self.get_firewall_group() + if firewall_group: + self.result['changed'] = True + + data = { + 'FIREWALLGROUPID': firewall_group['FIREWALLGROUPID'], + } + + self.result['diff']['before'] = firewall_group + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/firewall/group_delete", + method="POST", + data=data + ) + return firewall_group + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True, aliases=['description']), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + vultr_firewall_group = AnsibleVultrFirewallGroup(module) + if module.params.get('state') == "absent": + firewall_group = vultr_firewall_group.absent_firewall_group() + else: + firewall_group = vultr_firewall_group.present_firewall_group() + + result = vultr_firewall_group.get_result(firewall_group) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group_info.py new file mode 100644 index 00000000..52b3eb0a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_group_info.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_firewall_group_info +short_description: Gather information about the Vultr firewall groups available. +description: + - Gather information about firewall groups available in Vultr. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr firewall groups information + ngine_io.vultr.vultr_firewall_group_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_firewall_group_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_firewall_group_info: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the firewall group + returned: success + type: str + sample: 1234abcd + description: + description: Name of the firewall group + returned: success + type: str + sample: my firewall group + date_created: + description: Date the firewall group was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + date_modified: + description: Date the firewall group was modified + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrFirewallGroupInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrFirewallGroupInfo, self).__init__(module, "vultr_firewall_group_info") + + self.returns = { + "FIREWALLGROUPID": dict(key='id'), + "date_created": dict(), + "date_modified": dict(), + "description": dict(), + "instance_count": dict(convert_to='int'), + "max_rule_count": dict(convert_to='int'), + "rule_count": dict(convert_to='int') + } + + def get_firewall_group(self): + return self.api_query(path="/v1/firewall/group_list") + + +def parse_fw_group_list(fwgroups_list): + if not fwgroups_list: + return [] + + return [group for id, group in fwgroups_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + fw_group_info = AnsibleVultrFirewallGroupInfo(module) + result = fw_group_info.get_result(parse_fw_group_list(fw_group_info.get_firewall_group())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_rule.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_rule.py new file mode 100644 index 00000000..f9a59b2b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_firewall_rule.py @@ -0,0 +1,384 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_firewall_rule +short_description: Manages firewall rules on Vultr. +description: + - Create and remove firewall rules. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + group: + description: + - Name of the firewall group. + required: true + type: str + ip_version: + description: + - IP address version + choices: [ v4, v6 ] + default: v4 + aliases: [ ip_type ] + type: str + protocol: + description: + - Protocol of the firewall rule. + choices: [ icmp, tcp, udp, gre ] + default: tcp + type: str + cidr: + description: + - Network in CIDR format + - The CIDR format must match with the C(ip_version) value. + - Required if C(state=present). + - Defaulted to 0.0.0.0/0 or ::/0 depending on C(ip_version). + type: str + start_port: + description: + - Start port for the firewall rule. + - Required if C(protocol) is tcp or udp and I(state=present). + aliases: [ port ] + type: int + end_port: + description: + - End port for the firewall rule. + - Only considered if C(protocol) is tcp or udp and I(state=present). + type: int + state: + description: + - State of the firewall rule. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: ensure a firewall rule is present + ngine_io.vultr.vultr_firewall_rule: + group: application + protocol: tcp + start_port: 8000 + end_port: 9000 + cidr: 17.17.17.0/24 + +- name: open DNS port for all ipv4 and ipv6 + ngine_io.vultr.vultr_firewall_rule: + group: dns + protocol: udp + port: 53 + ip_version: "{{ item }}" + with_items: [ v4, v6 ] + +- name: allow ping + ngine_io.vultr.vultr_firewall_rule: + group: web + protocol: icmp + +- name: ensure a firewall rule is absent + ngine_io.vultr.vultr_firewall_rule: + group: application + protocol: tcp + start_port: 8000 + end_port: 9000 + cidr: 17.17.17.0/24 + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_firewall_rule: + description: Response from Vultr API + returned: success + type: complex + contains: + rule_number: + description: Rule number of the firewall rule + returned: success + type: int + sample: 2 + action: + description: Action of the firewall rule + returned: success + type: str + sample: accept + protocol: + description: Protocol of the firewall rule + returned: success + type: str + sample: tcp + start_port: + description: Start port of the firewall rule + returned: success and protocol is tcp or udp + type: int + sample: 80 + end_port: + description: End port of the firewall rule + returned: success and when port range and protocol is tcp or udp + type: int + sample: 8080 + cidr: + description: CIDR of the firewall rule (IPv4 or IPv6) + returned: success and when port range + type: str + sample: 0.0.0.0/0 + group: + description: Firewall group the rule is into. + returned: success + type: str + sample: web +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrFirewallRule(Vultr): + + def __init__(self, module): + super(AnsibleVultrFirewallRule, self).__init__(module, "vultr_firewall_rule") + + self.returns = { + 'rulenumber': dict(key='rule_number'), + 'action': dict(), + 'protocol': dict(), + 'start_port': dict(convert_to='int'), + 'end_port': dict(convert_to='int'), + 'cidr': dict(), + 'group': dict(), + } + self.firewall_group = None + + def get_firewall_group(self): + if self.firewall_group is not None: + return self.firewall_group + + firewall_groups = self.api_query(path="/v1/firewall/group_list") + if firewall_groups: + for firewall_group_id, firewall_group_data in firewall_groups.items(): + if firewall_group_data.get('description') == self.module.params.get('group'): + self.firewall_group = firewall_group_data + return self.firewall_group + self.fail_json(msg="Firewall group not found: %s" % self.module.params.get('group')) + + def _transform_cidr(self): + cidr = self.module.params.get('cidr') + ip_version = self.module.params.get('ip_version') + if cidr is None: + if ip_version == "v6": + cidr = "::/0" + else: + cidr = "0.0.0.0/0" + elif cidr.count('/') != 1: + self.fail_json(msg="CIDR has an invalid format: %s" % cidr) + + return cidr.split('/') + + def get_firewall_rule(self): + ip_version = self.module.params.get('ip_version') + firewall_group_id = self.get_firewall_group()['FIREWALLGROUPID'] + + firewall_rules = self.api_query( + path="/v1/firewall/rule_list" + "?FIREWALLGROUPID=%s" + "&direction=in" + "&ip_type=%s" + % (firewall_group_id, ip_version)) + + if firewall_rules: + subnet, subnet_size = self._transform_cidr() + + for firewall_rule_id, firewall_rule_data in firewall_rules.items(): + if firewall_rule_data.get('protocol') != self.module.params.get('protocol'): + continue + + if ip_version == 'v4' and (firewall_rule_data.get('subnet') or "0.0.0.0") != subnet: + continue + + if ip_version == 'v6' and (firewall_rule_data.get('subnet') or "::") != subnet: + continue + + if int(firewall_rule_data.get('subnet_size')) != int(subnet_size): + continue + + if firewall_rule_data.get('protocol') in ['tcp', 'udp']: + rule_port = firewall_rule_data.get('port') + + end_port = self.module.params.get('end_port') + start_port = self.module.params.get('start_port') + + # Port range "8000 - 8080" from the API + if ' - ' in rule_port: + if end_port is None: + continue + + port_range = "%s - %s" % (start_port, end_port) + if rule_port == port_range: + return firewall_rule_data + + # Single port + elif int(rule_port) == start_port: + return firewall_rule_data + + else: + return firewall_rule_data + + return {} + + def present_firewall_rule(self): + firewall_rule = self.get_firewall_rule() + if not firewall_rule: + firewall_rule = self._create_firewall_rule(firewall_rule) + return firewall_rule + + def _create_firewall_rule(self, firewall_rule): + protocol = self.module.params.get('protocol') + if protocol in ['tcp', 'udp']: + start_port = self.module.params.get('start_port') + + if start_port is None: + self.module.fail_on_missing_params(['start_port']) + + end_port = self.module.params.get('end_port') + if end_port is not None: + + if start_port >= end_port: + self.module.fail_json(msg="end_port must be higher than start_port") + + port_range = "%s:%s" % (start_port, end_port) + else: + port_range = start_port + else: + port_range = None + + self.result['changed'] = True + + subnet, subnet_size = self._transform_cidr() + + data = { + 'FIREWALLGROUPID': self.get_firewall_group()['FIREWALLGROUPID'], + 'direction': 'in', # currently the only option + 'ip_type': self.module.params.get('ip_version'), + 'protocol': protocol, + 'subnet': subnet, + 'subnet_size': subnet_size, + 'port': port_range + } + + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/firewall/rule_create", + method="POST", + data=data + ) + firewall_rule = self.get_firewall_rule() + return firewall_rule + + def absent_firewall_rule(self): + firewall_rule = self.get_firewall_rule() + if firewall_rule: + self.result['changed'] = True + + data = { + 'FIREWALLGROUPID': self.get_firewall_group()['FIREWALLGROUPID'], + 'rulenumber': firewall_rule['rulenumber'] + } + + self.result['diff']['before'] = firewall_rule + + if not self.module.check_mode: + self.api_query( + path="/v1/firewall/rule_delete", + method="POST", + data=data + ) + return firewall_rule + + def get_result(self, resource): + if resource: + if 'port' in resource and resource['protocol'] in ['tcp', 'udp']: + if ' - ' in resource['port']: + resource['start_port'], resource['end_port'] = resource['port'].split(' - ') + else: + resource['start_port'] = resource['port'] + if 'subnet' in resource: + resource['cidr'] = "%s/%s" % (resource['subnet'], resource['subnet_size']) + resource['group'] = self.get_firewall_group()['description'] + return super(AnsibleVultrFirewallRule, self).get_result(resource) + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + group=dict(type='str', required=True), + start_port=dict(type='int', aliases=['port']), + end_port=dict(type='int'), + protocol=dict(type='str', choices=['tcp', 'udp', 'gre', 'icmp'], default='tcp'), + cidr=dict(type='str',), + ip_version=dict(type='str', choices=['v4', 'v6'], default='v4', aliases=['ip_type']), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + vultr_firewall_rule = AnsibleVultrFirewallRule(module) + if module.params.get('state') == "absent": + firewall_rule = vultr_firewall_rule.absent_firewall_rule() + else: + firewall_rule = vultr_firewall_rule.present_firewall_rule() + + result = vultr_firewall_rule.get_result(firewall_rule) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network.py new file mode 100644 index 00000000..3992e3d1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network.py @@ -0,0 +1,232 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_network +short_description: Manages networks on Vultr. +description: + - Manage networks on Vultr. A network cannot be updated. It needs to be deleted and re-created. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +options: + name: + description: + - Name of the network. + required: true + aliases: [ description, label ] + type: str + cidr: + description: + - The CIDR IPv4 network block to be used when attaching servers to this network. Required if I(state=present). + type: str + region: + description: + - Region the network is deployed into. Required if I(state=present). + type: str + state: + description: + - State of the network. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: Ensure a network is present + ngine_io.vultr.vultr_network: + name: mynet + cidr: 192.168.42.0/24 + region: Amsterdam + +- name: Ensure a network is absent + ngine_io.vultr.vultr_network: + name: mynet + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_network: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the network + returned: success + type: str + sample: "net5b62c6dc63ef5" + name: + description: Name (label) of the network + returned: success + type: str + sample: "mynetwork" + date_created: + description: Date when the network was created + returned: success + type: str + sample: "2018-08-02 08:54:52" + region: + description: Region the network was deployed into + returned: success + type: str + sample: "Amsterdam" + v4_subnet: + description: IPv4 Network address + returned: success + type: str + sample: "192.168.42.0" + v4_subnet_mask: + description: Ipv4 Network mask + returned: success + type: int + sample: 24 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrNetwork(Vultr): + + def __init__(self, module): + super(AnsibleVultrNetwork, self).__init__(module, "vultr_network") + + self.returns = { + 'NETWORKID': dict(key='id'), + 'DCID': dict(key='region', transform=self._get_region_name), + 'date_created': dict(), + 'description': dict(key='name'), + 'v4_subnet': dict(), + 'v4_subnet_mask': dict(convert_to='int'), + } + + def _get_region_name(self, region_id=None): + return self.get_region().get('name') + + def get_network(self): + networks = self.api_query(path="/v1/network/list") + if networks: + for id, network in networks.items(): + if network.get('description') == self.module.params.get('name'): + return network + return {} + + def present_network(self): + network = self.get_network() + if not network: + network = self._create_network(network) + return network + + def _create_network(self, network): + self.result['changed'] = True + data = { + 'description': self.module.params.get('name'), + 'DCID': self.get_region()['DCID'], + 'v4_subnet': self.module.params.get('cidr').split('/')[0], + 'v4_subnet_mask': self.module.params.get('cidr').split('/')[1] + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/network/create", + method="POST", + data=data + ) + network = self.get_network() + return network + + def absent_network(self): + network = self.get_network() + if network: + self.result['changed'] = True + + data = { + 'NETWORKID': network['NETWORKID'], + } + + self.result['diff']['before'] = network + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/network/destroy", + method="POST", + data=data + ) + return network + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True, aliases=['description', 'label']), + cidr=dict(type='str',), + region=dict(type='str',), + state=dict(choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[['state', 'present', ['cidr', 'region']]] + ) + + vultr_network = AnsibleVultrNetwork(module) + if module.params.get('state') == "absent": + network = vultr_network.absent_network() + else: + network = vultr_network.present_network() + + result = vultr_network.get_result(network) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network_info.py new file mode 100644 index 00000000..85f6471a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_network_info.py @@ -0,0 +1,156 @@ +#!/usr/bin/python +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_network_info +short_description: Gather information about the Vultr networks available. +description: + - Gather information about networks available in Vultr. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr networks information + ngine_io.vultr.vultr_network_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_network_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_network_info: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the network + returned: success + type: str + sample: "net5b62c6dc63ef5" + name: + description: Name (label) of the network + returned: success + type: str + sample: "mynetwork" + date_created: + description: Date when the network was created + returned: success + type: str + sample: "2018-08-02 08:54:52" + region: + description: Region the network was deployed into + returned: success + type: str + sample: "Amsterdam" + v4_subnet: + description: IPv4 Network address + returned: success + type: str + sample: "192.168.42.0" + v4_subnet_mask: + description: Ipv4 Network mask + returned: success + type: int + sample: 24 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrNetworkInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrNetworkInfo, self).__init__(module, "vultr_network_info") + + self.returns = { + 'DCID': dict(key='region', transform=self._get_region_name), + 'NETWORKID': dict(key='id'), + 'date_created': dict(), + 'description': dict(key='name'), + 'v4_subnet': dict(), + 'v4_subnet_mask': dict(convert_to='int'), + } + + def _get_region_name(self, region): + return self.query_resource_by_key( + key='DCID', + value=region, + resource='regions', + use_cache=True + )['name'] + + def get_networks(self): + return self.api_query(path="/v1/network/list") + + +def parse_network_list(network_list): + if isinstance(network_list, list): + return [] + + return [network for id, network in network_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + network_info = AnsibleVultrNetworkInfo(module) + result = network_info.get_result(parse_network_list(network_info.get_networks())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_os_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_os_info.py new file mode 100644 index 00000000..258b50d5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_os_info.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_os_info +short_description: Get information about the Vultr OSes available. +description: + - Get infos about OSes available to boot servers. +version_added: "0.1.0" +author: + - "Yanis Guenane (@Spredzy)" + - "René Moser (@resmo)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Get Vultr OSes infos + ngine_io.vultr.vultr_os_info: + register: results + +- name: Print the gathered infos + debug: + var: results.vultr_os_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_os_info: + description: Response from Vultr API as list + returned: available + type: complex + contains: + arch: + description: OS Architecture + returned: success + type: str + sample: x64 + family: + description: OS family + returned: success + type: str + sample: openbsd + name: + description: OS name + returned: success + type: str + sample: OpenBSD 6 x64 + windows: + description: OS is a MS Windows + returned: success + type: bool +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrOSInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrOSInfo, self).__init__(module, "vultr_os_info") + + self.returns = { + "OSID": dict(key='id', convert_to='int'), + "arch": dict(), + "family": dict(), + "name": dict(), + "windows": dict(convert_to='bool') + } + + def get_oses(self): + return self.api_query(path="/v1/os/list") + + +def parse_oses_list(oses_list): + return [os for id, os in oses_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + os_info = AnsibleVultrOSInfo(module) + result = os_info.get_result(parse_oses_list(os_info.get_oses())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_baremetal_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_baremetal_info.py new file mode 100644 index 00000000..040ca2d9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_baremetal_info.py @@ -0,0 +1,140 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# (c) 2020, Simon Baerlocher <s.baerlocher@sbaerlocher.ch> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: vultr_plan_baremetal_info +short_description: Gather information about the Vultr Bare Metal plans available. +description: + - Gather information about Bare Metal plans available to boot servers. +version_added: "0.3.0" +author: "Simon Baerlocher (@sbaerlocher)" +extends_documentation_fragment: +- ngine_io.vultr.vultr +''' + +EXAMPLES = r''' +- name: Gather Vultr Bare Metal plans information + ngine_io.vultr.vultr_baremetal_plan_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_baremetal_plan_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_plan_baremetal_info: + description: Response from Vultr API + returned: success + type: complex + contains: + plan: + description: List of the Bare Metal plans available. + returned: success + type: list + sample: [{ + "available_locations": [ + 1 + ], + "bandwidth": 40.0, + "bandwidth_gb": 40960, + "disk": 110, + "id": 118, + "name": "32768 MB RAM,110 GB SSD,40.00 TB BW", + "plan_type": "DEDICATED", + "price_per_month": 240.0, + "ram": 32768, + "vcpu_count": 8, + "windows": false + }] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrPlanInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrPlanInfo, self).__init__(module, "vultr_plan_baremetal_info") + + self.returns = { + "METALPLANID": dict(key='id', convert_to='int'), + "available_locations": dict(), + "bandwidth_tb": dict(convert_to='int'), + "disk": dict(), + "name": dict(), + "plan_type": dict(), + "price_per_month": dict(convert_to='float'), + "ram": dict(convert_to='int'), + "windows": dict(convert_to='bool'), + "cpu_count": dict(convert_to='int'), + "cpu_model": dict(), + "cpu_thread_count": dict(convert_to='int'), + } + + def get_plans_baremetal(self): + return self.api_query(path="/v1/plans/list_baremetal") + + +def parse_plans_baremetal_list(plans_baremetal_list): + return [plan_baremetal for id, plan_baremetal in plans_baremetal_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + plan_baremetal_info = AnsibleVultrPlanInfo(module) + result = plan_baremetal_info.get_result(parse_plans_baremetal_list(plan_baremetal_info.get_plans_baremetal())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_info.py new file mode 100644 index 00000000..3783ab8b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_plan_info.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_plan_info +short_description: Gather information about the Vultr plans available. +description: + - Gather information about plans available to boot servers. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr +''' + +EXAMPLES = r''' +- name: Gather Vultr plans information + ngine_io.vultr.vultr_plan_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_plan_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_plan_info: + description: Response from Vultr API + returned: success + type: complex + contains: + plan: + description: List of the plans available. + returned: success + type: list + sample: [{ + "available_locations": [ + 1 + ], + "bandwidth": 40.0, + "bandwidth_gb": 40960, + "disk": 110, + "id": 118, + "name": "32768 MB RAM,110 GB SSD,40.00 TB BW", + "plan_type": "DEDICATED", + "price_per_month": 240.0, + "ram": 32768, + "vcpu_count": 8, + "windows": false + }] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrPlanInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrPlanInfo, self).__init__(module, "vultr_plan_info") + + self.returns = { + "VPSPLANID": dict(key='id', convert_to='int'), + "available_locations": dict(), + "bandwidth": dict(convert_to='float'), + "bandwidth_gb": dict(convert_to='int'), + "disk": dict(convert_to='int'), + "name": dict(), + "plan_type": dict(), + "price_per_month": dict(convert_to='float'), + "ram": dict(convert_to='int'), + "vcpu_count": dict(convert_to='int'), + "windows": dict(convert_to='bool') + } + + def get_plans(self): + return self.api_query(path="/v1/plans/list") + + +def parse_plans_list(plans_list): + return [plan for id, plan in plans_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + plan_info = AnsibleVultrPlanInfo(module) + result = plan_info.get_result(parse_plans_list(plan_info.get_plans())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_region_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_region_info.py new file mode 100644 index 00000000..2080d2d5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_region_info.py @@ -0,0 +1,129 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_region_info +short_description: Gather information about the Vultr regions available. +description: + - Gather information about regions available to boot servers. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr regions information + ngine_io.vultr.vultr_region_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_region_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_region_info: + description: Response from Vultr API + returned: success + type: list + sample: [ + { + "block_storage": false, + "continent": "Europe", + "country": "GB", + "ddos_protection": true, + "id": 8, + "name": "London", + "regioncode": "LHR", + "state": "" + } + ] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrRegionInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrRegionInfo, self).__init__(module, "vultr_region_info") + + self.returns = { + "DCID": dict(key='id', convert_to='int'), + "block_storage": dict(convert_to='bool'), + "continent": dict(), + "country": dict(), + "ddos_protection": dict(convert_to='bool'), + "name": dict(), + "regioncode": dict(), + "state": dict() + } + + def get_regions(self): + return self.api_query(path="/v1/regions/list") + + +def parse_regions_list(regions_list): + return [region for id, region in regions_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + region_info = AnsibleVultrRegionInfo(module) + result = region_info.get_result(parse_regions_list(region_info.get_regions())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server.py new file mode 100644 index 00000000..bda14846 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server.py @@ -0,0 +1,933 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_server +short_description: Manages virtual servers on Vultr. +description: + - Deploy, start, stop, update, restart, reinstall servers. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - Name of the server. + required: true + aliases: [ label ] + type: str + hostname: + description: + - The hostname to assign to this server. + type: str + os: + description: + - The operating system name or ID. + - Required if the server does not yet exist and is not restoring from a snapshot. + type: str + snapshot: + description: + - Name or ID of the snapshot to restore the server from. + type: str + firewall_group: + description: + - The firewall group description or ID to assign this server to. + type: str + plan: + description: + - Plan name or ID to use for the server. + - Required if the server does not yet exist. + type: str + force: + description: + - Force stop/start the server if required to apply changes + - Otherwise a running server will not be changed. + type: bool + default: no + notify_activate: + description: + - Whether to send an activation email when the server is ready or not. + - Only considered on creation. + type: bool + default: false + private_network_enabled: + description: + - Whether to enable private networking or not. + type: bool + auto_backup_enabled: + description: + - Whether to enable automatic backups or not. + type: bool + ipv6_enabled: + description: + - Whether to enable IPv6 or not. + type: bool + tag: + description: + - Tag for the server. + type: str + user_data: + description: + - User data to be passed to the server. + type: str + startup_script: + description: + - Name or ID of the startup script to execute on boot. + - Only considered while creating the server. + type: str + ssh_keys: + description: + - List of SSH key names or IDs passed to the server on creation. + aliases: [ ssh_key ] + type: list + elements: str + reserved_ip_v4: + description: + - IP address of the floating IP to use as the main IP of this server. + - Only considered on creation. + type: str + region: + description: + - Region name or ID the server is deployed into. + - Required if the server does not yet exist. + type: str + state: + description: + - State of the server. + default: present + choices: [ present, absent, restarted, reinstalled, started, stopped ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: create server + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 7 x64 + plan: 1024 MB RAM,25 GB SSD,1.00 TB BW + ssh_keys: + - my_key + - your_key + region: Amsterdam + state: present + +- name: ensure a server is present and started + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 7 x64 + plan: 1024 MB RAM,25 GB SSD,1.00 TB BW + firewall_group: my_group + ssh_key: my_key + region: Amsterdam + state: started + +- name: ensure a server is present and stopped provisioned using IDs + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + os: "167" + plan: "201" + region: "7" + state: stopped + +- name: ensure an existing server is stopped + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + state: stopped + +- name: ensure an existing server is started + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + state: started + +- name: ensure a server is absent + ngine_io.vultr.vultr_server: + name: "{{ vultr_server_name }}" + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_server: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + id: + description: ID of the server + returned: success + type: str + sample: 10194376 + name: + description: Name (label) of the server + returned: success + type: str + sample: "ansible-test-vm" + plan: + description: Plan used for the server + returned: success + type: str + sample: "1024 MB RAM,25 GB SSD,1.00 TB BW" + allowed_bandwidth_gb: + description: Allowed bandwidth to use in GB + returned: success + type: int + sample: 1000 + auto_backup_enabled: + description: Whether automatic backups are enabled + returned: success + type: bool + sample: false + cost_per_month: + description: Cost per month for the server + returned: success + type: float + sample: 5.00 + current_bandwidth_gb: + description: Current bandwidth used for the server + returned: success + type: int + sample: 0 + date_created: + description: Date when the server was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + default_password: + description: Password to login as root into the server + returned: success + type: str + sample: "!p3EWYJm$qDWYaFr" + disk: + description: Information about the disk + returned: success + type: str + sample: "Virtual 25 GB" + v4_gateway: + description: IPv4 gateway + returned: success + type: str + sample: "45.32.232.1" + internal_ip: + description: Internal IP + returned: success + type: str + sample: "" + kvm_url: + description: URL to the VNC + returned: success + type: str + sample: "https://my.vultr.com/subs/vps/novnc/api.php?data=xyz" + region: + description: Region the server was deployed into + returned: success + type: str + sample: "Amsterdam" + v4_main_ip: + description: Main IPv4 + returned: success + type: str + sample: "45.32.233.154" + v4_netmask: + description: Netmask IPv4 + returned: success + type: str + sample: "255.255.254.0" + os: + description: Operating system used for the server + returned: success + type: str + sample: "CentOS 6 x64" + firewall_group: + description: Firewall group the server is assigned to + returned: success and available + type: str + sample: "CentOS 6 x64" + pending_charges: + description: Pending charges + returned: success + type: float + sample: 0.01 + power_status: + description: Power status of the server + returned: success + type: str + sample: "running" + ram: + description: Information about the RAM size + returned: success + type: str + sample: "1024 MB" + server_state: + description: State about the server + returned: success + type: str + sample: "ok" + status: + description: Status about the deployment of the server + returned: success + type: str + sample: "active" + tag: + description: TBD + returned: success + type: str + sample: "" + v6_main_ip: + description: Main IPv6 + returned: success + type: str + sample: "" + v6_network: + description: Network IPv6 + returned: success + type: str + sample: "" + v6_network_size: + description: Network size IPv6 + returned: success + type: str + sample: "" + v6_networks: + description: Networks IPv6 + returned: success + type: list + sample: [] + vcpu_count: + description: Virtual CPU count + returned: success + type: int + sample: 1 +''' + +import time +import base64 +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text, to_bytes +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrServer(Vultr): + + def __init__(self, module): + super(AnsibleVultrServer, self).__init__(module, "vultr_server") + + self.server = None + self.returns = { + 'SUBID': dict(key='id'), + 'label': dict(key='name'), + 'date_created': dict(), + 'allowed_bandwidth_gb': dict(convert_to='int'), + 'auto_backups': dict(key='auto_backup_enabled', convert_to='bool'), + 'current_bandwidth_gb': dict(), + 'kvm_url': dict(), + 'default_password': dict(), + 'internal_ip': dict(), + 'disk': dict(), + 'cost_per_month': dict(convert_to='float'), + 'location': dict(key='region'), + 'main_ip': dict(key='v4_main_ip'), + 'network_v4': dict(key='v4_network'), + 'gateway_v4': dict(key='v4_gateway'), + 'os': dict(), + 'pending_charges': dict(convert_to='float'), + 'power_status': dict(), + 'ram': dict(), + 'plan': dict(), + 'server_state': dict(), + 'status': dict(), + 'firewall_group': dict(), + 'tag': dict(), + 'v6_main_ip': dict(), + 'v6_network': dict(), + 'v6_network_size': dict(), + 'v6_networks': dict(), + 'vcpu_count': dict(convert_to='int'), + } + self.server_power_state = None + + def get_startup_script(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('startup_script'), + resource='startupscript', + ) + + def get_os(self): + if self.module.params.get('snapshot'): + os_name = 'Snapshot' + else: + os_name = self.module.params.get('os') + + return self.query_resource_by_key( + key='name', + value=os_name, + resource='os', + use_cache=True, + id_key='OSID', + ) + + def get_snapshot(self): + return self.query_resource_by_key( + key='description', + value=self.module.params.get('snapshot'), + resource='snapshot', + id_key='SNAPSHOTID', + ) + + def get_ssh_keys(self): + ssh_key_names = self.module.params.get('ssh_keys') + if not ssh_key_names: + return [] + + ssh_keys = [] + for ssh_key_name in ssh_key_names: + ssh_key = self.query_resource_by_key( + key='name', + value=ssh_key_name, + resource='sshkey', + use_cache=True, + id_key='SSHKEYID', + ) + if ssh_key: + ssh_keys.append(ssh_key) + return ssh_keys + + def get_region(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('region'), + resource='regions', + use_cache=True, + id_key='DCID', + ) + + def get_firewall_group(self): + return self.query_resource_by_key( + key='description', + value=self.module.params.get('firewall_group'), + resource='firewall', + query_by='group_list', + id_key='FIREWALLGROUPID' + ) + + def get_user_data(self): + user_data = self.module.params.get('user_data') + if user_data is not None: + user_data = to_text(base64.b64encode(to_bytes(user_data))) + return user_data + + def get_server_user_data(self, server): + if not server or not server.get('SUBID'): + return None + + user_data = self.api_query(path="/v1/server/get_user_data?SUBID=%s" % server.get('SUBID')) + return user_data.get('userdata') + + def get_server(self, refresh=False): + if self.server is None or refresh: + self.server = None + server_list = self.api_query(path="/v1/server/list") + if server_list: + for server_id, server_data in server_list.items(): + if server_data.get('label') == self.module.params.get('name'): + self.server = server_data + + plan = self.query_resource_by_key( + key='VPSPLANID', + value=server_data['VPSPLANID'], + resource='plans', + use_cache=True + ) + self.server['plan'] = plan.get('name') + + os = self.query_resource_by_key( + key='OSID', + value=int(server_data['OSID']), + resource='os', + use_cache=True + ) + self.server['os'] = os.get('name') + + fwg_id = server_data.get('FIREWALLGROUPID') + fw = self.query_resource_by_key( + key='FIREWALLGROUPID', + value=server_data.get('FIREWALLGROUPID') if fwg_id and fwg_id != "0" else None, + resource='firewall', + query_by='group_list', + use_cache=True + ) + self.server['firewall_group'] = fw.get('description') + return self.server + + def present_server(self, start_server=True): + server = self.get_server() + if not server: + server = self._create_server(server=server) + else: + server = self._update_server(server=server, start_server=start_server) + return server + + def _create_server(self, server=None): + required_params = [ + 'os', + 'plan', + 'region', + ] + + snapshot_restore = self.module.params.get('snapshot') is not None + if snapshot_restore: + required_params.remove('os') + + self.module.fail_on_missing_params(required_params=required_params) + + self.result['changed'] = True + if not self.module.check_mode: + data = { + 'DCID': self.get_region().get('DCID'), + 'VPSPLANID': self.get_plan().get('VPSPLANID'), + 'FIREWALLGROUPID': self.get_firewall_group().get('FIREWALLGROUPID'), + 'OSID': self.get_os().get('OSID'), + 'SNAPSHOTID': self.get_snapshot().get('SNAPSHOTID'), + 'label': self.module.params.get('name'), + 'hostname': self.module.params.get('hostname'), + 'SSHKEYID': ','.join([ssh_key['SSHKEYID'] for ssh_key in self.get_ssh_keys()]), + 'enable_ipv6': self.get_yes_or_no('ipv6_enabled'), + 'enable_private_network': self.get_yes_or_no('private_network_enabled'), + 'auto_backups': self.get_yes_or_no('auto_backup_enabled'), + 'notify_activate': self.get_yes_or_no('notify_activate'), + 'tag': self.module.params.get('tag'), + 'reserved_ip_v4': self.module.params.get('reserved_ip_v4'), + 'user_data': self.get_user_data(), + 'SCRIPTID': self.get_startup_script().get('SCRIPTID'), + } + self.api_query( + path="/v1/server/create", + method="POST", + data=data + ) + server = self._wait_for_state(key='status', state='active') + server = self._wait_for_state(state='running', timeout=3600 if snapshot_restore else 60) + return server + + def _update_auto_backups_setting(self, server, start_server): + auto_backup_enabled_changed = self.switch_enable_disable(server, 'auto_backup_enabled', 'auto_backups') + + if auto_backup_enabled_changed: + if auto_backup_enabled_changed == "enable" and server['auto_backups'] == 'disable': + self.module.warn("Backups are disabled. Once disabled, backups can only be enabled again by customer support") + else: + server, warned = self._handle_power_status_for_update(server, start_server) + if not warned: + self.result['changed'] = True + self.result['diff']['before']['auto_backup_enabled'] = server.get('auto_backups') + self.result['diff']['after']['auto_backup_enabled'] = self.get_yes_or_no('auto_backup_enabled') + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/backup_%s" % auto_backup_enabled_changed, + method="POST", + data=data + ) + return server + + def _update_ipv6_setting(self, server, start_server): + ipv6_enabled_changed = self.switch_enable_disable(server, 'ipv6_enabled', 'v6_main_ip') + + if ipv6_enabled_changed: + if ipv6_enabled_changed == "disable": + self.module.warn("The Vultr API does not allow to disable IPv6") + else: + server, warned = self._handle_power_status_for_update(server, start_server) + if not warned: + self.result['changed'] = True + self.result['diff']['before']['ipv6_enabled'] = False + self.result['diff']['after']['ipv6_enabled'] = True + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/ipv6_%s" % ipv6_enabled_changed, + method="POST", + data=data + ) + server = self._wait_for_state(key='v6_main_ip') + return server + + def _update_private_network_setting(self, server, start_server): + private_network_enabled_changed = self.switch_enable_disable(server, 'private_network_enabled', 'internal_ip') + if private_network_enabled_changed: + if private_network_enabled_changed == "disable": + self.module.warn("The Vultr API does not allow to disable private network") + else: + server, warned = self._handle_power_status_for_update(server, start_server) + if not warned: + self.result['changed'] = True + self.result['diff']['before']['private_network_enabled'] = False + self.result['diff']['after']['private_network_enabled'] = True + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/private_network_%s" % private_network_enabled_changed, + method="POST", + data=data + ) + return server + + def _update_plan_setting(self, server, start_server): + # Verify the exising plan is not discontined by Vultr and therefore won't be found by the API + server_plan = self.get_plan(plan=server.get('VPSPLANID'), optional=True) + if not server_plan: + plan = self.get_plan(optional=True) + if not plan: + self.module.warn("The plan used to create the server is not longer available as well as the desired plan. Assuming same plan, keeping as is.") + return server + else: + plan = self.get_plan() + + plan_changed = True if plan and plan['VPSPLANID'] != server.get('VPSPLANID') else False + if plan_changed: + server, warned = self._handle_power_status_for_update(server, start_server) + if not warned: + self.result['changed'] = True + self.result['diff']['before']['plan'] = server.get('plan') + self.result['diff']['after']['plan'] = plan['name'] + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'VPSPLANID': plan['VPSPLANID'], + } + self.api_query( + path="/v1/server/upgrade_plan", + method="POST", + data=data + ) + return server + + def _handle_power_status_for_update(self, server, start_server): + # Remember the power state before we handle any action + if self.server_power_state is None: + self.server_power_state = server['power_status'] + + # A stopped server can be updated + if self.server_power_state == "stopped": + return server, False + + # A running server must be forced to update unless the wanted state is stopped + elif self.module.params.get('force') or not start_server: + warned = False + if not self.module.check_mode: + # Some update APIs would restart the VM, we handle the restart manually + # by stopping the server and start it at the end of the changes + server = self.stop_server(skip_results=True) + + # Warn the user that a running server won't get changed + else: + warned = True + self.module.warn("Some changes won't be applied to running instances. " + + "Use force=true to allow the instance %s to be stopped/started." % server['label']) + + return server, warned + + def _update_server(self, server=None, start_server=True): + # Wait for server to unlock if restoring + if server.get('os').strip() == 'Snapshot': + server = self._wait_for_state(key='server_status', state='ok', timeout=3600) + + # Update auto backups settings, stops server + server = self._update_auto_backups_setting(server=server, start_server=start_server) + + # Update IPv6 settings, stops server + server = self._update_ipv6_setting(server=server, start_server=start_server) + + # Update private network settings, stops server + server = self._update_private_network_setting(server=server, start_server=start_server) + + # Update plan settings, stops server + server = self._update_plan_setting(server=server, start_server=start_server) + + # User data + user_data = self.get_user_data() + server_user_data = self.get_server_user_data(server=server) + if user_data is not None and user_data != server_user_data: + self.result['changed'] = True + self.result['diff']['before']['user_data'] = server_user_data + self.result['diff']['after']['user_data'] = user_data + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'userdata': user_data, + } + self.api_query( + path="/v1/server/set_user_data", + method="POST", + data=data + ) + + # Tags + tag = self.module.params.get('tag') + if tag is not None and tag != server.get('tag'): + self.result['changed'] = True + self.result['diff']['before']['tag'] = server.get('tag') + self.result['diff']['after']['tag'] = tag + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'tag': tag, + } + self.api_query( + path="/v1/server/tag_set", + method="POST", + data=data + ) + + # Firewall group + firewall_group = self.get_firewall_group() + if firewall_group and firewall_group.get('description') != server.get('firewall_group'): + self.result['changed'] = True + self.result['diff']['before']['firewall_group'] = server.get('firewall_group') + self.result['diff']['after']['firewall_group'] = firewall_group.get('description') + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'FIREWALLGROUPID': firewall_group.get('FIREWALLGROUPID'), + } + self.api_query( + path="/v1/server/firewall_group_set", + method="POST", + data=data + ) + # Start server again if it was running before the changes + if not self.module.check_mode: + if self.server_power_state in ['starting', 'running'] and start_server: + server = self.start_server(skip_results=True) + + server = self._wait_for_state(key='status', state='active') + return server + + def absent_server(self): + server = self.get_server() + if server: + self.result['changed'] = True + self.result['diff']['before']['id'] = server['SUBID'] + self.result['diff']['after']['id'] = "" + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/destroy", + method="POST", + data=data + ) + for s in range(0, 60): + if server is not None: + break + time.sleep(2) + server = self.get_server(refresh=True) + else: + self.fail_json(msg="Wait for server '%s' to get deleted timed out" % server['label']) + return server + + def restart_server(self): + self.result['changed'] = True + server = self.get_server() + if server: + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/reboot", + method="POST", + data=data + ) + server = self._wait_for_state(state='running') + return server + + def reinstall_server(self): + self.result['changed'] = True + server = self.get_server() + if server: + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/reinstall", + method="POST", + data=data + ) + server = self._wait_for_state(state='running') + return server + + def _wait_for_state(self, key='power_status', state=None, timeout=60): + time.sleep(1) + server = self.get_server(refresh=True) + for s in range(0, timeout): + # Check for Truely if wanted state is None + if state is None and server.get(key): + break + elif server.get(key) == state: + break + time.sleep(2) + server = self.get_server(refresh=True) + + # Timed out + else: + if state is None: + msg = "Wait for '%s' timed out" % key + else: + msg = "Wait for '%s' to get into state '%s' timed out" % (key, state) + self.fail_json(msg=msg) + return server + + def start_server(self, skip_results=False): + server = self.get_server() + if server: + if server['power_status'] == 'starting': + server = self._wait_for_state(state='running') + + elif server['power_status'] != 'running': + if not skip_results: + self.result['changed'] = True + self.result['diff']['before']['power_status'] = server['power_status'] + self.result['diff']['after']['power_status'] = "running" + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/server/start", + method="POST", + data=data + ) + server = self._wait_for_state(state='running') + return server + + def stop_server(self, skip_results=False): + server = self.get_server() + if server and server['power_status'] != "stopped": + if not skip_results: + self.result['changed'] = True + self.result['diff']['before']['power_status'] = server['power_status'] + self.result['diff']['after']['power_status'] = "stopped" + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + } + self.api_query( + path="/v1/server/halt", + method="POST", + data=data + ) + server = self._wait_for_state(state='stopped') + return server + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(required=True, aliases=['label']), + hostname=dict(type='str'), + os=dict(type='str'), + snapshot=dict(type='str'), + plan=dict(type='str'), + force=dict(type='bool', default=False), + notify_activate=dict(type='bool', default=False), + private_network_enabled=dict(type='bool'), + auto_backup_enabled=dict(type='bool'), + ipv6_enabled=dict(type='bool'), + tag=dict(type='str'), + reserved_ip_v4=dict(type='str'), + firewall_group=dict(type='str'), + startup_script=dict(type='str'), + user_data=dict(type='str'), + ssh_keys=dict(type='list', elements='str', aliases=['ssh_key']), + region=dict(type='str'), + state=dict(choices=['present', 'absent', 'restarted', 'reinstalled', 'started', 'stopped'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + vultr_server = AnsibleVultrServer(module) + if module.params.get('state') == "absent": + server = vultr_server.absent_server() + else: + if module.params.get('state') == "started": + server = vultr_server.present_server() + server = vultr_server.start_server() + elif module.params.get('state') == "stopped": + server = vultr_server.present_server(start_server=False) + server = vultr_server.stop_server() + elif module.params.get('state') == "restarted": + server = vultr_server.present_server() + server = vultr_server.restart_server() + elif module.params.get('state') == "reinstalled": + server = vultr_server.reinstall_server() + else: + server = vultr_server.present_server() + + result = vultr_server.get_result(server) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_baremetal.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_baremetal.py new file mode 100644 index 00000000..a054d93a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_baremetal.py @@ -0,0 +1,548 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# (c) 2019, Nate River <vitikc@gmail.com> +# (c) 2020, Simon Baerlocher <s.baerlocher@sbaerlocher.ch> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = r''' +--- +module: vultr_server_baremetal +short_description: Manages baremetal servers on Vultr. +description: + - Deploy and destroy servers. +version_added: "0.3.0" +author: + - "Nate River (@vitikc)" + - "Simon Baerlocher (@sbaerlocher)" +options: + name: + description: + - Name of the server. + required: true + aliases: [ label ] + type: str + hostname: + description: + - The hostname to assign to this server. + type: str + os: + description: + - The operating system name or ID. + - Required if the server does not yet exist and is not restoring from a snapshot. + type: str + plan: + description: + - Plan name or ID to use for the server. + - Required if the server does not yet exist. + type: str + notify_activate: + description: + - Whether to send an activation email when the server is ready or not. + - Only considered on creation. + type: bool + default: false + ipv6_enabled: + description: + - Whether to enable IPv6 or not. + type: bool + tag: + description: + - Tag for the server. + type: str + user_data: + description: + - User data to be passed to the server. + type: str + startup_script: + description: + - Name or ID of the startup script to execute on boot. + - Only considered while creating the server. + type: str + ssh_keys: + description: + - List of SSH key names or IDs passed to the server on creation. + aliases: [ ssh_key ] + type: list + elements: str + reserved_ip_v4: + description: + - IP address of the floating IP to use as the main IP of this server. + - Only considered on creation. + type: str + region: + description: + - Region name or ID the server is deployed into. + - Required if the server does not yet exist. + type: str + state: + description: + - State of the server. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr +''' + +EXAMPLES = r''' +- name: create server + ngine_io.vultr.vultr_server_baremetal: + name: "{{ vultr_server_baremetal_name }}" + os: Debian 9 x64 (stretch) + plan: 32768 MB RAM,2x 240 GB SSD,5.00 TB BW + region: Amsterdam + +- name: ensure a server is absent + ngine_io.vultr.vultr_server_baremetal: + name: "{{ vultr_server_baremetal_name }}" + state: absent +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_server_baremetal: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + id: + description: ID of the server + returned: success + type: str + sample: 900000 + name: + description: Name (label) of the server + returned: success + type: str + sample: "ansible-test-baremetal" + plan: + description: Plan used for the server + returned: success + type: str + sample: "32768 MB RAM,2x 240 GB SSD,5.00 TB BW" + allowed_bandwidth_gb: + description: Allowed bandwidth to use in GB + returned: success + type: int + sample: 1000 + cost_per_month: + description: Cost per month for the server + returned: success + type: float + sample: 120.00 + current_bandwidth_gb: + description: Current bandwidth used for the server + returned: success + type: int + sample: 0 + date_created: + description: Date when the server was created + returned: success + type: str + sample: "2017-04-12 18:45:41" + default_password: + description: Password to login as root into the server + returned: success + type: str + sample: "ab81u!ryranq" + disk: + description: Information about the disk + returned: success + type: str + sample: "SSD 250 GB" + v4_gateway: + description: IPv4 gateway + returned: success + type: str + sample: "203.0.113.1" + internal_ip: + description: Internal IP + returned: success + type: str + sample: "" + region: + description: Region the server was deployed into + returned: success + type: str + sample: "Amsterdam" + v4_main_ip: + description: Main IPv4 + returned: success + type: str + sample: "203.0.113.10" + v4_netmask: + description: Netmask IPv4 + returned: success + type: str + sample: "255.255.255.0" + os: + description: Operating system used for the server + returned: success + type: str + sample: "Debian 9 x64" + pending_charges: + description: Pending charges + returned: success + type: float + sample: 0.18 + ram: + description: Information about the RAM size + returned: success + type: str + sample: "32768 MB" + status: + description: Status about the deployment of the server + returned: success + type: str + sample: "active" + tag: + description: Server tag + returned: success + type: str + sample: "my tag" + v6_main_ip: + description: Main IPv6 + returned: success + type: str + sample: "2001:DB8:9000::100" + v6_network: + description: Network IPv6 + returned: success + type: str + sample: "2001:DB8:9000::" + v6_network_size: + description: Network size IPv6 + returned: success + type: int + sample: 64 + v6_networks: + description: Networks IPv6 + returned: success + type: list + sample: [] +''' + +import time +import base64 +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text, to_bytes +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrServerBareMetal(Vultr): + + def __init__(self, module): + super(AnsibleVultrServerBareMetal, self).__init__(module, "vultr_server_baremetal") + + self.server = None + self.returns = { + 'SUBID': dict(key='id'), + 'label': dict(key='name'), + 'date_created': dict(), + 'allowed_bandwidth_gb': dict(convert_to='int'), + 'current_bandwidth_gb': dict(), + 'default_password': dict(), + 'internal_ip': dict(), + 'disk': dict(), + 'cost_per_month': dict(convert_to='float'), + 'location': dict(key='region'), + 'main_ip': dict(key='v4_main_ip'), + 'network_v4': dict(key='v4_network'), + 'gateway_v4': dict(key='v4_gateway'), + 'os': dict(), + 'pending_charges': dict(convert_to='float'), + 'ram': dict(), + 'plan': dict(), + 'status': dict(), + 'tag': dict(), + 'v6_main_ip': dict(), + 'v6_network': dict(), + 'v6_network_size': dict(), + 'v6_networks': dict(), + } + self.server_power_state = None + + def get_startup_script(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('startup_script'), + resource='startupscript', + ) + + def get_os(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('os'), + resource='os', + use_cache=True + ) + + def get_ssh_keys(self): + ssh_key_names = self.module.params.get('ssh_keys') + if not ssh_key_names: + return [] + + ssh_keys = [] + for ssh_key_name in ssh_key_names: + ssh_key = self.query_resource_by_key( + key='name', + value=ssh_key_name, + resource='sshkey', + use_cache=True + ) + if ssh_key: + ssh_keys.append(ssh_key) + return ssh_keys + + def get_region(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('region'), + resource='regions', + use_cache=True + ) + + def get_plan(self): + return self.query_resource_by_key( + key='name', + value=self.module.params.get('plan'), + resource='plans', + query_by='list_baremetal', + use_cache=True + ) + + def get_user_data(self): + user_data = self.module.params.get('user_data') + if user_data is not None: + user_data = to_text(base64.b64encode(to_bytes(user_data))) + return user_data + + def get_server_user_data(self, server): + if not server or not server.get('SUBID'): + return None + + user_data = self.api_query(path="/v1/baremetal/get_user_data?SUBID=%s" % server.get('SUBID')) + return user_data.get('userdata') + + def get_server(self, refresh=False): + if self.server is None or refresh: + self.server = None + server_list = self.api_query(path="/v1/baremetal/list") + if server_list: + for server_id, server_data in server_list.items(): + if server_data.get('label') == self.module.params.get('name'): + self.server = server_data + + plan = self.query_resource_by_key( + key='METALPLANID', + value=server_data['METALPLANID'], + resource='plans', + query_by='list_baremetal', + use_cache=True + ) + self.server['plan'] = plan.get('name') + + os = self.query_resource_by_key( + key='OSID', + value=int(server_data['OSID']), + resource='os', + use_cache=True + ) + self.server['os'] = os.get('name') + return self.server + + def _wait_for_state(self, key='status', state=None): + time.sleep(1) + server = self.get_server(refresh=True) + for s in range(0, 500): + if state is None and server.get(key): + break + elif server.get(key) == state: + break + time.sleep(2) + server = self.get_server(refresh=True) + + # Timed out + else: + if state is None: + msg = "Wait for '%s' timed out" % key + else: + msg = "Wait for '%s' to get into state '%s' timed out" % (key, state) + self.fail_json(msg=msg) + return server + + def present_server(self, start_server=True): + server = self.get_server() + if not server: + server = self._create_server(server=server) + else: + server = self._update_server(server=server, start_server=start_server) + return server + + def _create_server(self, server=None): + required_params = [ + 'os', + 'plan', + 'region', + ] + self.module.fail_on_missing_params(required_params=required_params) + + self.result['changed'] = True + if not self.module.check_mode: + data = { + 'DCID': self.get_region().get('DCID'), + 'METALPLANID': self.get_plan().get('METALPLANID'), + 'OSID': self.get_os().get('OSID'), + 'label': self.module.params.get('name'), + 'hostname': self.module.params.get('hostname'), + 'SSHKEYID': ','.join([ssh_key['SSHKEYID'] for ssh_key in self.get_ssh_keys()]), + 'enable_ipv6': self.get_yes_or_no('ipv6_enabled'), + 'notify_activate': self.get_yes_or_no('notify_activate'), + 'tag': self.module.params.get('tag'), + 'reserved_ip_v4': self.module.params.get('reserved_ip_v4'), + 'user_data': self.get_user_data(), + 'SCRIPTID': self.get_startup_script().get('SCRIPTID'), + } + self.api_query( + path="/v1/baremetal/create", + method="POST", + data=data + ) + server = self._wait_for_state(key='status', state='active') + return server + + def _update_server(self, server=None, start_server=True): + + # Update plan settings + # server = self._update_plan_setting(server=server, start_server=start_server) + + # User data + user_data = self.get_user_data() + server_user_data = self.get_server_user_data(server=server) + if user_data is not None and user_data != server_user_data: + self.result['changed'] = True + self.result['diff']['before']['user_data'] = server_user_data + self.result['diff']['after']['user_data'] = user_data + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'userdata': user_data, + } + self.api_query( + path="/v1/baremetal/set_user_data", + method="POST", + data=data + ) + + # Tags + tag = self.module.params.get('tag') + if tag is not None and tag != server.get('tag'): + self.result['changed'] = True + self.result['diff']['before']['tag'] = server.get('tag') + self.result['diff']['after']['tag'] = tag + + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'], + 'tag': tag, + } + self.api_query( + path="/v1/baremetal/tag_set", + method="POST", + data=data + ) + return server + + def absent_server(self): + server = self.get_server() + if server: + self.result['changed'] = True + self.result['diff']['before']['id'] = server['SUBID'] + self.result['diff']['after']['id'] = "" + if not self.module.check_mode: + data = { + 'SUBID': server['SUBID'] + } + self.api_query( + path="/v1/baremetal/destroy", + method="POST", + data=data + ) + for s in range(0, 60): + if server is not None: + break + time.sleep(2) + server = self.get_server(refresh=True) + else: + self.fail_json(msg="Wait for server '%s' to get deleted timed out" % server['label']) + return server + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(required=True, aliases=['label']), + hostname=dict(type='str',), + os=dict(type='str',), + plan=dict(type='str',), + notify_activate=dict(type='bool', default=False), + ipv6_enabled=dict(type='bool'), + tag=dict(type='str',), + reserved_ip_v4=dict(type='str',), + startup_script=dict(type='str',), + user_data=dict(type='str',), + ssh_keys=dict(type='list', elements='str', aliases=['ssh_key']), + region=dict(type='str',), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + vultr_server_baremetal = AnsibleVultrServerBareMetal(module) + if module.params.get('state') == "absent": + server = vultr_server_baremetal.absent_server() + else: + server = vultr_server_baremetal.present_server() + + result = vultr_server_baremetal.get_result(server) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_info.py new file mode 100644 index 00000000..4d84bdc8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_server_info.py @@ -0,0 +1,300 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_server_info +short_description: Gather information about the Vultr servers available. +description: + - Gather information about servers available. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr servers information + ngine_io.vultr.vultr_server_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_server_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_server_info: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the server + returned: success + type: str + sample: 10194376 + name: + description: Name (label) of the server + returned: success + type: str + sample: "ansible-test-vm" + plan: + description: Plan used for the server + returned: success + type: str + sample: "1024 MB RAM,25 GB SSD,1.00 TB BW" + allowed_bandwidth_gb: + description: Allowed bandwidth to use in GB + returned: success + type: int + sample: 1000 + auto_backup_enabled: + description: Whether automatic backups are enabled + returned: success + type: bool + sample: false + cost_per_month: + description: Cost per month for the server + returned: success + type: float + sample: 5.00 + current_bandwidth_gb: + description: Current bandwidth used for the server + returned: success + type: int + sample: 0 + date_created: + description: Date when the server was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + default_password: + description: Password to login as root into the server + returned: success + type: str + sample: "!p3EWYJm$qDWYaFr" + disk: + description: Information about the disk + returned: success + type: str + sample: "Virtual 25 GB" + v4_gateway: + description: IPv4 gateway + returned: success + type: str + sample: "45.32.232.1" + internal_ip: + description: Internal IP + returned: success + type: str + sample: "" + kvm_url: + description: URL to the VNC + returned: success + type: str + sample: "https://my.vultr.com/subs/vps/novnc/api.php?data=xyz" + region: + description: Region the server was deployed into + returned: success + type: str + sample: "Amsterdam" + v4_main_ip: + description: Main IPv4 + returned: success + type: str + sample: "45.32.233.154" + v4_netmask: + description: Netmask IPv4 + returned: success + type: str + sample: "255.255.254.0" + os: + description: Operating system used for the server + returned: success + type: str + sample: "CentOS 6 x64" + firewall_group: + description: Firewall group the server is assigned to + returned: success and available + type: str + sample: "CentOS 6 x64" + pending_charges: + description: Pending charges + returned: success + type: float + sample: 0.01 + power_status: + description: Power status of the server + returned: success + type: str + sample: "running" + ram: + description: Information about the RAM size + returned: success + type: str + sample: "1024 MB" + server_state: + description: State about the server + returned: success + type: str + sample: "ok" + status: + description: Status about the deployment of the server + returned: success + type: str + sample: "active" + tag: + description: TBD + returned: success + type: str + sample: "" + v6_main_ip: + description: Main IPv6 + returned: success + type: str + sample: "" + v6_network: + description: Network IPv6 + returned: success + type: str + sample: "" + v6_network_size: + description: Network size IPv6 + returned: success + type: str + sample: "" + v6_networks: + description: Networks IPv6 + returned: success + type: list + sample: [] + vcpu_count: + description: Virtual CPU count + returned: success + type: int + sample: 1 +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrServerInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrServerInfo, self).__init__(module, "vultr_server_info") + + self.returns = { + "APPID": dict(key='application', convert_to='int', transform=self._get_application_name), + "FIREWALLGROUPID": dict(key='firewallgroup', transform=self._get_firewallgroup_name), + "SUBID": dict(key='id', convert_to='int'), + "VPSPLANID": dict(key='plan', convert_to='int', transform=self._get_plan_name), + "allowed_bandwidth_gb": dict(convert_to='int'), + 'auto_backups': dict(key='auto_backup_enabled', convert_to='bool'), + "cost_per_month": dict(convert_to='float'), + "current_bandwidth_gb": dict(convert_to='float'), + "date_created": dict(), + "default_password": dict(), + "disk": dict(), + "gateway_v4": dict(key='v4_gateway'), + "internal_ip": dict(), + "kvm_url": dict(), + "label": dict(key='name'), + "location": dict(key='region'), + "main_ip": dict(key='v4_main_ip'), + "netmask_v4": dict(key='v4_netmask'), + "os": dict(), + "pending_charges": dict(convert_to='float'), + "power_status": dict(), + "ram": dict(), + "server_state": dict(), + "status": dict(), + "tag": dict(), + "v6_main_ip": dict(), + "v6_network": dict(), + "v6_network_size": dict(), + "v6_networks": dict(), + "vcpu_count": dict(convert_to='int'), + } + + def _get_application_name(self, application): + if application == 0: + return None + + return self.get_application(application, 'APPID').get('name') + + def _get_firewallgroup_name(self, firewallgroup): + if firewallgroup == 0: + return None + + return self.get_firewallgroup(firewallgroup, 'FIREWALLGROUPID').get('description') + + def _get_plan_name(self, plan): + return self.get_plan(plan, 'VPSPLANID', optional=True).get('name') or 'N/A' + + def get_servers(self): + return self.api_query(path="/v1/server/list") + + +def parse_servers_list(servers_list): + return [server for id, server in servers_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + server_info = AnsibleVultrServerInfo(module) + result = server_info.get_result(parse_servers_list(server_info.get_servers())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key.py new file mode 100644 index 00000000..6c9a56a8 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: vultr_ssh_key +short_description: Manages ssh keys on Vultr. +description: + - Create, update and remove ssh keys. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - Name of the ssh key. + required: true + type: str + ssh_key: + description: + - SSH public key. + - Required if C(state=present). + type: str + state: + description: + - State of the ssh key. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = ''' +- name: ensure an SSH key is present + ngine_io.vultr.vultr_ssh_key: + name: my ssh key + ssh_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + +- name: ensure an SSH key is absent + ngine_io.vultr.vultr_ssh_key: + name: my ssh key + state: absent +''' + +RETURN = ''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_ssh_key: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the ssh key + returned: success + type: str + sample: 5904bc6ed9234 + name: + description: Name of the ssh key + returned: success + type: str + sample: my ssh key + date_created: + description: Date the ssh key was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + ssh_key: + description: SSH public key + returned: success + type: str + sample: "ssh-rsa AA... someother@example.com" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrSshKey(Vultr): + + def __init__(self, module): + super(AnsibleVultrSshKey, self).__init__(module, "vultr_ssh_key") + + self.returns = { + 'SSHKEYID': dict(key='id'), + 'name': dict(), + 'ssh_key': dict(), + 'date_created': dict(), + } + + def get_ssh_key(self): + ssh_keys = self.api_query(path="/v1/sshkey/list") + if ssh_keys: + for ssh_key_id, ssh_key_data in ssh_keys.items(): + if ssh_key_data.get('name') == self.module.params.get('name'): + return ssh_key_data + return {} + + def present_ssh_key(self): + ssh_key = self.get_ssh_key() + if not ssh_key: + ssh_key = self._create_ssh_key(ssh_key) + else: + ssh_key = self._update_ssh_key(ssh_key) + return ssh_key + + def _create_ssh_key(self, ssh_key): + self.result['changed'] = True + data = { + 'name': self.module.params.get('name'), + 'ssh_key': self.module.params.get('ssh_key'), + } + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/sshkey/create", + method="POST", + data=data + ) + ssh_key = self.get_ssh_key() + return ssh_key + + def _update_ssh_key(self, ssh_key): + param_ssh_key = self.module.params.get('ssh_key') + if param_ssh_key != ssh_key['ssh_key']: + self.result['changed'] = True + + data = { + 'SSHKEYID': ssh_key['SSHKEYID'], + 'ssh_key': param_ssh_key, + } + + self.result['diff']['before'] = ssh_key + self.result['diff']['after'] = data + self.result['diff']['after'].update({'date_created': ssh_key['date_created']}) + + if not self.module.check_mode: + self.api_query( + path="/v1/sshkey/update", + method="POST", + data=data + ) + ssh_key = self.get_ssh_key() + return ssh_key + + def absent_ssh_key(self): + ssh_key = self.get_ssh_key() + if ssh_key: + self.result['changed'] = True + + data = { + 'SSHKEYID': ssh_key['SSHKEYID'], + } + + self.result['diff']['before'] = ssh_key + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/sshkey/destroy", + method="POST", + data=data + ) + return ssh_key + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + ssh_key=dict(type='str',), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ('state', 'present', ['ssh_key']), + ], + supports_check_mode=True, + ) + + vultr_ssh_key = AnsibleVultrSshKey(module) + if module.params.get('state') == "absent": + ssh_key = vultr_ssh_key.absent_ssh_key() + else: + ssh_key = vultr_ssh_key.present_ssh_key() + + result = vultr_ssh_key.get_result(ssh_key) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key_info.py new file mode 100644 index 00000000..51b2960b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_ssh_key_info.py @@ -0,0 +1,141 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> + +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_ssh_key_info +short_description: Get information about the Vultr SSH keys available. +description: + - Get infos about SSH keys available. +version_added: "0.1.0" +author: + - "Yanis Guenane (@Spredzy)" + - "René Moser (@resmo)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Get Vultr SSH keys infos + ngine_io.vultr.vultr_ssh_key_info: + register: result + +- name: Print the infos + debug: + var: result.vultr_ssh_key_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_ssh_key_info: + description: Response from Vultr API as list + returned: success + type: complex + contains: + id: + description: ID of the ssh key + returned: success + type: str + sample: 5904bc6ed9234 + name: + description: Name of the ssh key + returned: success + type: str + sample: my ssh key + date_created: + description: Date the ssh key was created + returned: success + type: str + sample: "2017-08-26 12:47:48" + ssh_key: + description: SSH public key + returned: success + type: str + sample: "ssh-rsa AA... someother@example.com" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrSSHKeyInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrSSHKeyInfo, self).__init__(module, "vultr_ssh_key_info") + + self.returns = { + 'SSHKEYID': dict(key='id'), + 'name': dict(), + 'ssh_key': dict(), + 'date_created': dict(), + } + + def get_sshkeys(self): + return self.api_query(path="/v1/sshkey/list") + + +def parse_keys_list(keys_list): + if not keys_list: + return [] + + return [key for id, key in keys_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + sshkey_info = AnsibleVultrSSHKeyInfo(module) + result = sshkey_info.get_result(parse_keys_list(sshkey_info.get_sshkeys())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script.py new file mode 100644 index 00000000..dfa58af7 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script.py @@ -0,0 +1,265 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_startup_script +short_description: Manages startup scripts on Vultr. +description: + - Create, update and remove startup scripts. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - The script name. + required: true + type: str + script_type: + description: + - The script type, can not be changed once created. + default: boot + choices: [ boot, pxe ] + aliases: [ type ] + type: str + script: + description: + - The script source code. + - Required if I(state=present). + type: str + state: + description: + - State of the script. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: ensure a pxe script exists, source from a file + ngine_io.vultr.vultr_startup_script: + name: my_web_script + script_type: pxe + script: "{{ lookup('file', 'path/to/script') }}" + +- name: ensure a boot script exists + ngine_io.vultr.vultr_startup_script: + name: vultr_startup_script + script: "#!/bin/bash\necho Hello World > /root/hello" + +- name: ensure a script is absent + ngine_io.vultr.vultr_startup_script: + name: my_web_script + state: absent +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_startup_script: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the startup script. + returned: success + type: str + sample: 249395 + name: + description: Name of the startup script. + returned: success + type: str + sample: my startup script + script: + description: The source code of the startup script. + returned: success + type: str + sample: "#!/bin/bash\necho Hello World > /root/hello" + script_type: + description: The type of the startup script. + returned: success + type: str + sample: pxe + date_created: + description: Date the startup script was created. + returned: success + type: str + sample: "2017-08-26 12:47:48" + date_modified: + description: Date the startup script was modified. + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrStartupScript(Vultr): + + def __init__(self, module): + super(AnsibleVultrStartupScript, self).__init__(module, "vultr_startup_script") + + self.returns = { + 'SCRIPTID': dict(key='id'), + 'type': dict(key='script_type'), + 'name': dict(), + 'script': dict(), + 'date_created': dict(), + 'date_modified': dict(), + } + + def get_script(self): + scripts = self.api_query(path="/v1/startupscript/list") + name = self.module.params.get('name') + if scripts: + for script_id, script_data in scripts.items(): + if script_data.get('name') == name: + return script_data + return {} + + def present_script(self): + script = self.get_script() + if not script: + script = self._create_script(script) + else: + script = self._update_script(script) + return script + + def _create_script(self, script): + self.result['changed'] = True + + data = { + 'name': self.module.params.get('name'), + 'script': self.module.params.get('script'), + 'type': self.module.params.get('script_type'), + } + + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + self.api_query( + path="/v1/startupscript/create", + method="POST", + data=data + ) + script = self.get_script() + return script + + def _update_script(self, script): + if script['script'] != self.module.params.get('script'): + self.result['changed'] = True + + data = { + 'SCRIPTID': script['SCRIPTID'], + 'script': self.module.params.get('script'), + } + + self.result['diff']['before'] = script + self.result['diff']['after'] = script.copy() + self.result['diff']['after'].update(data) + + if not self.module.check_mode: + self.api_query( + path="/v1/startupscript/update", + method="POST", + data=data + ) + script = self.get_script() + return script + + def absent_script(self): + script = self.get_script() + if script: + self.result['changed'] = True + + data = { + 'SCRIPTID': script['SCRIPTID'], + } + + self.result['diff']['before'] = script + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/startupscript/destroy", + method="POST", + data=data + ) + return script + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + script=dict(type='str',), + script_type=dict(type='str', default='boot', choices=['boot', 'pxe'], aliases=['type']), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ('state', 'present', ['script']), + ], + supports_check_mode=True, + ) + + vultr_script = AnsibleVultrStartupScript(module) + if module.params.get('state') == "absent": + script = vultr_script.absent_script() + else: + script = vultr_script.present_script() + + result = vultr_script.get_result(script) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script_info.py new file mode 100644 index 00000000..262954ad --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_startup_script_info.py @@ -0,0 +1,149 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_startup_script_info +short_description: Gather information about the Vultr startup scripts available. +description: + - Gather information about vultr_startup_scripts available. +version_added: "0.1.0" +author: "Yanis Guenane (@Spredzy)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Gather Vultr startup scripts information + ngine_io.vultr.vultr_startup_script_info: + register: result + +- name: Print the gathered information + debug: + var: result.vultr_startup_script_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_startup_script_info: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the startup script. + returned: success + type: str + sample: 249395 + name: + description: Name of the startup script. + returned: success + type: str + sample: my startup script + script: + description: The source code of the startup script. + returned: success + type: str + sample: "#!/bin/bash\necho Hello World > /root/hello" + type: + description: The type of the startup script. + returned: success + type: str + sample: pxe + date_created: + description: Date the startup script was created. + returned: success + type: str + sample: "2017-08-26 12:47:48" + date_modified: + description: Date the startup script was modified. + returned: success + type: str + sample: "2017-08-26 12:47:48" +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrStartupScriptInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrStartupScriptInfo, self).__init__(module, "vultr_startup_script_info") + + self.returns = { + "SCRIPTID": dict(key='id', convert_to='int'), + "date_created": dict(), + "date_modified": dict(), + "name": dict(), + "script": dict(), + "type": dict(), + } + + def get_startupscripts(self): + return self.api_query(path="/v1/startupscript/list") + + +def parse_startupscript_list(startupscipts_list): + if not startupscipts_list: + return [] + + return [startupscript for id, startupscript in startupscipts_list.items()] + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + startupscript_info = AnsibleVultrStartupScriptInfo(module) + result = startupscript_info.get_result(parse_startupscript_list(startupscript_info.get_startupscripts())) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user.py new file mode 100644 index 00000000..53ebfeac --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user.py @@ -0,0 +1,326 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_user +short_description: Manages users on Vultr. +description: + - Create, update and remove users. +version_added: "0.1.0" +author: "René Moser (@resmo)" +options: + name: + description: + - Name of the user + required: true + type: str + email: + description: + - Email of the user. + - Required if C(state=present). + type: str + password: + description: + - Password of the user. + - Only considered while creating a user or when C(force=yes). + type: str + force: + description: + - Password will only be changed with enforcement. + default: no + type: bool + api_enabled: + description: + - Whether the API is enabled or not. + default: yes + type: bool + acls: + description: + - List of ACLs this users should have, see U(https://www.vultr.com/api/#user_user_list). + - Required if C(state=present). + - One or more of the choices list, some depend on each other. + choices: + - manage_users + - subscriptions + - provisioning + - billing + - support + - abuse + - dns + - upgrade + aliases: [ acl ] + type: list + elements: str + state: + description: + - State of the user. + default: present + choices: [ present, absent ] + type: str +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Ensure a user exists + ngine_io.vultr.vultr_user: + name: john + email: john.doe@example.com + password: s3cr3t + acls: + - upgrade + - dns + - manage_users + - subscriptions + - upgrade + +- name: Remove a user + ngine_io.vultr.vultr_user: + name: john + state: absent +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_user: + description: Response from Vultr API + returned: success + type: complex + contains: + id: + description: ID of the user. + returned: success + type: str + sample: 5904bc6ed9234 + api_key: + description: API key of the user. + returned: only after resource was created + type: str + sample: 567E6K567E6K567E6K567E6K567E6K + name: + description: Name of the user. + returned: success + type: str + sample: john + email: + description: Email of the user. + returned: success + type: str + sample: "john@example.com" + api_enabled: + description: Whether the API is enabled or not. + returned: success + type: bool + sample: true + acls: + description: List of ACLs of the user. + returned: success + type: list + sample: [manage_users, support, upgrade] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +ACLS = [ + 'manage_users', + 'subscriptions', + 'provisioning', + 'billing', + 'support', + 'abuse', + 'dns', + 'upgrade', +] + + +class AnsibleVultrUser(Vultr): + + def __init__(self, module): + super(AnsibleVultrUser, self).__init__(module, "vultr_user") + + self.returns = { + 'USERID': dict(key='id'), + 'name': dict(), + 'email': dict(), + 'api_enabled': dict(convert_to='bool'), + 'acls': dict(), + 'api_key': dict() + } + + def _common_args(self): + return { + 'name': self.module.params.get('name'), + 'email': self.module.params.get('email'), + 'acls': self.module.params.get('acls'), + 'password': self.module.params.get('password'), + 'api_enabled': self.get_yes_or_no('api_enabled'), + } + + def get_user(self): + users = self.api_query(path="/v1/user/list") + for user in users or []: + if user.get('name') == self.module.params.get('name'): + return user + return {} + + def present_user(self): + user = self.get_user() + if not user: + user = self._create_user(user) + else: + user = self._update_user(user) + return user + + def _has_changed(self, user, data): + for k, v in data.items(): + if k not in user: + continue + elif isinstance(v, list): + for i in v: + if i not in user[k]: + return True + elif data[k] != user[k]: + return True + return False + + def _create_user(self, user): + self.module.fail_on_missing_params(required_params=['password']) + + self.result['changed'] = True + + data = self._common_args() + self.result['diff']['before'] = {} + self.result['diff']['after'] = data + + if not self.module.check_mode: + user = self.api_query( + path="/v1/user/create", + method="POST", + data=data + ) + user.update(self.get_user()) + return user + + def _update_user(self, user): + data = self._common_args() + data.update({ + 'USERID': user['USERID'], + }) + + force = self.module.params.get('force') + if not force: + del data['password'] + + if force or self._has_changed(user=user, data=data): + self.result['changed'] = True + + self.result['diff']['before'] = user + self.result['diff']['after'] = user.copy() + self.result['diff']['after'].update(data) + + if not self.module.check_mode: + self.api_query( + path="/v1/user/update", + method="POST", + data=data + ) + user = self.get_user() + return user + + def absent_user(self): + user = self.get_user() + if user: + self.result['changed'] = True + + data = { + 'USERID': user['USERID'], + } + + self.result['diff']['before'] = user + self.result['diff']['after'] = {} + + if not self.module.check_mode: + self.api_query( + path="/v1/user/delete", + method="POST", + data=data + ) + return user + + +def main(): + argument_spec = vultr_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + email=dict(type='str',), + password=dict(type='str', no_log=True), + force=dict(type='bool', default=False), + api_enabled=dict(type='bool', default=True), + acls=dict(type='list', elements='str', choices=ACLS, aliases=['acl']), + state=dict(type='str', choices=['present', 'absent'], default='present'), + )) + + module = AnsibleModule( + argument_spec=argument_spec, + required_if=[ + ('state', 'present', ['email', 'acls']), + ], + supports_check_mode=True, + ) + + vultr_user = AnsibleVultrUser(module) + if module.params.get('state') == "absent": + user = vultr_user.absent_user() + else: + user = vultr_user.present_user() + + result = vultr_user.get_result(user) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user_info.py b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user_info.py new file mode 100644 index 00000000..f07d0eff --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/plugins/modules/vultr_user_info.py @@ -0,0 +1,144 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: vultr_user_info +short_description: Get information about the Vultr user available. +version_added: "0.1.0" +description: + - Get infos about users available in Vultr. +author: + - "Yanis Guenane (@Spredzy)" + - "René Moser (@resmo)" +extends_documentation_fragment: +- ngine_io.vultr.vultr + +''' + +EXAMPLES = r''' +- name: Get Vultr user infos + ngine_io.vultr.vultr_user_info: + register: result + +- name: Print the infos + debug: + var: result.vultr_user_info +''' + +RETURN = r''' +--- +vultr_api: + description: Response from Vultr API with a few additions/modification + returned: success + type: complex + contains: + api_account: + description: Account used in the ini file to select the key + returned: success + type: str + sample: default + api_timeout: + description: Timeout used for the API requests + returned: success + type: int + sample: 60 + api_retries: + description: Amount of max retries for the API requests + returned: success + type: int + sample: 5 + api_retry_max_delay: + description: Exponential backoff delay in seconds between retries up to this max delay value. + returned: success + type: int + sample: 12 + api_endpoint: + description: Endpoint used for the API requests + returned: success + type: str + sample: "https://api.vultr.com" +vultr_user_info: + description: Response from Vultr API as list + returned: available + type: complex + contains: + id: + description: ID of the user. + returned: success + type: str + sample: 5904bc6ed9234 + api_key: + description: API key of the user. + returned: only after resource was created + type: str + sample: 567E6K567E6K567E6K567E6K567E6K + name: + description: Name of the user. + returned: success + type: str + sample: john + email: + description: Email of the user. + returned: success + type: str + sample: "john@example.com" + api_enabled: + description: Whether the API is enabled or not. + returned: success + type: bool + sample: true + acls: + description: List of ACLs of the user. + returned: success + type: list + sample: [ manage_users, support, upgrade ] +''' + +from ansible.module_utils.basic import AnsibleModule +from ..module_utils.vultr import ( + Vultr, + vultr_argument_spec, +) + + +class AnsibleVultrUserInfo(Vultr): + + def __init__(self, module): + super(AnsibleVultrUserInfo, self).__init__(module, "vultr_user_info") + + self.returns = { + "USERID": dict(key='id'), + "acls": dict(), + "api_enabled": dict(), + "email": dict(), + "name": dict() + } + + def get_regions(self): + return self.api_query(path="/v1/user/list") + + +def main(): + argument_spec = vultr_argument_spec() + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + user_info = AnsibleVultrUserInfo(module) + result = user_info.get_result(user_info.get_regions()) + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/aliases new file mode 100644 index 00000000..1e955564 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/aliases @@ -0,0 +1,2 @@ +cloud/vultr +smoke/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/tasks/main.yml new file mode 100644 index 00000000..1dfa8c44 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_account_info/tasks/main.yml @@ -0,0 +1,27 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test get vultr account infos in check mode + vultr_account_info: + check_mode: yes + register: result + +- name: verify test get vultr account infos in check mode + assert: + that: + - result.vultr_account_info.balance is defined + - result.vultr_account_info.last_payment_amount is defined + - result.vultr_account_info.last_payment_date is defined + - result.vultr_account_info.last_payment_amount is defined + +- name: test get vultr account fact + vultr_account_info: + register: result + +- name: verify test get vultr account infos + assert: + that: + - result.vultr_account_info.balance is defined + - result.vultr_account_info.last_payment_amount is defined + - result.vultr_account_info.last_payment_date is defined + - result.vultr_account_info.last_payment_amount is defined diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/defaults/main.yml new file mode 100644 index 00000000..b2c0ebe3 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/defaults/main.yml @@ -0,0 +1,14 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_block_storage_name: "{{ vultr_resource_prefix }}-volume" +vultr_block_storage_size: 10 +vultr_block_storage_size_2: 12 +vultr_block_storage_size_3: 14 +vultr_block_storage_region: New Jersey + +vultr_server_name: "{{ vultr_resource_prefix }}_vm_for_attachment" +vultr_server_ssh_keys: +- name: key1 + key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= mail@renemoser.net" + +vultr_server_plan_1: 1024 MB RAM,25 GB SSD,1.00 TB BW diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/tasks/main.yml new file mode 100644 index 00000000..3b802ace --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage/tasks/main.yml @@ -0,0 +1,315 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: setup create ssh keys + vultr_ssh_key: + name: "{{ item.name }}" + ssh_key: "{{ item.key }}" + loop: "{{ vultr_server_ssh_keys }}" + +- name: Setup create server for attachment + # We'll use this server to test block storage attachment, later + # in this test suite. + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 8 x64 + plan: "{{ vultr_server_plan_1 }}" + ssh_keys: + - key1 + region: "{{ vultr_block_storage_region }}" + state: started + register: result_server_setup +- name: verify setup create server + assert: + that: + - result_server_setup is changed + +- name: test fail if missing name + vultr_block_storage: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: size, region"' + +- name: test create block storage volume in check mode + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + register: result + check_mode: yes +- name: verify test create server in check mode + assert: + that: + - result is changed + +- name: test create block storage volume + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + register: result +- name: verify test create block storage volume + assert: + that: + - result is changed + - result.vultr_block_storage.name == "{{ vultr_block_storage_name }}" + - result.vultr_block_storage.region == "{{ vultr_block_storage_region }}" + - result.vultr_block_storage.size == 10 + +- name: test create block storage volume idempotence + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + register: result +- name: verify test block storage volume idempotence + assert: + that: + - result is not changed + - result.vultr_block_storage.name == "{{ vultr_block_storage_name }}" + - result.vultr_block_storage.region == "{{ vultr_block_storage_region }}" + - result.vultr_block_storage.size == 10 + +# volumes size can only be modified every 60s +- name: wait about 60s before resizing volume + wait_for: + timeout: 65 + +- name: test resize block storage volume + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size_2 }}" + region: "{{ vultr_block_storage_region }}" + register: result +- name: verify resize block storage volume + assert: + that: + - result is changed + - 'result.vultr_block_storage.size == {{ vultr_block_storage_size_2 | int }}' + +# volume size can only be modified every 60s +- name: wait about 60s before resizing volume + wait_for: + timeout: 65 + +- name: test resize block storage volume idempotency + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size_2 }}" + region: "{{ vultr_block_storage_region }}" + register: result +- name: verify resize block storage volume idempotency + assert: + that: + - not result.changed + - 'result.vultr_block_storage.size == {{ vultr_block_storage_size_2 | int }}' + +- name: test attaching fails if server id not provided + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: attached + register: result + ignore_errors: yes +- name: verify attaching fails if server id not provided + assert: + that: + - result is failed + - 'result.msg == "state is attached but all of the following are missing: attached_to_SUBID"' + +- name: test attach block volume in check mode + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: attached + attached_to_id: 1337 # dummy server id + register: result + check_mode: yes +- name: verify attach block volume in check mode + assert: + that: + - result is changed + - result.vultr_block_storage.attached_to_id == 1337 + +- name: test attach block volume + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: attached + attached_to_SUBID: "{{ result_server_setup.vultr_server.id | int}}" + register: result +- name: verify attach block volume + assert: + that: + - result.changed + - 'result.vultr_block_storage.attached_to_id == {{ result_server_setup.vultr_server.id | int }}' + +- name: test attach block volume idempotency + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: attached + attached_to_SUBID: "{{ result_server_setup.vultr_server.id | int }}" + register: result +- name: verify attach block volume idempotency + assert: + that: + - not result.changed + - 'result.vultr_block_storage.attached_to_id == {{ result_server_setup.vultr_server.id | int }}' + +# volume size can only be modified every 60s +- name: wait about 60s before resizing volume + wait_for: + timeout: 65 + +- name: test resize block storage volume while attaching + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size_3 }}" + region: "{{ vultr_block_storage_region }}" + state: attached + attached_to_SUBID: "{{ result_server_setup.vultr_server.id | int }}" + register: result +- name: verify resize block storage volume + assert: + that: + - result is changed + - 'result.vultr_block_storage.size == {{ vultr_block_storage_size_3 | int }}' + +- name: test attach block volume fails if attached somewhere else + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: attached + attached_to_SUBID: 1337 # some other server + register: result + ignore_errors: true +- name: verify attach block volume fails if attached somewhere else + assert: + that: + - result is failed + - 'result.msg == "Volume already attached to server {{ result_server_setup.vultr_server.id | int }}"' + +- name: test detach block volume in check mode + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: detached + register: result + check_mode: yes +- name: verify detach block volume + assert: + that: + - result is changed + - not result.vultr_block_storage.attached_to_id + +- name: test detach block volume + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: detached + register: result +- name: verify detach block volume + assert: + that: + - result is changed + - not result.vultr_block_storage.attached_to_id + +- name: test detach block volume idempotency + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + size: "{{ vultr_block_storage_size }}" + region: "{{ vultr_block_storage_region }}" + state: detached + register: result +- name: verify detach block volume idempotency + assert: + that: + - result is not changed + - not result.vultr_block_storage.attached_to_id + +- name: test destroy block storage volume in check mode + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + state: absent + register: result + check_mode: yes +- name: verify test destroy block storage volume in check mode + assert: + that: + - result is changed + - result.vultr_block_storage.name == "{{ vultr_block_storage_name }}" + +- name: test destroy block storage volume + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + state: absent + register: result +- name: verify test destroy an existing block storage volume + assert: + that: + - result is changed + - result.vultr_block_storage.name == "{{ vultr_block_storage_name }}" + +- name: test destroy an existing block storage volume idempotence + vultr_block_storage: + name: "{{ vultr_block_storage_name }}" + state: absent + register: result +- name: verify test destroy an existing block storage volume idempotence + assert: + that: + - result is not changed + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min before destroying server + wait_for: + +- name: cleanup server + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result +- name: verify test absent server + assert: + that: + - result is changed + +- name: cleanup ssh keys + vultr_ssh_key: + name: "{{ item.name }}" + ssh_key: "{{ item.key }}" + state: absent + loop: "{{ vultr_server_ssh_keys }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/defaults/main.yml new file mode 100644 index 00000000..17be33cb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/defaults/main.yml @@ -0,0 +1,5 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_block_storage_name: "{{ vultr_resource_prefix }}-volume" +vultr_block_storage_size: 10 +vultr_block_storage_region: New Jersey diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/tasks/main.yml new file mode 100644 index 00000000..1777c25e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_block_storage_info/tasks/main.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr block storage volume info - empty resource + vultr_block_storage_info: + +- name: Create the block storage volume + vultr_block_storage: + name: '{{ vultr_block_storage_name }}' + size: '{{ vultr_block_storage_size }}' + region: '{{ vultr_block_storage_region }}' + +- name: test gather vultr block storage volume info in check mode + vultr_block_storage_info: + check_mode: yes + register: result + +- name: verify test gather vultr block storage volume info in check mode + assert: + that: + - result.vultr_block_storage_info|selectattr('name','equalto','{{ vultr_block_storage_name }}') | list | count == 1 + +- name: test gather vultr block storage volume info + vultr_block_storage_info: + register: result + +- name: verify test gather vultr block storage volume info + assert: + that: + - result.vultr_block_storage_info|selectattr('name','equalto','{{ vultr_block_storage_name }}') | list | count == 1 + +- name: Delete the block storage volume + vultr_block_storage: + name: '{{ vultr_block_storage_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/defaults/main.yml new file mode 100644 index 00000000..45cbf728 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/defaults/main.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_dns_domain_name: "{{ vultr_resource_prefix }}-example-ansible.com" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/tasks/main.yml new file mode 100644 index 00000000..70678397 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain/tasks/main.yml @@ -0,0 +1,99 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_dns_domain: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: server_ip"' + +- name: test create dns domain in check mode + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + server_ip: 10.10.10.10 + register: result + check_mode: yes +- name: verify test create dns domain in check mode + assert: + that: + - result is changed + +- name: test create dns domain + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + server_ip: 10.10.10.10 + register: result +- name: verify test create dns domain + assert: + that: + - result is changed + - result.vultr_dns_domain.name == '{{ vultr_dns_domain_name }}' + +- name: test create dns domain idempotence + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + server_ip: 10.10.10.10 + register: result +- name: verify test create dns domain idempotence + assert: + that: + - result is not changed + - result.vultr_dns_domain.name == '{{ vultr_dns_domain_name }}' + +- name: test absent dns domain in check mode + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent dns domain in check mode + assert: + that: + - result is changed + - result.vultr_dns_domain.name == '{{ vultr_dns_domain_name }}' + +- name: test absent dns domain + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + state: absent + register: result +- name: verify test absent dns domain + assert: + that: + - result is changed + - result.vultr_dns_domain.name == '{{ vultr_dns_domain_name }}' + +- name: test absent dns domain idempotence + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + state: absent + register: result +- name: verify test absent dns domain idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/defaults/main.yml new file mode 100644 index 00000000..a452ee12 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/defaults/main.yml @@ -0,0 +1,4 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +dns_domain_name: "{{ vultr_resource_prefix }}-example-ansible.com" +dns_domain_server_ip: 104.24.16.59 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/tasks/main.yml new file mode 100644 index 00000000..d58aa108 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_domain_info/tasks/main.yml @@ -0,0 +1,32 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create the record + vultr_dns_domain: + name: '{{ dns_domain_name }}' + server_ip: '{{ dns_domain_server_ip }}' + +- name: test gather vultr dns domain info in check mode + vultr_dns_domain_info: + check_mode: yes + register: result + +- name: verify test gather vultr dns domain info in check mode + assert: + that: + - result.vultr_dns_domain_info|selectattr('domain','equalto','{{ dns_domain_name }}') | list | count == 1 + +- name: test gather vultr dns domain info + vultr_dns_domain_info: + register: result + +- name: verify test gather vultr dns domain info + assert: + that: + - result.vultr_dns_domain_info|selectattr('domain','equalto','{{ dns_domain_name }}') | list | count == 1 + +- name: Delete the record + vultr_dns_domain: + name: '{{ dns_domain_name }}' + server_ip: '{{ dns_domain_server_ip }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/defaults/main.yml new file mode 100644 index 00000000..fb52cfd9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/defaults/main.yml @@ -0,0 +1,39 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_dns_domain_name: "{{ vultr_resource_prefix }}-example-ansible.com" +vultr_dns_record_items: +# Single A record +- name: test-www + data: 10.10.10.10 + ttl: 400 + update_data: 10.10.10.11 + update_ttl: 200 + +# Multiple A records +- name: test-www-multiple + data: 10.10.11.10 + update_data: 10.10.11.11 + multiple: true + update_ttl: 600 + +# CNAME +- name: test-cname + data: www.ansible.com + update_data: www.ansible.ch + record_type: CNAME + +# Single Multiple MX record +- data: mx1.example-ansible.com + priority: 10 + update_priority: 20 + record_type: MX + +# Multiple MX records +- data: mx2.example-ansible.com + priority: 10 + update_data: mx1.example-ansible.com + update_priority: 20 + record_type: MX + multiple: true diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/create_record.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/create_record.yml new file mode 100644 index 00000000..5f33eb14 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/create_record.yml @@ -0,0 +1,67 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test setup dns record + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + record_type: "{{ item.record_type | default(omit) }}" + state: absent + register: result +- name: verify test setup dns record + assert: + that: + - result is successful + +- name: test create a dns record in check mode + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data }}" + ttl: "{{ item.ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.priority | default(omit) }}" + check_mode: yes + register: result +- name: verify test create a dns record in check mode + assert: + that: + - result is changed + +- name: test create a dns record + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data }}" + ttl: "{{ item.ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.priority | default(omit) }}" + register: result +- name: verify test create a dns record + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.data }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.priority | default(0) }} + +- name: test create a dns record idempotence + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data }}" + ttl: "{{ item.ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.priority | default(omit) }}" + register: result +- name: verify test create a dns record idempotence + assert: + that: + - result is not changed + - result.vultr_dns_record.data == "{{ item.data }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.priority | default(0) }} diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/main.yml new file mode 100644 index 00000000..19419efc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/main.yml @@ -0,0 +1,17 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup dns domain + vultr_dns_domain: + name: "{{ vultr_dns_domain_name }}" + server_ip: 10.10.10.10 + register: result +- name: verify setup dns domain + assert: + that: + - result is successful + +- include_tasks: test_fail_multiple.yml + +- include_tasks: record.yml + with_items: "{{ vultr_dns_record_items }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/record.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/record.yml new file mode 100644 index 00000000..c8c3926d --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/record.yml @@ -0,0 +1,6 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- include_tasks: create_record.yml +- include_tasks: update_record.yml +- include_tasks: remove_record.yml diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/remove_record.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/remove_record.yml new file mode 100644 index 00000000..e776a492 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/remove_record.yml @@ -0,0 +1,114 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test remove a dns record in check mode + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + check_mode: yes + register: result +- name: verify test remove a dns record in check mode + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.update_priority | default(item.priority | default(0)) }} + +- name: test remove second dns record in check mode + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data | default(item.data) }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + check_mode: yes + register: result + when: item.multiple is defined and item.multiple == true +- name: verify test remove a dns record in check mode + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.data | default(item.data) }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.priority | default(0) }} + when: item.multiple is defined and item.multiple == true + +- name: test remove a dns record + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + register: result +- name: verify test remove a dns record + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.update_priority | default(item.priority | default(0)) }} + +- name: test remove second dns record + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + register: result + when: item.multiple is defined and item.multiple == true +- name: verify test remove a dns record + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.data }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.priority | default(0) }} + when: item.multiple is defined and item.multiple == true + +- name: test remove a dns record idempotence + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + register: result +- name: verify test remove a dns record idempotence + assert: + that: + - result is not changed + +- name: test remove second dns record idempotence + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.data }}" + record_type: "{{ item.record_type | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + state: absent + register: result + when: item.multiple is defined and item.multiple == true +- name: verify test remove a dns record idempotence + assert: + that: + - result is not changed + when: item.multiple is defined and item.multiple == true diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/test_fail_multiple.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/test_fail_multiple.yml new file mode 100644 index 00000000..a41d9db5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/test_fail_multiple.yml @@ -0,0 +1,78 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup first dns record + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + data: 1.2.3.4 + multiple: yes + register: result +- name: verify setup a dns record + assert: + that: + - result is successful + +- name: setup second dns record + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + data: 1.2.3.5 + multiple: yes + register: result +- name: verify setup second dns record + assert: + that: + - result is successful + +- name: test-multiple fail multiple identical records found + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + state: absent + register: result + ignore_errors: yes +- name: verify test fail multiple identical records found + assert: + that: + - result is failed + +- name: test-multiple fail absent multiple identical records but not data + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + state: absent + multiple: yes + register: result + ignore_errors: yes +- name: verify test-multiple success absent multiple identical records found + assert: + that: + - result is failed + - "result.msg == 'multiple is True but all of the following are missing: data'" + +- name: test-multiple success absent multiple identical records second found + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + data: 1.2.3.5 + state: absent + multiple: yes + register: result +- name: verify test-multiple success absent multiple identical records second found + assert: + that: + - result is changed + +- name: test-multiple success absent multiple identical records first found + vultr_dns_record: + name: test-multiple + domain: "{{ vultr_dns_domain_name }}" + data: 1.2.3.4 + state: absent + multiple: yes + register: result +- name: verify test-multiple success absent multiple identical records firstfound + assert: + that: + - result is changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/update_record.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/update_record.yml new file mode 100644 index 00000000..204ebda4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_dns_record/tasks/update_record.yml @@ -0,0 +1,70 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test update or add another dns record in check mode + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + ttl: "{{ item.update_ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.update_priority | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + check_mode: yes + register: result +- name: verify test updatein check mode + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.data }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.ttl == {{ item.ttl | default(300) }} + - result.vultr_dns_record.priority == {{ item.priority | default(0) }} + when: item.multiple is undefined or item.multiple == false +- name: verify test add another dns record in check mode + assert: + that: + - result is changed + - not result.vultr_dns_record + when: item.multiple is defined and item.multiple == true + +- name: test update or add another dns record + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + ttl: "{{ item.update_ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.update_priority | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + register: result +- name: verify test update a dns record + assert: + that: + - result is changed + - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }} + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.priority == {{ item.update_priority | default(0) }} + +- name: test update or add another dns record idempotence + vultr_dns_record: + name: "{{ item.name | default(omit) }}" + domain: "{{ vultr_dns_domain_name }}" + data: "{{ item.update_data | default(item.data) }}" + ttl: "{{ item.update_ttl | default(omit) }}" + record_type: "{{ item.record_type | default(omit) }}" + priority: "{{ item.update_priority | default(omit) }}" + multiple: "{{ item.multiple | default(omit) }}" + register: result +- name: verify test update a dns record idempotence + assert: + that: + - result is not changed + - result.vultr_dns_record.data == "{{ item.update_data | default(item.data) }}" + - result.vultr_dns_record.name == "{{ item.name | default("") }}" + - result.vultr_dns_record.ttl == {{ item.update_ttl | default(300) }} + - result.vultr_dns_record.record_type == "{{ item.record_type | default('A') }}" + - result.vultr_dns_record.priority == {{ item.update_priority | default(0) }} diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/defaults/main.yml new file mode 100644 index 00000000..7057b466 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/defaults/main.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/tasks/main.yml new file mode 100644 index 00000000..577457c2 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group/tasks/main.yml @@ -0,0 +1,86 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_firewall_group: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test create firewall group in check mode + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + register: result + check_mode: yes +- name: verify test create firewall group in check mode + assert: + that: + - result is changed + +- name: test create firewall group + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + register: result +- name: verify test create firewall group + assert: + that: + - result is changed + - result.vultr_firewall_group.name == '{{ vultr_firewall_group_name }}' + +- name: test create firewall group idempotence + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + + register: result +- name: verify test create firewall group idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_group.name == '{{ vultr_firewall_group_name }}' + +- name: test absent firewall group in check mode + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent firewall group in check mode + assert: + that: + - result is changed + - result.vultr_firewall_group.name == '{{ vultr_firewall_group_name }}' + +- name: test absent firewall group + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + state: absent + register: result +- name: verify test absent firewall group + assert: + that: + - result is changed + - result.vultr_firewall_group.name == '{{ vultr_firewall_group_name }}' + +- name: test absent firewall group idempotence + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + state: absent + register: result +- name: verify test absent firewall group idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/defaults/main.yml new file mode 100644 index 00000000..e545fe42 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/defaults/main.yml @@ -0,0 +1,3 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/tasks/main.yml new file mode 100644 index 00000000..e813afd9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_group_info/tasks/main.yml @@ -0,0 +1,33 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr firewall group info - empty resources + vultr_firewall_group_info: + +- name: Create the firewall group + vultr_firewall_group: + name: '{{ firewall_group_name }}' + +- name: test gather vultr firewall group info in check mode + vultr_firewall_group_info: + check_mode: yes + register: result + +- name: verify test gather vultr firewall group info in check mode + assert: + that: + - result.vultr_firewall_group_info|selectattr('description','equalto','{{ firewall_group_name }}') | list | count == 1 + +- name: test gather vultr firewall group info + vultr_firewall_group_info: + register: result + +- name: verify test gather vultr firewall group info + assert: + that: + - result.vultr_firewall_group_info|selectattr('description','equalto','{{ firewall_group_name }}') | list | count == 1 + +- name: Delete the firewall group + vultr_firewall_group: + name: '{{ firewall_group_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/defaults/main.yml new file mode 100644 index 00000000..7057b466 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/defaults/main.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_firewall_group_name: "{{ vultr_resource_prefix }}_firewall-group" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/tasks/main.yml new file mode 100644 index 00000000..44097434 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_firewall_rule/tasks/main.yml @@ -0,0 +1,475 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup firewall group + vultr_firewall_group: + name: "{{ vultr_firewall_group_name }}" + register: result +- name: verify setup firewall group + assert: + that: + - result is success + +- name: setup firewall rule tcp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + state: absent + register: result +- name: verify setup firewal rule + assert: + that: + - result is success + +- name: setup firewall rule udp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + state: absent + register: result +- name: verify setup firewal rule udp + assert: + that: + - result is success + +- name: setup firewall rule udp v6 + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + state: absent + register: result +- name: verify setup firewal rule udp v6 + assert: + that: + - result is success + +- name: setup firewall rule port range + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + state: absent + register: result + tags: tmp +- name: verify setup firewal rule port range + assert: + that: + - result is success + +- name: setup firewall rule icmp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + state: absent + register: result +- name: verify setup firewal rule + assert: + that: + - result is success + +- name: test fail if missing group + vultr_firewall_rule: + register: result + ignore_errors: yes +- name: verify test fail if missing group + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: group"' + +- name: test create firewall rule tcp in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + register: result + check_mode: true +- name: verify test create firewall rule tcp in check mode + assert: + that: + - result is changed + +- name: test create firewall rule tcp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + register: result +- name: verify test create firewall rule tcp + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test create firewall rule tcp idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + register: result +- name: verify test create firewall rule tcp idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test create firewall rule udp in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + register: result + check_mode: true +- name: verify test create firewall rule udp in check mode + assert: + that: + - result is changed + +- name: test create firewall rule udp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + register: result +- name: verify test create firewall rule udp + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test create firewall rule udp idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + register: result +- name: verify test create firewall rule udp idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test create firewall rule udp v6 in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + register: result + check_mode: true +- name: verify test create firewall rule udp v6 in check mode + assert: + that: + - result is changed + +- name: test create firewall rule udp v6 + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + register: result +- name: verify test create firewall rule udp v6 + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "::/0" + +- name: test create firewall rule udp v6 idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + register: result +- name: verify test create firewall rule udp v6 idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "::/0" + +- name: test create firewall rule port range in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + register: result + check_mode: true +- name: verify test create firewall rule port range in check mode + assert: + that: + - result is changed + +- name: test create firewall rule port range + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + register: result +- name: verify test create firewall rule port range + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 8000 + - result.vultr_firewall_rule.end_port == 8080 + - result.vultr_firewall_rule.cidr == "10.100.12.0/24" + +- name: test create firewall rule port range idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + register: result +- name: test create firewall rule port range idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 8000 + - result.vultr_firewall_rule.end_port == 8080 + - result.vultr_firewall_rule.cidr == "10.100.12.0/24" + +- name: test create firewall rule icmp in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + register: result + check_mode: true +- name: test create firewall rule icmp in check mode + assert: + that: + - result is changed + +- name: test create firewall rule icmp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + register: result +- name: test create firewall rule icmp + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "icmp" + +- name: test create firewall rule icmp idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + register: result +- name: test create firewall rule icmp idempotence + assert: + that: + - result is not changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "icmp" + +- name: test remove firewall rule icmp in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + state: absent + register: result + check_mode: true +- name: test remove firewall rule icmp in check mode + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "icmp" + +- name: test remove firewall rule icmp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + state: absent + register: result +- name: test remove firewall rule icmp + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "icmp" + +- name: test remove firewall rule icmp idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + protocol: icmp + state: absent + register: result +- name: test remove firewall rule icmp idempotence + assert: + that: + - result is not changed + +- name: test remove firewall rule tcp in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + state: absent + register: result + check_mode: true +- name: verify test remove firewall rule tcp in check mode + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test remove firewall rule tcp + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + state: absent + register: result +- name: verify test remove firewall rule tcp + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "0.0.0.0/0" + +- name: test remove firewall rule tcp idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + state: absent + register: result +- name: verify test remove firewall rule tcp idempotence + assert: + that: + - result is not changed + +- name: test remove firewall rule udp v6 in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + state: absent + register: result + check_mode: true +- name: verify test remove firewall rule udp v6 in check mode + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "::/0" + +- name: test remove firewall rule udp v6 + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + state: absent + register: result +- name: verify test remove firewall rule udp v6 + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "udp" + - result.vultr_firewall_rule.start_port == 53 + - result.vultr_firewall_rule.cidr == "::/0" + +- name: test remove firewall rule udp v6 idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + port: 53 + protocol: udp + ip_version: v6 + state: absent + register: result +- name: verify test remove firewall rule udp v6 idempotence + assert: + that: + - result is not changed + +- name: test remove firewall rule port range in check mode + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + state: absent + register: result + check_mode: true +- name: verify test remove firewall rule port range in check mode + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 8000 + - result.vultr_firewall_rule.end_port == 8080 + - result.vultr_firewall_rule.cidr == "10.100.12.0/24" + +- name: test remove firewall rule port range + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + state: absent + register: result +- name: verify test remove firewall rule port range + assert: + that: + - result is changed + - result.vultr_firewall_rule.action == "accept" + - result.vultr_firewall_rule.protocol == "tcp" + - result.vultr_firewall_rule.start_port == 8000 + - result.vultr_firewall_rule.end_port == 8080 + - result.vultr_firewall_rule.cidr == "10.100.12.0/24" + +- name: test remove firewall rule port range idempotence + vultr_firewall_rule: + group: "{{ vultr_firewall_group_name }}" + start_port: 8000 + end_port: 8080 + protocol: tcp + cidr: 10.100.12.0/24 + state: absent + register: result +- name: verify test remove firewall rule port range idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/defaults/main.yml new file mode 100644 index 00000000..a3d9e592 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/defaults/main.yml @@ -0,0 +1,5 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_network_name: "{{ vultr_resource_prefix }}_network" +vultr_network_cidr: 192.168.42.0/24 +vultr_network_region: New Jersey diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/tasks/main.yml new file mode 100644 index 00000000..7a7b0b1b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network/tasks/main.yml @@ -0,0 +1,113 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_network: + name: "{{ vultr_network_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_network: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_network: + name: "{{ vultr_network_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: cidr, region"' + +- name: test create network in check mode + vultr_network: + name: "{{ vultr_network_name }}" + cidr: "{{ vultr_network_cidr }}" + region: "{{ vultr_network_region }}" + register: result + check_mode: yes +- name: verify test create server in check mode + assert: + that: + - result is changed + +- name: test create network + vultr_network: + name: "{{ vultr_network_name }}" + cidr: "{{ vultr_network_cidr }}" + region: "{{ vultr_network_region }}" + register: result + +- name: verify test create network + assert: + that: + - result is changed + - result.vultr_network.name == "{{ vultr_network_name }}" + - result.vultr_network.region == "{{ vultr_network_region }}" + - result.vultr_network.v4_subnet == "{{ vultr_network_cidr.split('/')[0] }}" + - result.vultr_network.v4_subnet_mask == 24 + +- name: test create network idempotence + vultr_network: + name: "{{ vultr_network_name }}" + cidr: "{{ vultr_network_cidr }}" + region: "{{ vultr_network_region }}" + register: result + +- name: verify test network idempotence + assert: + that: + - result is not changed + - result.vultr_network.name == "{{ vultr_network_name }}" + - result.vultr_network.region == "{{ vultr_network_region }}" + - result.vultr_network.v4_subnet == "{{ vultr_network_cidr.split('/')[0] }}" + - result.vultr_network.v4_subnet_mask == 24 + +- name: test destroy network in check mode + vultr_network: + name: "{{ vultr_network_name }}" + state: absent + register: result + check_mode: yes + +- name: verify test destroy network in check mode + assert: + that: + - result is changed + - result.vultr_network.name == "{{ vultr_network_name }}" + +- name: test destroy network volume + vultr_network: + name: "{{ vultr_network_name }}" + state: absent + register: result + +- name: verify test destroy an existing network + assert: + that: + - result is changed + - result.vultr_network.name == "{{ vultr_network_name }}" + +- name: test destroy an existing network idempotence + vultr_network: + name: "{{ vultr_network_name }}" + state: absent + register: result + +- name: verify test destroy an existing network idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/defaults/main.yml new file mode 100644 index 00000000..28e3e705 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/defaults/main.yml @@ -0,0 +1,5 @@ +--- +vultr_resource_prefix: "vultr_test_prefix" +vultr_network_name: "{{ vultr_resource_prefix }}_network" +vultr_network_cidr: 192.168.42.0/24 +vultr_network_region: New Jersey diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/tasks/main.yml new file mode 100644 index 00000000..90d45a08 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_network_info/tasks/main.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr network info - empty resources + vultr_network_info: + +- name: Create the network + vultr_network: + name: '{{ vultr_network_name }}' + cidr: '{{ vultr_network_cidr }}' + region: '{{ vultr_network_region }}' + +- name: test gather vultr network info in check mode + vultr_network_info: + check_mode: yes + register: result + +- name: verify test gather vultr network info in check mode + assert: + that: + - result.vultr_network_info|selectattr('name','equalto','{{ vultr_network_name }}') | list | count == 1 + +- name: test gather vultr network info + vultr_network_info: + register: result + +- name: verify test gather vultr network info + assert: + that: + - result.vultr_network_info|selectattr('name','equalto','{{ vultr_network_name }}') | list | count == 1 + +- name: Delete the script + vultr_network: + name: '{{ vultr_network_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/tasks/main.yml new file mode 100644 index 00000000..a48133e4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_os_info/tasks/main.yml @@ -0,0 +1,22 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test get vultr os infos in check mode + vultr_os_info: + check_mode: yes + register: result + +- name: verify test get vultr os infos in check mode + assert: + that: + - result.vultr_os_info|selectattr('name','equalto', 'CentOS 7 x64') | list | count == 1 + +- name: test get vultr os fact + vultr_os_info: + register: result + +- name: verify test get vultr os infos + assert: + that: + - result.vultr_os_info|selectattr('name','equalto', 'CentOS 7 x64') | list | count == 1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/tasks/main.yml new file mode 100644 index 00000000..372123bb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_baremetal_info/tasks/main.yml @@ -0,0 +1,22 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2020, Simon Bärlocher <s.baerlocher@sbaerlocher.ch> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr plan baremetal info in check mode + vultr_plan_baremetal_info: + check_mode: yes + register: result + +- name: verify test gather vultr plan baremetal info in check mode + assert: + that: + - result.vultr_plan_baremetal_info|selectattr('name','equalto','65536 MB RAM,2x 240 GB SSD,5.00 TB BW') | list | count == 1 + +- name: test gather vultr plan baremetal info + vultr_plan_baremetal_info: + register: result + +- name: verify test gather vultr plan baremetal info + assert: + that: + - result.vultr_plan_baremetal_info|selectattr('name','equalto','65536 MB RAM,2x 240 GB SSD,5.00 TB BW') | list | count == 1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/tasks/main.yml new file mode 100644 index 00000000..6b379032 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_plan_info/tasks/main.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr plan info in check mode + vultr_plan_info: + check_mode: yes + register: result + +- name: verify test gather vultr plan info in check mode + assert: + that: + - result.vultr_plan_info|selectattr('name','equalto','16384 MB RAM,2x110 GB SSD,20.00 TB BW') | list | count == 1 + +- name: test gather vultr plan info + vultr_plan_info: + register: result + +- name: verify test gather vultr plan info + assert: + that: + - result.vultr_plan_info|selectattr('name','equalto','16384 MB RAM,2x110 GB SSD,20.00 TB BW') | list | count == 1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/tasks/main.yml new file mode 100644 index 00000000..adf8a8a4 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_region_info/tasks/main.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr region info in check mode + vultr_region_info: + check_mode: yes + register: result + +- name: verify test gather vultr region info in check mode + assert: + that: + - result.vultr_region_info|selectattr('name','equalto','Atlanta') | list | count == 1 + +- name: test gather vultr region info + vultr_region_info: + register: result + +- name: verify test gather vultr region info + assert: + that: + - result.vultr_region_info|selectattr('name','equalto','Atlanta') | list | count == 1 diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/defaults/main.yml new file mode 100644 index 00000000..2b685295 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/defaults/main.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_server_name: "{{ vultr_resource_prefix }}_vm" +vultr_server_ssh_keys: +- name: key1 + key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= mail@renemoser.net" +- name: key2 + key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoQ9S7V+CufAgwoehnf2TqsJ9LTsu8pUA3FgpS2mdVwcMcTs++8P5sQcXHLtDmNLpWN4k7NQgxaY1oXy5e25x/4VhXaJXWEt3luSw+Phv/PB2+aGLvqCUirsLTAD2r7ieMhd/pcVf/HlhNUQgnO1mupdbDyqZoGD/uCcJiYav8i/V7nJWJouHA8yq31XS2yqXp9m3VC7UZZHzUsVJA9Us5YqF0hKYeaGruIHR2bwoDF9ZFMss5t6/pzxMljU/ccYwvvRDdI7WX4o4+zLuZ6RWvsU6LGbbb0pQdB72tlV41fSefwFsk4JRdKbyV3Xjf25pV4IXOTcqhy+4JTB/jXxrF torwalds@github.com" + +vultr_server_plan_1: 1024 MB RAM,25 GB SSD,1.00 TB BW +vultr_server_plan_2: 2048 MB RAM,55 GB SSD,2.00 TB BW diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/tasks/main.yml new file mode 100644 index 00000000..ac6a6f3f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server/tasks/main.yml @@ -0,0 +1,551 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min + wait_for: + when: result is changed + +- name: test fail if missing name + vultr_server: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_server: + name: "{{ vultr_server_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: os, plan, region"' + +- name: test fail if plan does not exist + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: does_not_exist + region: Amsterdam + register: result + ignore_errors: yes +- name: verify test fail if plan does not exist + assert: + that: + - result is failed + - 'result.msg == "Could not find plans with ID or name: does_not_exist"' + +- name: setup create ssh keys + vultr_ssh_key: + name: "{{ item.name }}" + ssh_key: "{{ item.key }}" + loop: "{{ vultr_server_ssh_keys }}" + +- name: test create server in check mode + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_1 }}" + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result + check_mode: yes +- name: verify test create server in check mode + assert: + that: + - result is changed + +- name: test create server + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_1 }}" + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result +- name: verify test create server + assert: + that: + - result is changed + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.power_status == 'running' + +- name: test create server idempotence + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_1 }}" + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result +- name: verify test create server idempotence + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + +- name: test stop an existing server in check mode + vultr_server: + name: "{{ vultr_server_name }}" + state: stopped + register: result + check_mode: yes +- name: verify test stop server in check mode + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test stop an existing server + vultr_server: + name: "{{ vultr_server_name }}" + state: stopped + register: result +- name: verify test stop an existing server + assert: + that: + - result is changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test stop an existing server idempotence + vultr_server: + name: "{{ vultr_server_name }}" + state: stopped + register: result +- name: verify test stop an existing server idempotence + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test start an existing server in check mode + vultr_server: + name: "{{ vultr_server_name }}" + state: started + register: result + check_mode: yes +- name: verify test start an existing server in check mode + assert: + that: + - result is changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test start an existing server + vultr_server: + name: "{{ vultr_server_name }}" + state: started + register: result +- name: verify test start an existing server + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test start an existing server idempotence + vultr_server: + name: "{{ vultr_server_name }}" + state: started + register: result +- name: verify test start an existing server idempotence + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test update plan for server in check mode without force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + region: Amsterdam + register: result + check_mode: yes +- name: verify test update plan for server in check mode without force + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + +- name: test update plan for server without force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + region: Amsterdam + register: result +- name: verify test update plan for server without force + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + +- name: setup firewall group + vultr_firewall_group: + name: test_firewall_group + register: result +- name: verify test create firewall group + assert: + that: + - result is success + +- name: test fail with unknown firewall group + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + region: Amsterdam + firewall_group: does not exist + tag: test_tag + register: result + ignore_errors: yes + check_mode: yes +- name: verify test fail with unknown firewall group + assert: + that: + - result is failed + - result.msg.startswith('Could not find') + +- name: test update tag, firewall group for server in check mode without force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result + check_mode: yes +- name: verify test update tag, firewall group for server in check mode without force + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.tag == '' + - result.vultr_server.firewall_group != 'test_firewall_group' + +- name: test update tag, firewall group for server without force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result +- name: verify test update tag, firewall group for server without force + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.tag == 'test_tag' + - result.vultr_server.firewall_group == 'test_firewall_group' + +- name: test update tag, firewall group for server without force idempotence + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result +- name: verify test update tag, firewall group for server without force idempotence + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.tag == 'test_tag' + - result.vultr_server.firewall_group == 'test_firewall_group' + +- name: test update server in check mode with force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + auto_backup_enabled: yes + private_network_enabled: yes + region: Amsterdam + force: yes + register: result + check_mode: yes +- name: verify test update server in check mode with force + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_1 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.auto_backup_enabled == false + - result.vultr_server.internal_ip == '' + +- name: test update server with force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + auto_backup_enabled: yes + private_network_enabled: yes + region: Amsterdam + force: yes + register: result +- name: verify test update server with force + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.auto_backup_enabled == true + - result.vultr_server.internal_ip != '' + +- name: test update server idempotence with force + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + auto_backup_enabled: yes + private_network_enabled: yes + region: Amsterdam + force: yes + register: result +- name: verify test update server idempotence with force + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.auto_backup_enabled == true + - result.vultr_server.internal_ip != '' + +- name: test update server with IDs idempotence with force + vultr_server: + name: "{{ vultr_server_name }}" + os: "127" + plan: "202" + auto_backup_enabled: yes + private_network_enabled: yes + region: "7" + force: yes + register: result +- name: verify test update server idempotence with force + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.auto_backup_enabled == true + - result.vultr_server.internal_ip != '' + +- name: test update server to stopped in check mode + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + ipv6_enabled: yes + region: Amsterdam + state: stopped + register: result + check_mode: yes +- name: verify test update server to stopped in check mode + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.v6_main_ip == '' + +- name: test update server to stopped + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + ipv6_enabled: yes + region: Amsterdam + state: stopped + register: result +- name: verify test update server to stopped + assert: + that: + - result is changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.v6_main_ip != '' + +- name: test update server to stopped idempotence + vultr_server: + name: "{{ vultr_server_name }}" + os: CentOS 6 x64 + plan: "{{ vultr_server_plan_2 }}" + ipv6_enabled: yes + region: Amsterdam + state: stopped + register: result +- name: verify test update server to stopped idempotence + assert: + that: + - result is not changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.plan == vultr_server_plan_2 + - result.vultr_server.region == 'Amsterdam' + - result.vultr_server.v6_main_ip != '' + +- name: test restart an existing server in check mode + vultr_server: + name: "{{ vultr_server_name }}" + state: restarted + register: result + check_mode: yes +- name: verify test restart an existing server in check mode + assert: + that: + - result is changed + - result.vultr_server.power_status == 'stopped' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test restart an existing server + vultr_server: + name: "{{ vultr_server_name }}" + state: restarted + register: result +- name: verify test restart an existing server + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test absent server in check mode + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent server in check mode + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min + wait_for: + +- name: test absent server + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result +- name: verify test absent server + assert: + that: + - result is changed + - result.vultr_server.power_status == 'running' + - result.vultr_server.name == vultr_server_name + - result.vultr_server.os == 'CentOS 6 x64' + - result.vultr_server.region == 'Amsterdam' + +- name: test absent server idempotence + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result +- name: verify test absent server idempotence + assert: + that: + - result is not changed + +- name: cleanup ssh keys + vultr_ssh_key: + name: "{{ item.name }}" + ssh_key: "{{ item.key }}" + state: absent + loop: "{{ vultr_server_ssh_keys }}" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/defaults/main.yml new file mode 100644 index 00000000..0be096a5 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/defaults/main.yml @@ -0,0 +1,13 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# Copyright (c) 2020, Simon Bärlocher <s.baerlocher@sbaerlocher.ch> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: 'vultr-test-prefix' +vultr_server_baremetal_name: '{{ vultr_resource_prefix }}_baremetal' +vultr_server_baremetal_ssh_keys: + - name: key1 + key: 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= mail@renemoser.net' + - name: key2 + key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoQ9S7V+CufAgwoehnf2TqsJ9LTsu8pUA3FgpS2mdVwcMcTs++8P5sQcXHLtDmNLpWN4k7NQgxaY1oXy5e25x/4VhXaJXWEt3luSw+Phv/PB2+aGLvqCUirsLTAD2r7ieMhd/pcVf/HlhNUQgnO1mupdbDyqZoGD/uCcJiYav8i/V7nJWJouHA8yq31XS2yqXp9m3VC7UZZHzUsVJA9Us5YqF0hKYeaGruIHR2bwoDF9ZFMss5t6/pzxMljU/ccYwvvRDdI7WX4o4+zLuZ6RWvsU6LGbbb0pQdB72tlV41fSefwFsk4JRdKbyV3Xjf25pV4IXOTcqhy+4JTB/jXxrF torwalds@github.com' + +vultr_server_baremetal_plan_1: 65536 MB RAM,2x 240 GB SSD,5.00 TB BW diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/tasks/main.yml new file mode 100644 index 00000000..f4dd752f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_baremetal/tasks/main.yml @@ -0,0 +1,366 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min + wait_for: + when: result is changed + +- name: test fail if missing name + vultr_server_baremetal: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: os, plan, region"' + +- name: test fail if plan does not exist + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + plan: does_not_exist + region: Amsterdam + register: result + ignore_errors: yes +- name: verify test fail if plan does not exist + assert: + that: + - result is failed + - 'result.msg == "Could not find plans with ID or name: does_not_exist"' + +- name: setup create ssh keys + vultr_ssh_key: + name: '{{ item.name }}' + ssh_key: '{{ item.key }}' + loop: '{{ vultr_server_baremetal_ssh_keys }}' + +- name: test create server in check mode + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + plan: '{{ vultr_server_baremetal_plan_1 }}' + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result + check_mode: yes +- name: verify test create server in check mode + assert: + that: + - result is changed + +- name: test create server + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + plan: '{{ vultr_server_baremetal_plan_1 }}' + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result +- name: verify test create server + assert: + that: + - result is changed + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.plan == vultr_server_baremetal_plan_1 + - result.vultr_server_baremetal.region == 'Amsterdam' + - result.vultr_server_baremetal.power_status == 'running' + +- name: test create server idempotence + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + plan: '{{ vultr_server_baremetal_plan_1 }}' + ssh_keys: + - key1 + - key2 + region: Amsterdam + state: started + register: result +- name: verify test create server idempotence + assert: + that: + - result is not changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.plan == vultr_server_baremetal_plan_1 + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test stop an existing server in check mode + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: stopped + register: result + check_mode: yes +- name: verify test stop server in check mode + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test stop an existing server + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: stopped + register: result +- name: verify test stop an existing server + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'stopped' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test stop an existing server idempotence + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: stopped + register: result +- name: verify test stop an existing server idempotence + assert: + that: + - result is not changed + - result.vultr_server_baremetal.power_status == 'stopped' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test start an existing server in check mode + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: started + register: result + check_mode: yes +- name: verify test start an existing server in check mode + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'stopped' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test start an existing server + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: started + register: result +- name: verify test start an existing server + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test start an existing server idempotence + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: started + register: result +- name: verify test start an existing server idempotence + assert: + that: + - result is not changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: setup firewall group + vultr_firewall_group: + name: test_firewall_group + register: result +- name: verify test create firewall group + assert: + that: + - result is success + +- name: test fail with unknown firewall group + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + region: Amsterdam + firewall_group: does not exist + tag: test_tag + register: result + ignore_errors: yes + check_mode: yes +- name: verify test fail with unknown firewall group + assert: + that: + - result is failed + - result.msg.startswith('Could not find') + +- name: test update tag, firewall group for server in check mode without force + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result + check_mode: yes +- name: verify test update tag, firewall group for server in check mode without force + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.plan == vultr_server_baremetal_plan_1 + - result.vultr_server_baremetal.region == 'Amsterdam' + - result.vultr_server_baremetal.tag == '' + - result.vultr_server_baremetal.firewall_group != 'test_firewall_group' + +- name: test update tag, firewall group for server without force + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result +- name: verify test update tag, firewall group for server without force + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + - result.vultr_server_baremetal.tag == 'test_tag' + - result.vultr_server_baremetal.firewall_group == 'test_firewall_group' + +- name: test update tag, firewall group for server without force idempotence + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + os: CentOS 6 x64 + region: Amsterdam + firewall_group: test_firewall_group + tag: test_tag + register: result +- name: verify test update tag, firewall group for server without force idempotence + assert: + that: + - result is not changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + - result.vultr_server_baremetal.tag == 'test_tag' + - result.vultr_server_baremetal.firewall_group == 'test_firewall_group' + +- name: test restart an existing server in check mode + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: restarted + register: result + check_mode: yes +- name: verify test restart an existing server in check mode + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'stopped' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test restart an existing server + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: restarted + register: result +- name: verify test restart an existing server + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test absent server in check mode + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: absent + register: result + check_mode: yes +- name: verify test absent server in check mode + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min + wait_for: + +- name: test absent server + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: absent + register: result +- name: verify test absent server + assert: + that: + - result is changed + - result.vultr_server_baremetal.power_status == 'running' + - result.vultr_server_baremetal.name == vultr_server_baremetal_name + - result.vultr_server_baremetal.os == 'CentOS 6 x64' + - result.vultr_server_baremetal.region == 'Amsterdam' + +- name: test absent server idempotence + vultr_server_baremetal: + name: '{{ vultr_server_baremetal_name }}' + state: absent + register: result +- name: verify test absent server idempotence + assert: + that: + - result is not changed + +- name: cleanup ssh keys + vultr_ssh_key: + name: '{{ item.name }}' + ssh_key: '{{ item.key }}' + state: absent + loop: '{{ vultr_server_baremetal_ssh_keys }}' diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/defaults/main.yml new file mode 100644 index 00000000..37134a1f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/defaults/main.yml @@ -0,0 +1,6 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_server_name: "{{ vultr_resource_prefix }}_vm" +vultr_server_os: CentOS 7 x64 +vultr_server_plan: 1024 MB RAM,25 GB SSD,1.00 TB BW +vultr_server_region: Amsterdam diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/tasks/main.yml new file mode 100644 index 00000000..83deb769 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_server_info/tasks/main.yml @@ -0,0 +1,66 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup ensure VM is absent + vultr_server: + name: "{{ vultr_server_name }}" + state: absent + register: result + +# Servers can only be destroyed 5 min after creation +- name: wait for 5 min until VM is absent + wait_for: + when: result is changed + +- name: test gather vultr server info - empty resources + vultr_server_info: + register: result +- name: verify test gather vultr server info - empty resources + assert: + that: + - result.vultr_server_info | selectattr('name','equalto',vultr_server_name) | list | count == 0 + +- name: setup firewall group + vultr_firewall_group: + name: test_vultr_server_info + +- name: setup create the server + vultr_server: + name: '{{ vultr_server_name }}' + os: '{{ vultr_server_os }}' + plan: '{{ vultr_server_plan }}' + region: '{{ vultr_server_region }}' + firewall_group: test_vultr_server_info + +- name: test gather vultr server info in check mode + vultr_server_info: + check_mode: yes + register: result + +- name: verify test gather vultr server info in check mode + assert: + that: + - result.vultr_server_info|selectattr('name','equalto',vultr_server_name) | list | count == 1 + +- name: test gather vultr server info + vultr_server_info: + register: result + +- name: verify test gather vultr server info + assert: + that: + - result.vultr_server_info|selectattr('name','equalto',vultr_server_name) | list | count == 1 + +- name: Pause for 5 min before deleting the VM + pause: + minutes: 5 + +- name: cleanup the server + vultr_server: + name: '{{ vultr_server_name }}' + state: absent + +- name: cleanup firewall group + vultr_firewall_group: + name: test_vultr_server_info + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/defaults/main.yml new file mode 100644 index 00000000..53cce567 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/defaults/main.yml @@ -0,0 +1,7 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_ssh_key_name: "{{ vultr_resource_prefix }}_ansible-ssh-key" +vultr_ssh_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= ansible@example.com" +vultr_ssh_key2: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoQ9S7V+CufAgwoehnf2TqsJ9LTsu8pUA3FgpS2mdVwcMcTs++8P5sQcXHLtDmNLpWN4k7NQgxaY1oXy5e25x/4VhXaJXWEt3luSw+Phv/PB2+aGLvqCUirsLTAD2r7ieMhd/pcVf/HlhNUQgnO1mupdbDyqZoGD/uCcJiYav8i/V7nJWJouHA8yq31XS2yqXp9m3VC7UZZHzUsVJA9Us5YqF0hKYeaGruIHR2bwoDF9ZFMss5t6/pzxMljU/ccYwvvRDdI7WX4o4+zLuZ6RWvsU6LGbbb0pQdB72tlV41fSefwFsk4JRdKbyV3Xjf25pV4IXOTcqhy+4JTB/jXxrF torwalds@github.com" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/tasks/main.yml new file mode 100644 index 00000000..ce46970e --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key/tasks/main.yml @@ -0,0 +1,140 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_ssh_key: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: ssh_key"' + +- name: test create ssh key in check mode + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key }}" + register: result + check_mode: yes +- name: verify test create ssh key in check mode + assert: + that: + - result is changed + +- name: test create ssh key + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key }}" + register: result +- name: verify test create ssh key + assert: + that: + - result is changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key }}' + +- name: test create ssh key idempotence + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key }}" + register: result +- name: verify test create ssh key idempotence + assert: + that: + - result is not changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key }}' + +- name: test update ssh key in check mode + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key2 }}" + register: result + check_mode: yes +- name: verify test update ssh key in check mode + assert: + that: + - result is changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key }}' + +- name: test update ssh key + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key2 }}" + register: result +- name: verify test update ssh key + assert: + that: + - result is changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key2 }}' + +- name: test update ssh key idempotence + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + ssh_key: "{{ vultr_ssh_key2 }}" + register: result +- name: verify test update ssh key idempotence + assert: + that: + - result is not changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key2 }}' + +- name: test absent ssh key in check mode + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent ssh key in check mode + assert: + that: + - result is changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key2 }}' + +- name: test absent ssh key + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + state: absent + register: result +- name: verify test absent ssh key + assert: + that: + - result is changed + - result.vultr_ssh_key.name == '{{ vultr_ssh_key_name }}' + - result.vultr_ssh_key.ssh_key == '{{ vultr_ssh_key2 }}' + +- name: test absent ssh key idempotence + vultr_ssh_key: + name: "{{ vultr_ssh_key_name }}" + state: absent + register: result +- name: verify test absent ssh key idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/defaults/main.yml new file mode 100644 index 00000000..63bda99f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/defaults/main.yml @@ -0,0 +1,4 @@ +--- +vultr_resource_prefix: "vultr_test_prefix" +ssh_key_name: "{{ vultr_resource_prefix }}-sshkey" +ssh_key_content: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+ZFQv3MyjtL1BMpSA0o0gIkzLVVC711rthT29hBNeORdNowQ7FSvVWUdAbTq00U7Xzak1ANIYLJyn+0r7olsdG4XEiUR0dqgC99kbT/QhY5mLe5lpl7JUjW9ctn00hNmt+TswpatCKWPNwdeAJT2ERynZaqPobENgvIq7jfOFWQIVew7qrewtqwerqwrewUr2Cdq7Nb7U0XFXh3x1p0v0+MbL4tiJwPlMAGvFTKIMt+EaA+AsRIxiOo9CMk5ZuOl9pT8h5vNuEOcvS0qx4v44EAD2VOsCVCcrPNMcpuSzZP8dRTGU9wRREAWXngD0Zq9YJMH38VTxHiskoBw1NnPz ansibletest-{{ vultr_resource_prefix }}@sshkey diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/tasks/main.yml new file mode 100644 index 00000000..6a44144b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_ssh_key_info/tasks/main.yml @@ -0,0 +1,44 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test get vultr ssh key info - empty resources + vultr_ssh_key_info: + register: result + +- name: verify test get vultr ssh key infos in check mode + assert: + that: + - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 0 + - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 0 + +- name: Upload an ssh key + vultr_ssh_key: + name: '{{ ssh_key_name }}' + ssh_key: '{{ ssh_key_content }}' + +- name: test get vultr ssh key infos in check mode + vultr_ssh_key_info: + check_mode: yes + register: result + +- name: verify test get vultr ssh key infos in check mode + assert: + that: + - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 1 + - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 1 + +- name: test get vultr ssh key info + vultr_ssh_key_info: + register: result + +- name: verify test get vultr ssh key infos + assert: + that: + - result.vultr_ssh_key_info|selectattr('name','equalto','{{ ssh_key_name }}') | list | count == 1 + - result.vultr_ssh_key_info|selectattr('ssh_key','equalto','{{ ssh_key_content }}') | list | count == 1 + +- name: Destroy the ssh key + vultr_ssh_key: + name: '{{ ssh_key_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/defaults/main.yml new file mode 100644 index 00000000..38b68a69 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/defaults/main.yml @@ -0,0 +1,7 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_startup_script_name: "{{ vultr_resource_prefix }}_script" +vultr_startup_script: "#!/bin/bash\necho Hello World > /root/hello" +vultr_startup_script2: "#!/bin/bash\necho Hello to my World > /root/hello" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/tasks/main.yml new file mode 100644 index 00000000..09929beb --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script/tasks/main.yml @@ -0,0 +1,140 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: setup + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_startup_script: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg == "state is present but all of the following are missing: script"' + +- name: test create startup script in check mode + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script }}" + register: result + check_mode: yes +- name: verify test create startup script in check mode + assert: + that: + - result is changed + +- name: test create startup script + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script }}" + register: result +- name: verify test create startup script + assert: + that: + - result is changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script }}' + +- name: test create startup script idempotence + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script }}" + register: result +- name: verify test create startup script idempotence + assert: + that: + - result is not changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script }}' + +- name: test update startup script in check mode + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script2 }}" + register: result + check_mode: yes +- name: verify test update startup script in check mode + assert: + that: + - result is changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script }}' + +- name: test update startup script + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script2 }}" + register: result +- name: verify test update startup script + assert: + that: + - result is changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script2 }}' + +- name: test update startup script idempotence + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + script: "{{ vultr_startup_script2 }}" + register: result +- name: verify test update startup script idempotence + assert: + that: + - result is not changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script2 }}' + +- name: test absent startup script in check mode + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent startup script in check mode + assert: + that: + - result is changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script2 }}' + +- name: test absent startup script + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + state: absent + register: result +- name: verify test absent startup script + assert: + that: + - result is changed + - result.vultr_startup_script.name == '{{ vultr_startup_script_name }}' + - result.vultr_startup_script.script == '{{ vultr_startup_script2 }}' + +- name: test absent startup script idempotence + vultr_startup_script: + name: "{{ vultr_startup_script_name }}" + state: absent + register: result +- name: verify test absent startup script idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/defaults/main.yml new file mode 100644 index 00000000..017cff1a --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/defaults/main.yml @@ -0,0 +1,4 @@ +vultr_resource_prefix: "vultr_test_prefix" +startup_script_name: "{{ vultr_resource_prefix }}_script" +startup_script_type: boot +startup_script_content: "#!/bin/bash\necho Hello World > /root/hello" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/tasks/main.yml new file mode 100644 index 00000000..15882438 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_startup_script_info/tasks/main.yml @@ -0,0 +1,35 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: test gather vultr startup script info - empty resources + vultr_startup_script_info: + +- name: Create the script + vultr_startup_script: + name: '{{ startup_script_name }}' + script_type: '{{ startup_script_type }}' + script: '{{ startup_script_content }}' + +- name: test gather vultr startup script info in check mode + vultr_startup_script_info: + check_mode: yes + register: result + +- name: verify test gather vultr startup script info in check mode + assert: + that: + - result.vultr_startup_script_info|selectattr('name','equalto','{{ startup_script_name }}') | list | count == 1 + +- name: test gather vultr startup script info + vultr_startup_script_info: + register: result + +- name: verify test gather vultr startup script info + assert: + that: + - result.vultr_startup_script_info|selectattr('name','equalto','{{ startup_script_name }}') | list | count == 1 + +- name: Delete the script + vultr_startup_script: + name: '{{ startup_script_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/defaults/main.yml new file mode 100644 index 00000000..9050a68f --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/defaults/main.yml @@ -0,0 +1,5 @@ +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +vultr_resource_prefix: "vultr-test-prefix" +vultr_user_name: "{{ vultr_resource_prefix }}_user" diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/tasks/main.yml new file mode 100644 index 00000000..8c3684c1 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user/tasks/main.yml @@ -0,0 +1,225 @@ +--- +# Copyright (c) 2018, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +- name: setup + vultr_user: + name: "{{ vultr_user_name }}" + state: absent + register: result +- name: verify setup + assert: + that: + - result is success + +- name: test fail if missing name + vultr_user: + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg == "missing required arguments: name"' + +- name: test fail if missing params for state=present + vultr_user: + name: "{{ vultr_user_name }}" + register: result + ignore_errors: yes +- name: verify fail if missing params for state=present + assert: + that: + - result is failed + - 'result.msg.startswith("state is present but all of the following are missing")' + +- name: test fail param not in choices + vultr_user: + name: "{{ vultr_user_name }}" + email: john.doe@example.com + password: s3cr3t + acls: + - bad + - dns + - manage_users + register: result + ignore_errors: yes +- name: verify test fail if missing name + assert: + that: + - result is failed + - 'result.msg.startswith("value of acls must be one or more of")' + +- name: test create user in check mode + vultr_user: + name: "{{ vultr_user_name }}" + email: john.doe@example.com + password: s3cr3t + acls: + - upgrade + - dns + - manage_users + register: result + check_mode: yes +- name: verify test create user in check mode + assert: + that: + - result is changed + +- name: test create user + vultr_user: + name: "{{ vultr_user_name }}" + email: john.doe@example.com + password: s3cr3t + acls: + - upgrade + - dns + - manage_users + register: result +- name: verify test create user + assert: + that: + - result is changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'john.doe@example.com' + - result.vultr_user.api_enabled == true + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'dns' in result.vultr_user.acls" + - result.vultr_user.api_key is defined + +- name: test create user idempotence + vultr_user: + name: "{{ vultr_user_name }}" + email: john.doe@example.com + password: s3cr3t + acls: + - upgrade + - dns + - manage_users + register: result +- name: verify test create user idempotence + assert: + that: + - result is not changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'john.doe@example.com' + - result.vultr_user.api_enabled == true + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'dns' in result.vultr_user.acls" + - result.vultr_user.api_key is not defined + +- name: test update user in check mode + vultr_user: + name: "{{ vultr_user_name }}" + email: jimmy@example.com + password: s3cr3t + api_enabled: false + acls: + - manage_users + - upgrade + - support + register: result + check_mode: yes +- name: verify test update user in check mode + assert: + that: + - result is changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'john.doe@example.com' + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'dns' in result.vultr_user.acls" + - result.vultr_user.api_enabled == true + - result.vultr_user.api_key is not defined + +- name: test update user + vultr_user: + name: "{{ vultr_user_name }}" + email: jimmy@example.com + password: s3cr3t + api_enabled: false + acls: + - manage_users + - upgrade + - support + register: result +- name: verify test update user + assert: + that: + - result is changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'jimmy@example.com' + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'support' in result.vultr_user.acls" + - result.vultr_user.api_enabled == false + - result.vultr_user.api_key is not defined + +- name: test update user idempotence + vultr_user: + name: "{{ vultr_user_name }}" + email: jimmy@example.com + password: s3cr3t + api_enabled: false + acls: + - manage_users + - upgrade + - support + register: result +- name: verify test update user idempotence + assert: + that: + - result is not changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'jimmy@example.com' + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'support' in result.vultr_user.acls" + - result.vultr_user.api_enabled == false + - result.vultr_user.api_key is not defined + +- name: test absent user in check mode + vultr_user: + name: "{{ vultr_user_name }}" + state: absent + register: result + check_mode: yes +- name: verify test absent user in check mode + assert: + that: + - result is changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'jimmy@example.com' + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'support' in result.vultr_user.acls" + - result.vultr_user.api_enabled == false + - result.vultr_user.api_key is not defined + +- name: test absent user + vultr_user: + name: "{{ vultr_user_name }}" + state: absent + register: result +- name: verify test absent user + assert: + that: + - result is changed + - result.vultr_user.name == '{{ vultr_user_name }}' + - result.vultr_user.email == 'jimmy@example.com' + - "'upgrade' in result.vultr_user.acls" + - "'manage_users' in result.vultr_user.acls" + - "'support' in result.vultr_user.acls" + - result.vultr_user.api_enabled == false + - result.vultr_user.api_key is not defined + +- name: test absent user idempotence + vultr_user: + name: "{{ vultr_user_name }}" + state: absent + register: result +- name: verify test absent user idempotence + assert: + that: + - result is not changed diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/aliases b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/aliases new file mode 100644 index 00000000..bf469bb9 --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/aliases @@ -0,0 +1 @@ +cloud/vultr diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/defaults/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/defaults/main.yml new file mode 100644 index 00000000..5922f6fe --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/defaults/main.yml @@ -0,0 +1,10 @@ +--- +vultr_resource_prefix: "vultr-test-prefix" +user_name: "{{ vultr_resource_prefix }}_user" +user_email: mytestuser-{{ vultr_resource_prefix }}@example.com +user_password: "{{ vultr_resource_prefix }}aP4ssw0rd!" +user_acls: + - upgrade + - dns + - manage_users + - subscriptions diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/tasks/main.yml b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/tasks/main.yml new file mode 100644 index 00000000..164c22fc --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/integration/targets/vultr_user_info/tasks/main.yml @@ -0,0 +1,34 @@ +# Copyright (c) 2018, Yanis Guenane <yanis+ansible@guenane.org> +# Copyright (c) 2019, René Moser <mail@renemoser.net> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +--- +- name: Create the user + vultr_user: + name: '{{ user_name }}' + email: '{{ user_email }}' + password: '{{ user_password }}' + acls: '{{ user_acls }}' + +- name: test get vultr user info in check mode + vultr_user_info: + register: result + check_mode: yes + +- name: verify test get vultr user info in check mode + assert: + that: + - result.vultr_user_info|selectattr('name','equalto','{{ user_name }}') | list | count == 1 + +- name: test get vultr user info + vultr_user_info: + register: result + +- name: verify test get vultr user info + assert: + that: + - result.vultr_user_info|selectattr('name','equalto','{{ user_name }}') | list | count == 1 + +- name: Delete the user + vultr_user: + name: '{{ user_name }}' + state: absent diff --git a/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/sanity/ignore-2.10.txt b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/sanity/ignore-2.10.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/collections-debian-merged/ansible_collections/ngine_io/vultr/tests/sanity/ignore-2.10.txt |